Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 95f5b05

Browse files
authored
GH-88597: Added command line interface to UUID module. (#99463)
The `uuid` module now supports command line usage. ```python ❯ ./python.exe -m uuid 5f2d57b1-90e8-417c-ba5d-69b9b6f74289 ❯ ./python.exe -m uuid -h usage: uuid.py [-h] [-u {uuid1,uuid3,uuid4,uuid5}] [-ns NAMESPACE] [-n NAME] ... ```
1 parent c1c5882 commit 95f5b05

File tree

6 files changed

+174
-0
lines changed

6 files changed

+174
-0
lines changed

Doc/library/uuid.rst

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,46 @@ 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+
273+
.. code-block:: sh
274+
275+
python -m uuid [-h] [-u {uuid1,uuid3,uuid4,uuid5}] [-ns NAMESPACE] [-n NAME]
276+
277+
The following options are accepted:
278+
279+
.. program:: uuid
280+
281+
.. cmdoption:: -h, --help
282+
283+
Show the help message and exit.
284+
285+
.. cmdoption:: -u <uuid>
286+
--uuid <uuid>
287+
288+
Specify the function name to use to generate the uuid. By default :func:`uuid4`
289+
is used.
290+
291+
.. cmdoption:: -ns <namespace>
292+
--namespace <namespace>
293+
294+
The namespace used as part of generating the uuid. Only required for
295+
:func:`uuid3` / :func:`uuid5` functions.
296+
297+
.. cmdoption:: -n <name>
298+
--name <name>
299+
300+
The name used as part of generating the uuid. Only required for
301+
:func:`uuid3` / :func:`uuid5` functions.
302+
303+
264304
.. _uuid-example:
265305

266306
Example
@@ -301,3 +341,22 @@ Here are some examples of typical usage of the :mod:`uuid` module::
301341
>>> uuid.UUID(bytes=x.bytes)
302342
UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
303343

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

Doc/whatsnew/3.12.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,12 @@ unicodedata
327327
* The Unicode database has been updated to version 15.0.0. (Contributed by
328328
Benjamin Peterson in :gh:`96734`).
329329

330+
uuid
331+
----
332+
333+
* Add a :ref:`command-line interface <uuid-cli>`.
334+
(Contributed by Adam Chhina in :gh:`88597`.)
335+
330336
tempfile
331337
--------
332338

Lib/test/test_uuid.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,64 @@ 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 = stdout.getvalue().strip()
701+
uuid_output = self.uuid.UUID(output)
702+
703+
# Output uuid should be in the format of uuid4
704+
self.assertEqual(output, str(uuid_output))
705+
self.assertEqual(uuid_output.version, 4)
706+
707+
@mock.patch.object(sys, "argv",
708+
["", "-u", "uuid3", "-ns", "NAMESPACE_DNS", "-n", "python.org"])
709+
def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self):
710+
stdout = io.StringIO()
711+
with contextlib.redirect_stdout(stdout):
712+
self.uuid.main()
713+
714+
output = stdout.getvalue().strip()
715+
uuid_output = self.uuid.UUID(output)
716+
717+
# Output should be in the form of uuid5
718+
self.assertEqual(output, str(uuid_output))
719+
self.assertEqual(uuid_output.version, 3)
720+
721+
@mock.patch.object(sys, "argv",
722+
["", "-u", "uuid5", "-ns", "NAMESPACE_DNS", "-n", "python.org"])
723+
def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self):
724+
stdout = io.StringIO()
725+
with contextlib.redirect_stdout(stdout):
726+
self.uuid.main()
727+
728+
output = stdout.getvalue().strip()
729+
uuid_output = self.uuid.UUID(output)
730+
731+
# Output should be in the form of uuid5
732+
self.assertEqual(output, str(uuid_output))
733+
self.assertEqual(uuid_output.version, 5)
734+
735+
678736
class TestUUIDWithoutExtModule(BaseTestUUID, unittest.TestCase):
679737
uuid = py_uuid
680738

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+
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+
:mod:`uuid` now has a command line interface. Try ``python -m uuid -h``.

0 commit comments

Comments
 (0)