From 50c6294fe3e79d48da792945f49c86206c93ea6d Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Thu, 2 Jan 2025 15:50:35 +0000 Subject: [PATCH 1/7] Add `uuid.NIL` and `uuid.MAX` --- Doc/library/uuid.rst | 25 +++++++++++++++++++ Doc/whatsnew/3.14.rst | 4 +++ Lib/test/test_uuid.py | 12 +++++++++ Lib/uuid.py | 13 ++++++++++ Misc/ACKS | 1 + ...-01-02-20-34-04.gh-issue-128427.onPoQZ.rst | 2 ++ 6 files changed, 57 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 39e82d0e19a9ac..866ecaa1d19ea8 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -288,6 +288,24 @@ of the :attr:`~UUID.variant` attribute: Reserved for future definition. +The :mod:`uuid` module defines the special Nil and Max UUID values: + + +.. data:: NIL + + A special form of UUID that is specified to have all 128 bits set to zero + according to :rfc:`RFC 9562, §5.9 <9562#section-5.9>`. + + .. versionadded:: 3.14 + + +.. data:: MAX + + A special form of UUID that is specified to have all 128 bits set to one + according to :rfc:`RFC 9562, §5.10 <9562#section-5.10>`. + + .. versionadded:: 3.14 + .. seealso:: @@ -380,6 +398,13 @@ Here are some examples of typical usage of the :mod:`uuid` module:: >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') + >>> # get the Nil UUID + >>> uuid.NIL + UUID('00000000-0000-0000-0000-000000000000') + + >>> # get the Max UUID + >>> uuid.MAX + UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') .. _uuid-cli-example: diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 61f5ffdb6c89d1..f0bf52f613920e 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -665,6 +665,10 @@ uuid in :rfc:`9562`. (Contributed by Bénédikt Tran in :gh:`89083`.) +* :data:`uuid.NIL` and :data:`uuid.MAX` are now available to represent the Nil + and Max UUID formats as defined by :rfc:`9562`. (Contributed by Nick Pope in + :gh:`128427`.) + zipinfo ------- diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 7bd26a8ca34b62..71043966decbb3 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -34,6 +34,18 @@ def get_command_stdout(command, args): class BaseTestUUID: uuid = None + def test_nil_uuid(self): + self.assertEqual( + self.uuid.NIL, + self.uuid.UUID('00000000-0000-0000-0000-000000000000'), + ) + + def test_max_uuid(self): + self.assertEqual( + self.uuid.MAX, + self.uuid.UUID('ffffffff-ffff-ffff-ffff-ffffffffffff'), + ) + def test_safe_uuid_enum(self): class CheckedSafeUUID(enum.Enum): safe = 0 diff --git a/Lib/uuid.py b/Lib/uuid.py index 9c6ad9643cf6d5..aab1a66d49d88c 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -42,6 +42,14 @@ # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') + + # get the Nil UUID + >>> uuid.NIL + UUID('00000000-0000-0000-0000-000000000000') + + # get the Max UUID + >>> uuid.MAX + UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') """ import os @@ -799,5 +807,10 @@ def main(): NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') +# RFC 9562 Sections 5.9 and 5.10 define the special Nil and Max UUID formats. + +NIL = UUID('00000000-0000-0000-0000-000000000000') +MAX = UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') + if __name__ == "__main__": main() diff --git a/Misc/ACKS b/Misc/ACKS index c6e53317b37d78..5a59fb74cd8817 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1473,6 +1473,7 @@ Michael Pomraning Martin Pool Iustin Pop Claudiu Popa +Nick Pope John Popplewell Matheus Vieira Portela Davin Potts diff --git a/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst b/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst new file mode 100644 index 00000000000000..7ed7b72518f589 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst @@ -0,0 +1,2 @@ +:data:`uuid.NIL` and :data:`uuid.MAX` are now available to represent the Nil +and Max UUID formats as defined by :rfc:`9562`. From fc14200c6583e53c568e297b855290aca6f9f1a8 Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Fri, 3 Jan 2025 10:36:06 +0000 Subject: [PATCH 2/7] Edits to documentation --- Doc/library/uuid.rst | 6 ++++-- Doc/whatsnew/3.14.rst | 7 ++++--- .../Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 866ecaa1d19ea8..09b4d4ac4ffd56 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -288,6 +288,7 @@ of the :attr:`~UUID.variant` attribute: Reserved for future definition. + The :mod:`uuid` module defines the special Nil and Max UUID values: @@ -296,7 +297,7 @@ The :mod:`uuid` module defines the special Nil and Max UUID values: A special form of UUID that is specified to have all 128 bits set to zero according to :rfc:`RFC 9562, §5.9 <9562#section-5.9>`. - .. versionadded:: 3.14 + .. versionadded:: next .. data:: MAX @@ -304,7 +305,7 @@ The :mod:`uuid` module defines the special Nil and Max UUID values: A special form of UUID that is specified to have all 128 bits set to one according to :rfc:`RFC 9562, §5.10 <9562#section-5.10>`. - .. versionadded:: 3.14 + .. versionadded:: next .. seealso:: @@ -406,6 +407,7 @@ Here are some examples of typical usage of the :mod:`uuid` module:: >>> uuid.MAX UUID('ffffffff-ffff-ffff-ffff-ffffffffffff') + .. _uuid-cli-example: Command-Line Example diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index f0bf52f613920e..e17b686a5c733b 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -665,9 +665,10 @@ uuid in :rfc:`9562`. (Contributed by Bénédikt Tran in :gh:`89083`.) -* :data:`uuid.NIL` and :data:`uuid.MAX` are now available to represent the Nil - and Max UUID formats as defined by :rfc:`9562`. (Contributed by Nick Pope in - :gh:`128427`.) +* :const:`uuid.NIL` and :const:`uuid.MAX` are now available to represent the + Nil and Max UUID formats as defined by :rfc:`9562`. + (Contributed by Nick Pope in :gh:`128427`.) + zipinfo ------- diff --git a/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst b/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst index 7ed7b72518f589..54cae43702ded7 100644 --- a/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst +++ b/Misc/NEWS.d/next/Library/2025-01-02-20-34-04.gh-issue-128427.onPoQZ.rst @@ -1,2 +1,2 @@ -:data:`uuid.NIL` and :data:`uuid.MAX` are now available to represent the Nil +:const:`uuid.NIL` and :const:`uuid.MAX` are now available to represent the Nil and Max UUID formats as defined by :rfc:`9562`. From 8b71df2e837afe582c4a74f6ecc3d9597d36f71e Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Fri, 3 Jan 2025 12:13:23 +0000 Subject: [PATCH 3/7] Edits to tests --- Lib/test/test_uuid.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 71043966decbb3..5c0da80e718334 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -35,16 +35,24 @@ class BaseTestUUID: uuid = None def test_nil_uuid(self): - self.assertEqual( - self.uuid.NIL, - self.uuid.UUID('00000000-0000-0000-0000-000000000000'), - ) + nil_uuid = self.uuid.NIL + + s = '00000000-0000-0000-0000-000000000000' + i = 0x00000000000000000000000000000000 + self.assertEqual(nil_uuid, self.uuid.UUID(s)) + self.assertEqual(nil_uuid, self.uuid.UUID(int=i)) + self.assertEqual(nil_uuid.int, i) + self.assertEqual(str(nil_uuid), s) def test_max_uuid(self): - self.assertEqual( - self.uuid.MAX, - self.uuid.UUID('ffffffff-ffff-ffff-ffff-ffffffffffff'), - ) + max_uuid = self.uuid.MAX + + s = 'ffffffff-ffff-ffff-ffff-ffffffffffff' + i = 0xffffffffffffffffffffffffffffffff + self.assertEqual(max_uuid, self.uuid.UUID(s)) + self.assertEqual(max_uuid, self.uuid.UUID(int=i)) + self.assertEqual(max_uuid.int, i) + self.assertEqual(str(max_uuid), s) def test_safe_uuid_enum(self): class CheckedSafeUUID(enum.Enum): From 2fde894bce08048e822a08c3a7a437afa887ea57 Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Mon, 6 Jan 2025 13:38:05 +0000 Subject: [PATCH 4/7] More tweaks to test assertions --- Lib/test/test_uuid.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 5c0da80e718334..ef9695f80db080 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -38,21 +38,25 @@ def test_nil_uuid(self): nil_uuid = self.uuid.NIL s = '00000000-0000-0000-0000-000000000000' - i = 0x00000000000000000000000000000000 + i = 0 self.assertEqual(nil_uuid, self.uuid.UUID(s)) self.assertEqual(nil_uuid, self.uuid.UUID(int=i)) self.assertEqual(nil_uuid.int, i) self.assertEqual(str(nil_uuid), s) + self.assertIsNone(nil_uuid.version) + self.assertEqual(nil_uuid.variant, self.uuid.RESERVED_NCS) def test_max_uuid(self): max_uuid = self.uuid.MAX s = 'ffffffff-ffff-ffff-ffff-ffffffffffff' - i = 0xffffffffffffffffffffffffffffffff + i = (1 << 128) - 1 self.assertEqual(max_uuid, self.uuid.UUID(s)) self.assertEqual(max_uuid, self.uuid.UUID(int=i)) self.assertEqual(max_uuid.int, i) self.assertEqual(str(max_uuid), s) + self.assertIsNone(max_uuid.version) + self.assertEqual(max_uuid.variant, self.uuid.RESERVED_FUTURE) def test_safe_uuid_enum(self): class CheckedSafeUUID(enum.Enum): From ecf263a1290b885b5dabf0964756381b06993e63 Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Mon, 6 Jan 2025 14:29:03 +0000 Subject: [PATCH 5/7] Add comments to test assertions --- Lib/test/test_uuid.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index ef9695f80db080..5585545f3ed013 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -43,8 +43,17 @@ def test_nil_uuid(self): self.assertEqual(nil_uuid, self.uuid.UUID(int=i)) self.assertEqual(nil_uuid.int, i) self.assertEqual(str(nil_uuid), s) - self.assertIsNone(nil_uuid.version) + # The Nil UUID falls within the range of the Apollo NCS variant as per + # RFC 9562. + # See https://www.rfc-editor.org/rfc/rfc9562.html#table1 + # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.9-4 self.assertEqual(nil_uuid.variant, self.uuid.RESERVED_NCS) + # A version field of all zeros is "Unused" in RFC 9562, but the version + # field also only applies to the 10xx variant, i.e. the variant + # specified in RFC 9562. As such, because the Nil UUID falls under a + # different variant, its version is considered undefined. + # See https://www.rfc-editor.org/rfc/rfc9562.html#table2 + self.assertIsNone(nil_uuid.version) def test_max_uuid(self): max_uuid = self.uuid.MAX @@ -55,8 +64,18 @@ def test_max_uuid(self): self.assertEqual(max_uuid, self.uuid.UUID(int=i)) self.assertEqual(max_uuid.int, i) self.assertEqual(str(max_uuid), s) - self.assertIsNone(max_uuid.version) + # The Max UUID falls within the range of the "yet-to-be defined" future + # UUID variant as per RFC 9562. + # See https://www.rfc-editor.org/rfc/rfc9562.html#table1 + # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.10-4 self.assertEqual(max_uuid.variant, self.uuid.RESERVED_FUTURE) + # A version field of all ones is "Reserved for future definition" in + # RFC 9562, but the version field also only applies to the 10xx + # variant, i.e. the variant specified in RFC 9562. As such, because the + # Max UUID falls under a different variant, its version is considered + # undefined. + # See https://www.rfc-editor.org/rfc/rfc9562.html#table2 + self.assertIsNone(max_uuid.version) def test_safe_uuid_enum(self): class CheckedSafeUUID(enum.Enum): From cba80bc6d2fa81a5f2b4b4893ab5c8f1addde305 Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Mon, 6 Jan 2025 20:34:24 +0000 Subject: [PATCH 6/7] Empty commit to retrigger CI From bf61ffee10fd42fdd9981282968ca4c965bd8cb2 Mon Sep 17 00:00:00 2001 From: Nick Pope <nick@nickpope.me.uk> Date: Tue, 7 Jan 2025 08:53:00 +0000 Subject: [PATCH 7/7] Remove extra links --- Lib/test/test_uuid.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 5585545f3ed013..49fae4e38d1231 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -45,7 +45,6 @@ def test_nil_uuid(self): self.assertEqual(str(nil_uuid), s) # The Nil UUID falls within the range of the Apollo NCS variant as per # RFC 9562. - # See https://www.rfc-editor.org/rfc/rfc9562.html#table1 # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.9-4 self.assertEqual(nil_uuid.variant, self.uuid.RESERVED_NCS) # A version field of all zeros is "Unused" in RFC 9562, but the version @@ -66,7 +65,6 @@ def test_max_uuid(self): self.assertEqual(str(max_uuid), s) # The Max UUID falls within the range of the "yet-to-be defined" future # UUID variant as per RFC 9562. - # See https://www.rfc-editor.org/rfc/rfc9562.html#table1 # See https://www.rfc-editor.org/rfc/rfc9562.html#section-5.10-4 self.assertEqual(max_uuid.variant, self.uuid.RESERVED_FUTURE) # A version field of all ones is "Reserved for future definition" in