Skip to content

Commit 4cf2678

Browse files
committed
Add --uuid4 option and allow read from stdin
1 parent cfc4184 commit 4cf2678

3 files changed

Lines changed: 50 additions & 21 deletions

File tree

CHANGELOG.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ Changelog
55

66
Versions follow `Semantic Versioning <http://www.semver.org>`_
77

8+
`2.2.0`_ - 2023-09-21
9+
---------------------
10+
11+
Added
12+
~~~~~
13+
* Added a new flag ``--uuid4`` to the CLI ``show`` command, that converts the provided ``ULID``
14+
into an RFC 4122 compliant ``UUID``.
15+
* The `ulid build` command allows the use of the special value ``-`` for all options to read its
16+
inputs from ``stdin``. E.g.
17+
18+
.. code-block:: bash
19+
20+
$ date --iso-8601 | python -m ulid build --from-datetime -
21+
01HAT9PVR02T3S13XB48S7GEHE
22+
823
`2.1.0`_ - 2023-09-21
924
---------------------
1025

@@ -113,6 +128,7 @@ Changed
113128
* The package now has no external dependencies.
114129
* The test-coverage has been raised to 100%.
115130

131+
.. _2.2.0: https://github.com/mdomke/python-ulid/compare/2.1.0...2.2.0
116132
.. _2.1.0: https://github.com/mdomke/python-ulid/compare/2.0.0...2.1.0
117133
.. _2.0.0: https://github.com/mdomke/python-ulid/compare/1.1.0...2.0.0
118134
.. _1.1.0: https://github.com/mdomke/python-ulid/compare/1.0.3...1.1.0

README.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,15 @@ and convert ULIDs, e.g.
136136
Timestamp: 1695219822.248
137137
Datetime: 2023-09-20 14:23:42.248000+00:00
138138
139+
The special character ``-`` allows to read values from ``stdin`` so that they can be piped. E.g.
140+
141+
.. code-block:: bash
142+
139143
$ echo 01HASFKBN8SKZTSVVS03K5AMMS | ulid show --uuid -
140-
018ab2f9-aea8-ccff-acef-7900e6555299
144+
018ab2f9-aea8-4cff-acef-7900e6555299
145+
146+
$ date --iso-8601 | python -m ulid build --from-datetime -
147+
01HAT9PVR02T3S13XB48S7GEHE
141148
142149
.. cli-end
143150

ulid/__main__.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
import shutil
33
import sys
44
import textwrap
5+
from collections.abc import Callable
56
from collections.abc import Sequence
67
from datetime import datetime
78
from functools import partial
9+
from typing import Any
10+
from typing import Optional
811
from uuid import UUID
912

1013
import ulid
@@ -47,45 +50,40 @@ def make_parser(prog: str | None = None) -> argparse.ArgumentParser:
4750
)
4851
b.add_argument(
4952
"--from-int",
50-
type=int,
5153
metavar="<int>",
5254
help="create from integer",
5355
)
5456
b.add_argument(
5557
"--from-hex",
56-
type=str,
5758
metavar="<str>",
5859
help="create from 32 character hex value",
5960
)
6061
b.add_argument(
6162
"--from-str",
62-
type=str,
6363
metavar="<str>",
6464
help="create from base32 encoded string of length 26",
6565
)
6666
b.add_argument(
6767
"--from-timestamp",
68-
type=parse_numeric,
6968
metavar="<int|float>",
7069
help="create from timestamp either as float in secs or int as millis",
7170
)
7271
b.add_argument(
7372
"--from-datetime",
74-
type=datetime.fromisoformat,
7573
metavar="<iso8601>",
7674
help="create from datetime. The timestamp part of the ULID will be taken from the datetime",
7775
)
7876
b.add_argument(
7977
"--from-uuid",
80-
type=UUID,
8178
metavar="<uuid>",
8279
help="create from given UUID. The timestamp part will be random.",
8380
)
8481
b.set_defaults(func=build)
8582

8683
s = subparsers.add_parser("show", help="show properties of a ULID")
8784
s.add_argument("ulid", help="the ULID to inspect. The special value - reads from stdin")
88-
s.add_argument("--uuid", action="store_true", help="convert to UUID")
85+
s.add_argument("--uuid", action="store_true", help="convert to fully random UUID")
86+
s.add_argument("--uuid4", action="store_true", help="convert to RFC 4122 compliant UUIDv4")
8987
s.add_argument("--hex", action="store_true", help="convert to hex")
9088
s.add_argument("--int", action="store_true", help="convert to int")
9189
s.add_argument("--timestamp", "--ts", action="store_true", help="show timestamp")
@@ -94,42 +92,50 @@ def make_parser(prog: str | None = None) -> argparse.ArgumentParser:
9492
return parser
9593

9694

95+
def main(argv: Sequence[str], prog: str | None = None) -> None:
96+
args = make_parser(prog).parse_args(argv)
97+
args.func(args)
98+
99+
100+
def from_value_or_stdin(value: str, convert: Optional[Callable[[str], Any]] = None) -> Any:
101+
value = sys.stdin.readline().strip() if value == "-" else value
102+
if convert is not None:
103+
return convert(value)
104+
return value
105+
106+
97107
def parse_numeric(s: str) -> int | float:
98108
try:
99109
return int(s)
100110
except ValueError:
101111
return float(s)
102112

103113

104-
def main(argv: Sequence[str], prog: str | None = None) -> None:
105-
args = make_parser(prog).parse_args(argv)
106-
args.func(args)
107-
108-
109114
def build(args: argparse.Namespace) -> None:
110115
ulid: ULID
111116
if args.from_int is not None:
112-
ulid = ULID.from_int(args.from_int)
117+
ulid = ULID.from_int(from_value_or_stdin(args.from_int, int))
113118
elif args.from_hex is not None:
114-
ulid = ULID.from_hex(args.from_hex)
119+
ulid = ULID.from_hex(from_value_or_stdin(args.from_hex))
115120
elif args.from_str is not None:
116-
ulid = ULID.from_str(args.from_str)
121+
ulid = ULID.from_str(from_value_or_stdin(args.from_str))
117122
elif args.from_timestamp is not None:
118-
ulid = ULID.from_timestamp(args.from_timestamp)
123+
ulid = ULID.from_timestamp(from_value_or_stdin(args.from_timestamp, parse_numeric))
119124
elif args.from_datetime is not None:
120-
ulid = ULID.from_datetime(args.from_datetime)
125+
ulid = ULID.from_datetime(from_value_or_stdin(args.from_datetime, datetime.fromisoformat))
121126
elif args.from_uuid is not None:
122-
ulid = ULID.from_uuid(args.from_uuid)
127+
ulid = ULID.from_uuid(from_value_or_stdin(args.from_uuid, UUID))
123128
else:
124129
ulid = ULID()
125130
print(ulid)
126131

127132

128133
def show(args: argparse.Namespace) -> None:
129-
value = sys.stdin.readline().strip() if args.ulid == "-" else args.ulid
130-
ulid: ULID = ULID.from_str(value)
134+
ulid: ULID = ULID.from_str(from_value_or_stdin(args.ulid))
131135
if args.uuid:
132136
print(ulid.to_uuid())
137+
elif args.uuid4:
138+
print(ulid.to_uuid4())
133139
elif args.hex:
134140
print(ulid.hex)
135141
elif args.int:

0 commit comments

Comments
 (0)