diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index ea9ea7dc7d9b82..d2ac13fe159d83 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -75,6 +75,10 @@ which relays any information about the UUID's safety, using this enumeration: ``12345678-1234-5678-1234-567812345678`` where the 32 hexadecimal digits represent the UUID. + .. versionchanged:: 3.7 + *bytes* and *bytes_le* parameters now accept any bytes-like objects of 16 + bytes, bytearray and memoryview for example, not only :class:`bytes`. + :class:`UUID` instances have these read-only attributes: .. attribute:: UUID.bytes diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 083c2aa8aab54d..e43232a8ecd5c1 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -220,14 +220,20 @@ def test_exceptions(self): badvalue(lambda: self.uuid.UUID('123456781234567812345678z2345678')) # Badly formed bytes. - badvalue(lambda: self.uuid.UUID(bytes='abc')) - badvalue(lambda: self.uuid.UUID(bytes='\0'*15)) - badvalue(lambda: self.uuid.UUID(bytes='\0'*17)) + badtype(lambda: self.uuid.UUID(bytes='unicode')) + badtype(lambda: self.uuid.UUID(bytes='u'*16)) + badvalue(lambda: self.uuid.UUID(bytes=b'abc')) + badvalue(lambda: self.uuid.UUID(bytes=b'\0'*15)) + badvalue(lambda: self.uuid.UUID(bytes=b'\0'*17)) + badtype(lambda: self.uuid.UUID(bytes=16)) # Badly formed bytes_le. - badvalue(lambda: self.uuid.UUID(bytes_le='abc')) - badvalue(lambda: self.uuid.UUID(bytes_le='\0'*15)) - badvalue(lambda: self.uuid.UUID(bytes_le='\0'*17)) + badtype(lambda: self.uuid.UUID(bytes_le='unicode')) + badtype(lambda: self.uuid.UUID(bytes_le='u'*16)) + badvalue(lambda: self.uuid.UUID(bytes_le=b'abc')) + badvalue(lambda: self.uuid.UUID(bytes_le=b'\0'*15)) + badvalue(lambda: self.uuid.UUID(bytes_le=b'\0'*17)) + badtype(lambda: self.uuid.UUID(bytes_le=16)) # Badly formed fields. badvalue(lambda: self.uuid.UUID(fields=(1,))) @@ -476,6 +482,15 @@ def testIssue8621(self): self.assertNotEqual(parent_value, child_value) + def test_bytes_like(self): + u = self.uuid.uuid4() + + self.assertEqual(self.uuid.UUID(bytes=memoryview(u.bytes)), u) + self.assertEqual(self.uuid.UUID(bytes=bytearray(u.bytes)), u) + + self.assertEqual(self.uuid.UUID(bytes_le=memoryview(u.bytes_le)), u) + self.assertEqual(self.uuid.UUID(bytes_le=bytearray(u.bytes_le)), u) + class TestUUIDWithoutExtModule(BaseTestUUID, unittest.TestCase): uuid = py_uuid diff --git a/Lib/uuid.py b/Lib/uuid.py index 3123ff88a16b0b..951f27ef632ec5 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -160,15 +160,18 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, raise ValueError('badly formed hexadecimal UUID string') int = int_(hex, 16) if bytes_le is not None: + if not isinstance(bytes_le, (bytes_, bytearray, int_)): + bytes_le = bytes_(bytes_le) if len(bytes_le) != 16: raise ValueError('bytes_le is not a 16-char string') bytes = (bytes_le[4-1::-1] + bytes_le[6-1:4-1:-1] + bytes_le[8-1:6-1:-1] + bytes_le[8:]) if bytes is not None: + int = int_.from_bytes(bytes, byteorder='big') + # test length after the conversion to raise a TypeError exception + # if 'bytes' type is str even if 'bytes' length is not 16 if len(bytes) != 16: raise ValueError('bytes is not a 16-char string') - assert isinstance(bytes, bytes_), repr(bytes) - int = int_.from_bytes(bytes, byteorder='big') if fields is not None: if len(fields) != 6: raise ValueError('fields is not a 6-tuple') diff --git a/Misc/NEWS.d/next/Library/2017-09-28-16-21-13.bpo-29729.skDkJA.rst b/Misc/NEWS.d/next/Library/2017-09-28-16-21-13.bpo-29729.skDkJA.rst new file mode 100644 index 00000000000000..502b04a7f57149 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-28-16-21-13.bpo-29729.skDkJA.rst @@ -0,0 +1,3 @@ +uuid.UUID now accepts bytes-like object of 16 bytes. The constructor doesn't +require the 'bytes' and 'bytes_le' arguments to be an instance of bytes: accept +bytes-like types, bytearray and memoryview for example.