mirror of
https://github.com/python/cpython.git
synced 2025-12-04 00:30:19 +00:00
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.
This commit is contained in:
parent
f1e3eeebc0
commit
413b7db8a4
4 changed files with 43 additions and 6 deletions
|
|
@ -186,7 +186,8 @@ The :mod:`uuid` module defines the following functions:
|
||||||
.. function:: uuid3(namespace, name)
|
.. function:: uuid3(namespace, name)
|
||||||
|
|
||||||
Generate a UUID based on the MD5 hash of a namespace identifier (which is a
|
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
|
.. index:: single: uuid3
|
||||||
|
|
||||||
|
|
@ -201,7 +202,8 @@ The :mod:`uuid` module defines the following functions:
|
||||||
.. function:: uuid5(namespace, name)
|
.. function:: uuid5(namespace, name)
|
||||||
|
|
||||||
Generate a UUID based on the SHA-1 hash of a namespace identifier (which is a
|
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
|
.. index:: single: uuid5
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -600,7 +600,22 @@ class BaseTestUUID:
|
||||||
def test_uuid3(self):
|
def test_uuid3(self):
|
||||||
equal = self.assertEqual
|
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'),
|
for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, 'python.org'),
|
||||||
'6fa459ea-ee8a-3ca4-894e-db77e160355e'),
|
'6fa459ea-ee8a-3ca4-894e-db77e160355e'),
|
||||||
(self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'),
|
(self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'),
|
||||||
|
|
@ -632,7 +647,22 @@ class BaseTestUUID:
|
||||||
def test_uuid5(self):
|
def test_uuid5(self):
|
||||||
equal = self.assertEqual
|
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'),
|
for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, 'python.org'),
|
||||||
'886313e1-3b8a-5372-9b90-0c9aee199e5d'),
|
'886313e1-3b8a-5372-9b90-0c9aee199e5d'),
|
||||||
(self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'),
|
(self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'),
|
||||||
|
|
|
||||||
|
|
@ -711,9 +711,11 @@ def uuid1(node=None, clock_seq=None):
|
||||||
|
|
||||||
def uuid3(namespace, name):
|
def uuid3(namespace, name):
|
||||||
"""Generate a UUID from the MD5 hash of a namespace UUID and a 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
|
from hashlib import md5
|
||||||
digest = md5(
|
digest = md5(
|
||||||
namespace.bytes + bytes(name, "utf-8"),
|
namespace.bytes + name,
|
||||||
usedforsecurity=False
|
usedforsecurity=False
|
||||||
).digest()
|
).digest()
|
||||||
return UUID(bytes=digest[:16], version=3)
|
return UUID(bytes=digest[:16], version=3)
|
||||||
|
|
@ -724,8 +726,10 @@ def uuid4():
|
||||||
|
|
||||||
def uuid5(namespace, name):
|
def uuid5(namespace, name):
|
||||||
"""Generate a UUID from the SHA-1 hash of a namespace UUID and a 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
|
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)
|
return UUID(bytes=hash[:16], version=5)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support :class:`bytes` objects as their *name* argument.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue