Skip to content

Commit e7fa43b

Browse files
committed
GH-88597: Added command line interface to UUID module.
1 parent 57be545 commit e7fa43b

File tree

5 files changed

+138
-0
lines changed

5 files changed

+138
-0
lines changed

Doc/library/uuid.rst

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,47 @@ of the :attr:`variant` attribute:
261261
internal format of UUIDs, and methods of generating UUIDs.
262262

263263

264+
.. _uuid-cli:
265+
266+
Command-Line Usage
267+
------------------
268+
269+
.. versionadded:: 3.12
270+
271+
The :mod:`uuid` module can be executed as a script from the command line.
272+
It is as simple as:
273+
274+
.. code-block:: sh
275+
276+
python -m uuid [-h] [-u {uuid1,uuid3,uuid4,uuid5}] [-ns NAMESPACE] [-n NAME]
277+
278+
The following options are accepted:
279+
280+
.. program:: uuid
281+
282+
.. cmdoption:: -h, --help
283+
284+
Show the help message and exit.
285+
286+
.. cmdoption:: -u <uuid>
287+
--uuid <uuid>
288+
289+
Specify the function name to use to generate the uuid. By default it uses :func:`uuid4`
290+
is used.
291+
292+
.. cmdoption:: -ns <namespace>
293+
--namespace <namespace>
294+
295+
The namespace used as part of generating the uuid. Only required for
296+
:func:`uuid3` / :func:`uuid5` functions.
297+
298+
.. cmdoption:: -n <name>
299+
--name <name>
300+
301+
The name used as part of generating the uuid. Only required for
302+
:func:`uuid3` / :func:`uuid5` functions.
303+
304+
264305
.. _uuid-example:
265306

266307
Example
@@ -301,3 +342,22 @@ Here are some examples of typical usage of the :mod:`uuid` module::
301342
>>> uuid.UUID(bytes=x.bytes)
302343
UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
303344

345+
346+
.. _uuid-cli-example:
347+
348+
Command-Line Example
349+
--------------------
350+
351+
Here are some examples of typical usage of the :mod:`uuid` command line interface:
352+
353+
.. code-block:: shell
354+
355+
# generate a random uuid - by default uuid4() is used
356+
$ python -m uuid
357+
358+
# generate a uuid using uuid1()
359+
$ python -m uuid -u uuid1
360+
361+
# generate a uuid using uuid5
362+
$ python -m uuid -u uuid5 -ns NAMESPACE_URL -n example.com
363+

Lib/test/test_uuid.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,33 @@ def test_uuid_weakref(self):
675675
weak = weakref.ref(strong)
676676
self.assertIs(strong, weak())
677677

678+
@mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-ns", "NAMESPACE_DNS"])
679+
def test_cli_namespace_required_for_uuid3(self):
680+
with self.assertRaises(SystemExit) as cm:
681+
self.uuid.main()
682+
683+
# Check that exception code is the same as argparse.ArgumentParser.error
684+
self.assertEqual(cm.exception.code, 2)
685+
686+
@mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "python.org"])
687+
def test_cli_name_required_for_uuid3(self):
688+
with self.assertRaises(SystemExit) as cm:
689+
self.uuid.main()
690+
691+
# Check that exception code is the same as argparse.ArgumentParser.error
692+
self.assertEqual(cm.exception.code, 2)
693+
694+
@mock.patch.object(sys, "argv", [""])
695+
def test_cli_uuid4_outputted_with_no_args(self):
696+
stdout = io.StringIO()
697+
with contextlib.redirect_stdout(stdout):
698+
self.uuid.main()
699+
700+
# Output uuid should be in the format of uuid4
701+
self.assertRegex(
702+
stdout.getvalue().strip(),
703+
r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
704+
678705
class TestUUIDWithoutExtModule(BaseTestUUID, unittest.TestCase):
679706
uuid = py_uuid
680707

Lib/uuid.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,9 +728,58 @@ def uuid5(namespace, name):
728728
hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest()
729729
return UUID(bytes=hash[:16], version=5)
730730

731+
732+
def main():
733+
"""Run the uuid command line interface."""
734+
uuid_funcs = {"uuid1": uuid1,
735+
"uuid3": uuid3,
736+
"uuid4": uuid4,
737+
"uuid5": uuid5}
738+
uuid_namespace_funcs = ("uuid3", "uuid5")
739+
namespaces = {
740+
"NAMESPACE_DNS": NAMESPACE_DNS,
741+
"NAMESPACE_URL": NAMESPACE_URL,
742+
"NAMESPACE_OID": NAMESPACE_OID,
743+
"NAMESPACE_X500": NAMESPACE_X500
744+
}
745+
746+
import argparse
747+
parser = argparse.ArgumentParser(
748+
description="Generates a uuid using the selected uuid function.")
749+
parser.add_argument("-u", "--uuid", choices=uuid_funcs.keys(), default="uuid4",
750+
help="The function to use to generate the uuid. "
751+
"By default uuid4 function is used.")
752+
parser.add_argument("-ns", "--namespace",
753+
help="The namespace used as part of generating the uuid. "
754+
"Only required for uuid3/uuid5 functions.")
755+
parser.add_argument("-n", "--name",
756+
help="The name used as part of generating the uuid. "
757+
"Only required for uuid3/uuid5 functions.")
758+
759+
args = parser.parse_args()
760+
uuid_func = uuid_funcs[args.uuid]
761+
namespace = args.namespace
762+
name = args.name
763+
764+
if args.uuid in uuid_namespace_funcs:
765+
if not namespace or not name:
766+
parser.error(
767+
"Incorrect number of arguments. "
768+
f"{args.uuid} requires a namespace and a name. "
769+
"Run 'python -m uuid -h' for more information."
770+
)
771+
namespace = namespaces[namespace] if namespace in namespaces else UUID(namespace)
772+
print(uuid_func(namespace, name))
773+
else:
774+
print(uuid_func())
775+
776+
731777
# The following standard UUIDs are for use with uuid3() or uuid5().
732778

733779
NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
734780
NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
735781
NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
736782
NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
783+
784+
if __name__ == "__main__":
785+
SystemExit(main())

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ Nicolas Chauvat
315315
Jerry Chen
316316
Michael Chermside
317317
Ingrid Cheung
318+
Adam Chhina
318319
Terry Chia
319320
Albert Chin-A-Young
320321
Adal Chiriliuc
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
UUID module now has a command line interface.

0 commit comments

Comments
 (0)