[Python-checkins] gh-94684: uuid: support bytes in the name argument to uuid3/5 (#94709)

JelleZijlstra webhook-mailer at python.org
Thu Mar 23 19:42:50 EDT 2023


https://github.com/python/cpython/commit/413b7db8a480ea6e0d3e8c9729502282ca748a84
commit: 413b7db8a480ea6e0d3e8c9729502282ca748a84
branch: main
author: MonadChains <monadchains at gmail.com>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2023-03-23T17:42:43-06:00
summary:

gh-94684: uuid: support bytes in the name argument to uuid3/5 (#94709)

RFC 4122 does not specify that name should be a string, so for completness the functions should also support a name given as a raw byte sequence.

files:
A Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst
M Doc/library/uuid.rst
M Lib/test/test_uuid.py
M Lib/uuid.py

diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst
index 38b6434f467f..94b9a4323721 100644
--- a/Doc/library/uuid.rst
+++ b/Doc/library/uuid.rst
@@ -186,7 +186,8 @@ The :mod:`uuid` module defines the following functions:
 .. function:: uuid3(namespace, name)
 
    Generate a UUID based on the MD5 hash of a namespace identifier (which is a
-   UUID) and a name (which is a string).
+   UUID) and a name (which is a :class:`bytes` object or a string
+   that will be encoded using UTF-8).
 
 .. index:: single: uuid3
 
@@ -201,7 +202,8 @@ The :mod:`uuid` module defines the following functions:
 .. function:: uuid5(namespace, name)
 
    Generate a UUID based on the SHA-1 hash of a namespace identifier (which is a
-   UUID) and a name (which is a string).
+   UUID) and a name (which is a :class:`bytes` object or a string
+   that will be encoded using UTF-8).
 
 .. index:: single: uuid5
 
diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index b2c229cd634e..a178e942ecda 100755
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -600,7 +600,22 @@ def test_uuid1_time(self):
     def test_uuid3(self):
         equal = self.assertEqual
 
-        # Test some known version-3 UUIDs.
+        # Test some known version-3 UUIDs with name passed as a byte object
+        for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, b'python.org'),
+                      '6fa459ea-ee8a-3ca4-894e-db77e160355e'),
+                     (self.uuid.uuid3(self.uuid.NAMESPACE_URL, b'http://python.org/'),
+                      '9fe8e8c4-aaa8-32a9-a55c-4535a88b748d'),
+                     (self.uuid.uuid3(self.uuid.NAMESPACE_OID, b'1.3.6.1'),
+                      'dd1a1cef-13d5-368a-ad82-eca71acd4cd1'),
+                     (self.uuid.uuid3(self.uuid.NAMESPACE_X500, b'c=ca'),
+                      '658d3002-db6b-3040-a1d1-8ddd7d189a4d'),
+                    ]:
+            equal(u.variant, self.uuid.RFC_4122)
+            equal(u.version, 3)
+            equal(u, self.uuid.UUID(v))
+            equal(str(u), v)
+
+        # Test some known version-3 UUIDs with name passed as a string
         for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, 'python.org'),
                       '6fa459ea-ee8a-3ca4-894e-db77e160355e'),
                      (self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'),
@@ -632,7 +647,22 @@ def test_uuid4(self):
     def test_uuid5(self):
         equal = self.assertEqual
 
-        # Test some known version-5 UUIDs.
+        # Test some known version-5 UUIDs with names given as byte objects
+        for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, b'python.org'),
+                      '886313e1-3b8a-5372-9b90-0c9aee199e5d'),
+                     (self.uuid.uuid5(self.uuid.NAMESPACE_URL, b'http://python.org/'),
+                      '4c565f0d-3f5a-5890-b41b-20cf47701c5e'),
+                     (self.uuid.uuid5(self.uuid.NAMESPACE_OID, b'1.3.6.1'),
+                      '1447fa61-5277-5fef-a9b3-fbc6e44f4af3'),
+                     (self.uuid.uuid5(self.uuid.NAMESPACE_X500, b'c=ca'),
+                      'cc957dd1-a972-5349-98cd-874190002798'),
+                    ]:
+            equal(u.variant, self.uuid.RFC_4122)
+            equal(u.version, 5)
+            equal(u, self.uuid.UUID(v))
+            equal(str(u), v)
+
+        # Test some known version-5 UUIDs with names given as strings
         for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, 'python.org'),
                       '886313e1-3b8a-5372-9b90-0c9aee199e5d'),
                      (self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'),
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 1c5578bf1f05..698be34873b9 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -711,9 +711,11 @@ def uuid1(node=None, clock_seq=None):
 
 def uuid3(namespace, name):
     """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
+    if isinstance(name, str):
+        name = bytes(name, "utf-8")
     from hashlib import md5
     digest = md5(
-        namespace.bytes + bytes(name, "utf-8"),
+        namespace.bytes + name,
         usedforsecurity=False
     ).digest()
     return UUID(bytes=digest[:16], version=3)
@@ -724,8 +726,10 @@ def uuid4():
 
 def uuid5(namespace, name):
     """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
+    if isinstance(name, str):
+        name = bytes(name, "utf-8")
     from hashlib import sha1
-    hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest()
+    hash = sha1(namespace.bytes + name).digest()
     return UUID(bytes=hash[:16], version=5)
 
 
diff --git a/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst
new file mode 100644
index 000000000000..1fa38c0044d3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst
@@ -0,0 +1 @@
+Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support :class:`bytes` objects as their *name* argument.



More information about the Python-checkins mailing list