Skip to content

Commit 69566ee

Browse files
committed
Allow setting namespace from command line usage of uuid module
- This applies to generating version 3 and 5 UUIDs - Will correctly bail when invalid UUID is supplied as namespace
1 parent 4b33308 commit 69566ee

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

Lib/test/test_uuid.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,29 @@ def test_cli_uuid3_ouputted_with_valid_namespace_and_name(self):
12231223
self.assertEqual(output, str(uuid_output))
12241224
self.assertEqual(uuid_output.version, 3)
12251225

1226+
@mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "any UUID", "-N", "python.org"])
1227+
@mock.patch('sys.stderr', new_callable=io.StringIO)
1228+
def test_cli_uuid3_with_invalid_namespace(self, mock_err):
1229+
with self.assertRaises(SystemExit) as cm:
1230+
self.uuid.main()
1231+
# Check that exception code is the same as argparse.ArgumentParser.error
1232+
self.assertEqual(cm.exception.code, 2)
1233+
self.assertIn("error: badly formed hexadecimal UUID string", mock_err.getvalue())
1234+
1235+
@mock.patch.object(sys, "argv",
1236+
["", "-u", "uuid3", "-n", "0d6a16cc-34a7-47d8-b660-214d0ae184d2", "-N", "some.user"])
1237+
def test_cli_uuid3_ouputted_with_user_provided_namespace_and_name(self):
1238+
stdout = io.StringIO()
1239+
with contextlib.redirect_stdout(stdout):
1240+
self.uuid.main()
1241+
1242+
output = stdout.getvalue().strip()
1243+
uuid_output = self.uuid.UUID(output)
1244+
1245+
# Output should be in the form of uuid5
1246+
self.assertEqual(output, str(uuid_output))
1247+
self.assertEqual(uuid_output.version, 3)
1248+
12261249
@mock.patch.object(sys, "argv",
12271250
["", "-u", "uuid5", "-n", "@dns", "-N", "python.org"])
12281251
def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self):
@@ -1237,6 +1260,29 @@ def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self):
12371260
self.assertEqual(output, str(uuid_output))
12381261
self.assertEqual(uuid_output.version, 5)
12391262

1263+
@mock.patch.object(sys, "argv", ["", "-u", "uuid5", "-n", "any UUID", "-N", "python.org"])
1264+
@mock.patch('sys.stderr', new_callable=io.StringIO)
1265+
def test_cli_uuid5_with_invalid_namespace(self, mock_err):
1266+
with self.assertRaises(SystemExit) as cm:
1267+
self.uuid.main()
1268+
# Check that exception code is the same as argparse.ArgumentParser.error
1269+
self.assertEqual(cm.exception.code, 2)
1270+
self.assertIn("error: badly formed hexadecimal UUID string", mock_err.getvalue())
1271+
1272+
@mock.patch.object(sys, "argv",
1273+
["", "-u", "uuid5", "-n", "0d6a16cc-34a7-47d8-b660-214d0ae184d2", "-N", "some.user"])
1274+
def test_cli_uuid5_ouputted_with_user_provided_namespace_and_name(self):
1275+
stdout = io.StringIO()
1276+
with contextlib.redirect_stdout(stdout):
1277+
self.uuid.main()
1278+
1279+
output = stdout.getvalue().strip()
1280+
uuid_output = self.uuid.UUID(output)
1281+
1282+
# Output should be in the form of uuid5
1283+
self.assertEqual(output, str(uuid_output))
1284+
self.assertEqual(uuid_output.version, 5)
1285+
12401286
@mock.patch.object(sys, "argv", ["", "-u", "uuid6"])
12411287
def test_cli_uuid6(self):
12421288
self.do_test_standalone_uuid(6)

Lib/uuid.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -962,7 +962,7 @@ def main():
962962
default="uuid4",
963963
help="function to generate the UUID")
964964
parser.add_argument("-n", "--namespace",
965-
choices=["any UUID", *namespaces.keys()],
965+
metavar=f"{{any UUID,{','.join(namespaces.keys())}}}",
966966
help="uuid3/uuid5 only: "
967967
"a UUID, or a well-known predefined UUID addressed "
968968
"by namespace name")
@@ -984,7 +984,15 @@ def main():
984984
f"{args.uuid} requires a namespace and a name. "
985985
"Run 'python -m uuid -h' for more information."
986986
)
987-
namespace = namespaces[namespace] if namespace in namespaces else UUID(namespace)
987+
if namespace in namespaces:
988+
namespace = namespaces[namespace]
989+
else:
990+
try:
991+
namespace = UUID(namespace)
992+
except ValueError as e:
993+
parser.error(
994+
f"{str(e)}: '{args.namespace}'."
995+
)
988996
for _ in range(args.count):
989997
print(uuid_func(namespace, name))
990998
else:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix usage for :mod:`uuid` command line interface to support a custom namespace be
2+
provided for uuid3 and uuid5.

0 commit comments

Comments
 (0)