From 8c69658d07d76b1c89a0d3badbe35e0f179fd2d3 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Mon, 15 Oct 2018 16:41:53 +1100 Subject: [PATCH 1/5] uuid: Provide UUID class and uuid4() implementation using os.urandom(). Includes unit test. Signed-off-by: Damien George --- python-stdlib/uuid/manifest.py | 3 +++ python-stdlib/uuid/test_uuid.py | 15 +++++++++++++++ python-stdlib/uuid/uuid.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 python-stdlib/uuid/manifest.py create mode 100644 python-stdlib/uuid/test_uuid.py create mode 100644 python-stdlib/uuid/uuid.py diff --git a/python-stdlib/uuid/manifest.py b/python-stdlib/uuid/manifest.py new file mode 100644 index 000000000..e59bdf2c0 --- /dev/null +++ b/python-stdlib/uuid/manifest.py @@ -0,0 +1,3 @@ +metadata(version="0.1.0") + +module("uuid.py") diff --git a/python-stdlib/uuid/test_uuid.py b/python-stdlib/uuid/test_uuid.py new file mode 100644 index 000000000..5e9c81483 --- /dev/null +++ b/python-stdlib/uuid/test_uuid.py @@ -0,0 +1,15 @@ +import uuid + +u1 = uuid.uuid4() +u2 = uuid.uuid4() + +assert str(u1) != str(u2), "Two uuid4 should not match" + +assert len(str(u1)) == len(str(u1)) == 36 + +assert str(repr(u1)).startswith("") + +assert len(u1.hex) == 32 + +print("OK") diff --git a/python-stdlib/uuid/uuid.py b/python-stdlib/uuid/uuid.py new file mode 100644 index 000000000..db16473db --- /dev/null +++ b/python-stdlib/uuid/uuid.py @@ -0,0 +1,28 @@ +import os +import ubinascii + + +class UUID: + def __init__(self, bytes): + if len(bytes) != 16: + raise ValueError('bytes arg must be 16 bytes long') + self._bytes = bytes + + @property + def hex(self): + return ubinascii.hexlify(self._bytes).decode() + + def __str__(self): + h = self.hex + return '-'.join((h[0:8], h[8:12], h[12:16], h[16:20], h[20:32])) + + def __repr__(self): + return "" % str(self) + + +def uuid4(): + """Generates a random UUID compliant to RFC 4122 pg.14""" + random = bytearray(os.urandom(16)) + random[6] = (random[6] & 0x0F) | 0x40 + random[8] = (random[8] & 0x3F) | 0x80 + return UUID(bytes=random) From b6820342b83b15cd78d1bfbe9fbeb11bdaa7a098 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 11 Jul 2026 15:02:12 +1000 Subject: [PATCH 2/5] uuid: Convert test to use unittest. And run it as part of CI. Signed-off-by: Damien George --- python-stdlib/uuid/test_uuid.py | 29 +++++++++++++++++++++-------- tools/ci.sh | 1 + 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/python-stdlib/uuid/test_uuid.py b/python-stdlib/uuid/test_uuid.py index 5e9c81483..25aa308c1 100644 --- a/python-stdlib/uuid/test_uuid.py +++ b/python-stdlib/uuid/test_uuid.py @@ -1,15 +1,28 @@ +import unittest import uuid -u1 = uuid.uuid4() -u2 = uuid.uuid4() -assert str(u1) != str(u2), "Two uuid4 should not match" +class TestUUID(unittest.TestCase): + def test_unique(self): + n = 10 + us = set(uuid.uuid4().bytes for _ in range(n)) + self.assertEqual(len(us), n) -assert len(str(u1)) == len(str(u1)) == 36 + def test_len(self): + u = uuid.uuid4() + self.assertEqual(len(str(u)), 36) + self.assertEqual(len(u.hex), 32) -assert str(repr(u1)).startswith("") + def test_repr(self): + u = str(repr(uuid.uuid4())) + self.assertTrue(u.startswith("")) -assert len(u1.hex) == 32 + def test_constructor(self): + u1 = uuid.uuid4() + u2 = uuid.UUID(bytes.fromhex(u1.hex)) + self.assertEqual(u1.hex, u2.hex) -print("OK") + +if __name__ == "__main__": + unittest.main() diff --git a/tools/ci.sh b/tools/ci.sh index efbd4d186..2fc7ba004 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -106,6 +106,7 @@ function ci_package_tests_run { python-stdlib/time \ python-stdlib/unittest/tests \ python-stdlib/unittest-discover/tests \ + python-stdlib/uuid \ ; do (cd $path && "${MICROPYTHON}" -m unittest) if [ $? -ne 0 ]; then false; return; fi From ffa0ddf5fe7316108b37c286e537610506dc210c Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 11 Jul 2026 15:02:38 +1000 Subject: [PATCH 3/5] uuid: Use bytes.hex instead of binascii.hexlify. Using `bytes.hex()` eliminates an import, and eliminates the call to `.decode()` to convert it to a str. Also run ruff format. Signed-off-by: Damien George --- python-stdlib/uuid/uuid.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python-stdlib/uuid/uuid.py b/python-stdlib/uuid/uuid.py index db16473db..9790923c3 100644 --- a/python-stdlib/uuid/uuid.py +++ b/python-stdlib/uuid/uuid.py @@ -1,20 +1,19 @@ import os -import ubinascii class UUID: def __init__(self, bytes): if len(bytes) != 16: - raise ValueError('bytes arg must be 16 bytes long') + raise ValueError("bytes arg must be 16 bytes long") self._bytes = bytes @property def hex(self): - return ubinascii.hexlify(self._bytes).decode() + return self._bytes.hex() def __str__(self): h = self.hex - return '-'.join((h[0:8], h[8:12], h[12:16], h[16:20], h[20:32])) + return "-".join((h[0:8], h[8:12], h[12:16], h[16:20], h[20:32])) def __repr__(self): return "" % str(self) From 9aaeb3b23eb4503f34d6e4fdeae43978abc700a6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 Jul 2026 23:47:57 +1000 Subject: [PATCH 4/5] uuid: Add UUID.bytes attribute. Signed-off-by: Damien George --- python-stdlib/uuid/test_uuid.py | 3 ++- python-stdlib/uuid/uuid.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python-stdlib/uuid/test_uuid.py b/python-stdlib/uuid/test_uuid.py index 25aa308c1..91e6cc53a 100644 --- a/python-stdlib/uuid/test_uuid.py +++ b/python-stdlib/uuid/test_uuid.py @@ -10,8 +10,9 @@ def test_unique(self): def test_len(self): u = uuid.uuid4() - self.assertEqual(len(str(u)), 36) + self.assertEqual(len(u.bytes), 16) self.assertEqual(len(u.hex), 32) + self.assertEqual(len(str(u)), 36) def test_repr(self): u = str(repr(uuid.uuid4())) diff --git a/python-stdlib/uuid/uuid.py b/python-stdlib/uuid/uuid.py index 9790923c3..0b3a278c9 100644 --- a/python-stdlib/uuid/uuid.py +++ b/python-stdlib/uuid/uuid.py @@ -5,11 +5,11 @@ class UUID: def __init__(self, bytes): if len(bytes) != 16: raise ValueError("bytes arg must be 16 bytes long") - self._bytes = bytes + self.bytes = bytes @property def hex(self): - return self._bytes.hex() + return self.bytes.hex() def __str__(self): h = self.hex @@ -24,4 +24,4 @@ def uuid4(): random = bytearray(os.urandom(16)) random[6] = (random[6] & 0x0F) | 0x40 random[8] = (random[8] & 0x3F) | 0x80 - return UUID(bytes=random) + return UUID(bytes(random)) From 0400c5683028417897a7e071df8350e2d4746b74 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 20 Jul 2026 23:48:11 +1000 Subject: [PATCH 5/5] uuid: Make UUID.__repr__ match CPython. Signed-off-by: Damien George --- python-stdlib/uuid/test_uuid.py | 7 ++++--- python-stdlib/uuid/uuid.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/python-stdlib/uuid/test_uuid.py b/python-stdlib/uuid/test_uuid.py index 91e6cc53a..efd472296 100644 --- a/python-stdlib/uuid/test_uuid.py +++ b/python-stdlib/uuid/test_uuid.py @@ -15,9 +15,10 @@ def test_len(self): self.assertEqual(len(str(u)), 36) def test_repr(self): - u = str(repr(uuid.uuid4())) - self.assertTrue(u.startswith("")) + u = repr(uuid.uuid4()) + self.assertEqual(len(u), 44) + self.assertTrue(u.startswith("UUID('")) + self.assertTrue(u.endswith("')")) def test_constructor(self): u1 = uuid.uuid4() diff --git a/python-stdlib/uuid/uuid.py b/python-stdlib/uuid/uuid.py index 0b3a278c9..b131f7a7a 100644 --- a/python-stdlib/uuid/uuid.py +++ b/python-stdlib/uuid/uuid.py @@ -16,7 +16,7 @@ def __str__(self): return "-".join((h[0:8], h[8:12], h[12:16], h[16:20], h[20:32])) def __repr__(self): - return "" % str(self) + return "UUID('{}')".format(self) def uuid4():