From bbdef4c80d0e04221711a5cfcc9671af987bb28b Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Thu, 16 Feb 2017 10:41:22 -0500 Subject: [PATCH 01/11] bpo-22807: Expose platform UUID generation safety information. --- Doc/library/uuid.rst | 31 ++++++++++++++++++++++++++++++- Lib/test/test_uuid.py | 40 ++++++++++++++++++++++++++++++++++++++++ Lib/uuid.py | 36 +++++++++++++++++++++++++++++++----- Misc/NEWS | 4 ++++ 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index edbf832529a64f..40d6ac7f08ac6d 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -19,8 +19,30 @@ If all you want is a unique ID, you should probably call :func:`uuid1` or a UUID containing the computer's network address. :func:`uuid4` creates a random UUID. +Depending on support from the underlying platform, :func:`uuid1` may or may +not return a "safe" UUID. A safe UUID is one which is generated using +synchronization methods that ensure no two processes can obtain the same +UUID. All instances of :class:`UUID` have an :attr:`is_safe` attribute +which relays any information about the UUID's safety, using this enumeration: -.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None) +.. class:: SafeUUID + +.. attribute:: SafeUUID.safe + + The UUID was generated by the platform in a multiprocessing-safe way. + +.. attribute:: SafeUUID.unsafe + + The UUID was not generated in a multiprocessing-safe way. + +.. attribute:: SafeUUID.unknown + + The platform does not provide information on whether the UUID was generated + safely or not. + +.. versionadded:: 3.7 + +.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, is_safe=SafeUUID.unknown) Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the *bytes* argument, a string of 16 bytes in little-endian order as @@ -120,6 +142,13 @@ random UUID. The UUID version number (1 through 5, meaningful only when the variant is :const:`RFC_4122`). +.. attribute:: UUID.is_safe + + An enumeration of :class:`SafeUUID` which indicates whether the platform + generated the UUID in a multiprocessing-safe way. + + .. versionadded:: 3.7 + The :mod:`uuid` module defines the following functions: diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 47248f92c7b6af..df0593311ca2e7 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -340,6 +340,46 @@ def test_uuid1(self): equal(((u.clock_seq_hi_variant & 0x3f) << 8) | u.clock_seq_low, 0x3fff) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + @unittest.skipUnless(uuid._uuid_generate_time.restype is not None, + 'requires uuid_generate_time_safe(3)') + def test_uuid1_safe(self): + u = uuid.uuid1() + # uuid_generate_time_safe() may return 0 or -1 but what it returns is + # dependent on the underlying platform support. At least it cannot be + # unknown (unless I suppose the platform is buggy). + self.assertNotEqual(u.is_safe, uuid.SafeUUID.unknown) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_unknown(self): + # Even if the platform has uuid_generate_time_safe(), let's mock it to + # be uuid_generate_time() and ensure the safety is unknown. + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', None): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.unknown) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_is_safe(self): + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', lambda x: 0): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.safe) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_is_unsafe(self): + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', lambda x: -1): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.unsafe) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_bogus_return_value(self): + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', lambda x: 3): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.unknown) + def test_uuid3(self): equal = self.assertEqual diff --git a/Lib/uuid.py b/Lib/uuid.py index 200c800b34e4bb..47e0b4242b83d0 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -46,6 +46,9 @@ import os +from enum import Enum + + __author__ = 'Ka-Ping Yee ' RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ @@ -55,7 +58,14 @@ int_ = int # The built-in int type bytes_ = bytes # The built-in bytes type -class UUID(object): + +class SafeUUID(Enum): + safe = 0 + unsafe = -1 + unknown = None + + +class UUID: """Instances of the UUID class represent UUIDs as specified in RFC 4122. UUID objects are immutable, hashable, and usable as dictionary keys. Converting a UUID to a string with str() yields something in the form @@ -104,7 +114,7 @@ class UUID(object): """ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, - int=None, version=None): + int=None, version=None, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six @@ -128,6 +138,10 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, be given. The 'version' argument is optional; if given, the resulting UUID will have its variant and version set according to RFC 4122, overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'. + + is_safe is an enum exposed as an attribute on the instance. It + indicates whether the UUID has been generated in a way that is safe + for multiprocessing applications, via uuid_generate_time_safe(3). """ if [hex, bytes, bytes_le, fields, int].count(None) != 4: @@ -182,6 +196,7 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, int &= ~(0xf000 << 64) int |= version << 76 self.__dict__['int'] = int + self.__dict__['is_safe'] = is_safe def __eq__(self, other): if isinstance(other, UUID): @@ -474,8 +489,15 @@ def _netbios_getnode(): lib = ctypes.CDLL(ctypes.util.find_library(libname)) except Exception: continue - if hasattr(lib, 'uuid_generate_time'): + # Try to find the safe variety first. + if hasattr(lib, 'uuid_generate_time_safe'): + _uuid_generate_time = lib.uuid_generate_time_safe + # int uuid_generate_time_safe(uuid_t out); + break + elif hasattr(lib, 'uuid_generate_time'): _uuid_generate_time = lib.uuid_generate_time + # void uuid_generate_time(uuid_t out); + _uuid_generate_time.restype = None break del _libnames @@ -566,8 +588,12 @@ def uuid1(node=None, clock_seq=None): # use UuidCreate here because its UUIDs don't conform to RFC 4122). if _uuid_generate_time and node is clock_seq is None: _buffer = ctypes.create_string_buffer(16) - _uuid_generate_time(_buffer) - return UUID(bytes=bytes_(_buffer.raw)) + safely_generated = _uuid_generate_time(_buffer) + try: + is_safe = SafeUUID(safely_generated) + except ValueError: + is_safe = SafeUUID.unknown + return UUID(bytes=bytes_(_buffer.raw), is_safe=is_safe) global _last_timestamp import time diff --git a/Misc/NEWS b/Misc/NEWS index 1422627b9052a2..0e4fd7838cfe89 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,10 @@ Extension Modules Library ------- +- bpo-22807: Add uuid.SafeUUID and uuid.UUID.is_safe to relay information from + the platform about whether generated UUIDs are generated with a + multiprocessing safe method. + - bpo-29576: Improve some deprecations in importlib. Some deprecated methods now emit DeprecationWarnings and have better descriptive messages. From ccefb3ad7aa89d59ab8abf881171367b375a94de Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Thu, 16 Feb 2017 11:56:15 -0500 Subject: [PATCH 02/11] pragma-fy some lines that are okay not to get covered. --- Lib/uuid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 47e0b4242b83d0..ebb57e18a3d30e 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -487,14 +487,14 @@ def _netbios_getnode(): for libname in _libnames: try: lib = ctypes.CDLL(ctypes.util.find_library(libname)) - except Exception: + except Exception: # pragma: nocover continue # Try to find the safe variety first. if hasattr(lib, 'uuid_generate_time_safe'): _uuid_generate_time = lib.uuid_generate_time_safe # int uuid_generate_time_safe(uuid_t out); break - elif hasattr(lib, 'uuid_generate_time'): + elif hasattr(lib, 'uuid_generate_time'): # pragma: nocover _uuid_generate_time = lib.uuid_generate_time # void uuid_generate_time(uuid_t out); _uuid_generate_time.restype = None From 9040ce0478fdda48e8b78789695b1aa96e6ac17e Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 17 Feb 2017 10:22:49 -0500 Subject: [PATCH 03/11] Make is_safe a keyword argument. --- Doc/library/uuid.rst | 2 +- Lib/uuid.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 40d6ac7f08ac6d..cafe0b8b084428 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -42,7 +42,7 @@ which relays any information about the UUID's safety, using this enumeration: .. versionadded:: 3.7 -.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, is_safe=SafeUUID.unknown) +.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, *, is_safe=SafeUUID.unknown) Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the *bytes* argument, a string of 16 bytes in little-endian order as diff --git a/Lib/uuid.py b/Lib/uuid.py index ebb57e18a3d30e..a5594def677983 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -114,7 +114,8 @@ class UUID: """ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, - int=None, version=None, is_safe=SafeUUID.unknown): + int=None, version=None, + *, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six From 440f56023a15933a354d89458f73adc20a7a82af Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 17 Feb 2017 10:23:03 -0500 Subject: [PATCH 04/11] Oops, fix indentation. --- Lib/uuid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index a5594def677983..c26469425e6962 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -115,7 +115,7 @@ class UUID: def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, - *, is_safe=SafeUUID.unknown): + *, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six From 1b3d88eb33085e90af729c4c2f78b5ba1b942b1e Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sat, 18 Feb 2017 12:01:47 +0530 Subject: [PATCH 05/11] Make devguide link in README more prominent (#145) --- README.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 652dfef7df304a..8b701c1d9c94d6 100644 --- a/README.rst +++ b/README.rst @@ -15,6 +15,13 @@ reserved. See the end of this file for further copyright and license information. +Contributing to CPython +----------------------- + +For more complete instructions on contributing to CPython development, +see the `Developer Guide`_. + +.. _Developer Guide: https://docs.python.org/devguide/ Using Python ------------ @@ -126,10 +133,6 @@ is downloadable in HTML, PDF, and reStructuredText formats; the latter version is primarily for documentation authors, translators, and people with special formatting requirements. -If you would like to contribute to the development of Python, relevant -documentation is available in the `Python Developer's Guide -`_. - For information about building Python's documentation, refer to `Doc/README.rst `_. From ace5c0fdd9b962e6e886c29dbcea72c53f051dc4 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sat, 18 Feb 2017 15:01:22 +0530 Subject: [PATCH 06/11] bpo-29571: Use correct locale encoding in test_re (#149) ``local.getlocale(locale.LC_CTYPE)`` and ``locale.getpreferredencoding(False)`` may give different answers in some cases (such as the ``en_IN`` locale). ``re.LOCALE`` uses the latter, so update the test case to match. --- Lib/test/test_re.py | 2 +- Misc/NEWS | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 1d7fb76c383396..92d2c1386de464 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1399,7 +1399,7 @@ def test_ascii_and_unicode_flag(self): def test_locale_flag(self): import locale - _, enc = locale.getlocale(locale.LC_CTYPE) + enc = locale.getpreferredencoding(False) # Search non-ASCII letter for i in range(128, 256): try: diff --git a/Misc/NEWS b/Misc/NEWS index 1422627b9052a2..53f1dc6d7f0c4f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -801,6 +801,11 @@ Tools/Demos Tests ----- +- Issue #29571: to match the behaviour of the ``re.LOCALE`` flag, + test_re.test_locale_flag now uses ``locale.getpreferredencoding(False)`` to + determine the candidate encoding for the test regex (allowing it to correctly + skip the test when the default locale encoding is a multi-byte encoding) + - Issue #24932: Use proper command line parsing in _testembed - Issue #28950: Disallow -j0 to be combined with -T/-l in regrtest From 7787df6752ecba9727b3a3f5d52aef3698654c8d Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Thu, 16 Feb 2017 10:41:22 -0500 Subject: [PATCH 07/11] bpo-22807: Expose platform UUID generation safety information. --- Doc/library/uuid.rst | 31 ++++++++++++++++++++++++++++++- Lib/test/test_uuid.py | 40 ++++++++++++++++++++++++++++++++++++++++ Lib/uuid.py | 36 +++++++++++++++++++++++++++++++----- Misc/NEWS | 4 ++++ 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index edbf832529a64f..40d6ac7f08ac6d 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -19,8 +19,30 @@ If all you want is a unique ID, you should probably call :func:`uuid1` or a UUID containing the computer's network address. :func:`uuid4` creates a random UUID. +Depending on support from the underlying platform, :func:`uuid1` may or may +not return a "safe" UUID. A safe UUID is one which is generated using +synchronization methods that ensure no two processes can obtain the same +UUID. All instances of :class:`UUID` have an :attr:`is_safe` attribute +which relays any information about the UUID's safety, using this enumeration: -.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None) +.. class:: SafeUUID + +.. attribute:: SafeUUID.safe + + The UUID was generated by the platform in a multiprocessing-safe way. + +.. attribute:: SafeUUID.unsafe + + The UUID was not generated in a multiprocessing-safe way. + +.. attribute:: SafeUUID.unknown + + The platform does not provide information on whether the UUID was generated + safely or not. + +.. versionadded:: 3.7 + +.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, is_safe=SafeUUID.unknown) Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the *bytes* argument, a string of 16 bytes in little-endian order as @@ -120,6 +142,13 @@ random UUID. The UUID version number (1 through 5, meaningful only when the variant is :const:`RFC_4122`). +.. attribute:: UUID.is_safe + + An enumeration of :class:`SafeUUID` which indicates whether the platform + generated the UUID in a multiprocessing-safe way. + + .. versionadded:: 3.7 + The :mod:`uuid` module defines the following functions: diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 47248f92c7b6af..df0593311ca2e7 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -340,6 +340,46 @@ def test_uuid1(self): equal(((u.clock_seq_hi_variant & 0x3f) << 8) | u.clock_seq_low, 0x3fff) + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + @unittest.skipUnless(uuid._uuid_generate_time.restype is not None, + 'requires uuid_generate_time_safe(3)') + def test_uuid1_safe(self): + u = uuid.uuid1() + # uuid_generate_time_safe() may return 0 or -1 but what it returns is + # dependent on the underlying platform support. At least it cannot be + # unknown (unless I suppose the platform is buggy). + self.assertNotEqual(u.is_safe, uuid.SafeUUID.unknown) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_unknown(self): + # Even if the platform has uuid_generate_time_safe(), let's mock it to + # be uuid_generate_time() and ensure the safety is unknown. + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', None): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.unknown) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_is_safe(self): + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', lambda x: 0): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.safe) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_is_unsafe(self): + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', lambda x: -1): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.unsafe) + + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') + def test_uuid1_bogus_return_value(self): + with unittest.mock.patch.object(uuid._uuid_generate_time, + 'restype', lambda x: 3): + u = uuid.uuid1() + self.assertEqual(u.is_safe, uuid.SafeUUID.unknown) + def test_uuid3(self): equal = self.assertEqual diff --git a/Lib/uuid.py b/Lib/uuid.py index 200c800b34e4bb..47e0b4242b83d0 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -46,6 +46,9 @@ import os +from enum import Enum + + __author__ = 'Ka-Ping Yee ' RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ @@ -55,7 +58,14 @@ int_ = int # The built-in int type bytes_ = bytes # The built-in bytes type -class UUID(object): + +class SafeUUID(Enum): + safe = 0 + unsafe = -1 + unknown = None + + +class UUID: """Instances of the UUID class represent UUIDs as specified in RFC 4122. UUID objects are immutable, hashable, and usable as dictionary keys. Converting a UUID to a string with str() yields something in the form @@ -104,7 +114,7 @@ class UUID(object): """ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, - int=None, version=None): + int=None, version=None, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six @@ -128,6 +138,10 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, be given. The 'version' argument is optional; if given, the resulting UUID will have its variant and version set according to RFC 4122, overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'. + + is_safe is an enum exposed as an attribute on the instance. It + indicates whether the UUID has been generated in a way that is safe + for multiprocessing applications, via uuid_generate_time_safe(3). """ if [hex, bytes, bytes_le, fields, int].count(None) != 4: @@ -182,6 +196,7 @@ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, int &= ~(0xf000 << 64) int |= version << 76 self.__dict__['int'] = int + self.__dict__['is_safe'] = is_safe def __eq__(self, other): if isinstance(other, UUID): @@ -474,8 +489,15 @@ def _netbios_getnode(): lib = ctypes.CDLL(ctypes.util.find_library(libname)) except Exception: continue - if hasattr(lib, 'uuid_generate_time'): + # Try to find the safe variety first. + if hasattr(lib, 'uuid_generate_time_safe'): + _uuid_generate_time = lib.uuid_generate_time_safe + # int uuid_generate_time_safe(uuid_t out); + break + elif hasattr(lib, 'uuid_generate_time'): _uuid_generate_time = lib.uuid_generate_time + # void uuid_generate_time(uuid_t out); + _uuid_generate_time.restype = None break del _libnames @@ -566,8 +588,12 @@ def uuid1(node=None, clock_seq=None): # use UuidCreate here because its UUIDs don't conform to RFC 4122). if _uuid_generate_time and node is clock_seq is None: _buffer = ctypes.create_string_buffer(16) - _uuid_generate_time(_buffer) - return UUID(bytes=bytes_(_buffer.raw)) + safely_generated = _uuid_generate_time(_buffer) + try: + is_safe = SafeUUID(safely_generated) + except ValueError: + is_safe = SafeUUID.unknown + return UUID(bytes=bytes_(_buffer.raw), is_safe=is_safe) global _last_timestamp import time diff --git a/Misc/NEWS b/Misc/NEWS index 53f1dc6d7f0c4f..9d61b4623e659c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -229,6 +229,10 @@ Extension Modules Library ------- +- bpo-22807: Add uuid.SafeUUID and uuid.UUID.is_safe to relay information from + the platform about whether generated UUIDs are generated with a + multiprocessing safe method. + - bpo-29576: Improve some deprecations in importlib. Some deprecated methods now emit DeprecationWarnings and have better descriptive messages. From 27753e2aae2449fabc2d6d6d01aeb85d3810dcc1 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Thu, 16 Feb 2017 11:56:15 -0500 Subject: [PATCH 08/11] pragma-fy some lines that are okay not to get covered. --- Lib/uuid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 47e0b4242b83d0..ebb57e18a3d30e 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -487,14 +487,14 @@ def _netbios_getnode(): for libname in _libnames: try: lib = ctypes.CDLL(ctypes.util.find_library(libname)) - except Exception: + except Exception: # pragma: nocover continue # Try to find the safe variety first. if hasattr(lib, 'uuid_generate_time_safe'): _uuid_generate_time = lib.uuid_generate_time_safe # int uuid_generate_time_safe(uuid_t out); break - elif hasattr(lib, 'uuid_generate_time'): + elif hasattr(lib, 'uuid_generate_time'): # pragma: nocover _uuid_generate_time = lib.uuid_generate_time # void uuid_generate_time(uuid_t out); _uuid_generate_time.restype = None From c8982010e76631bd47a82dfb554ea1a07e2c78b1 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 17 Feb 2017 10:22:49 -0500 Subject: [PATCH 09/11] Make is_safe a keyword argument. --- Doc/library/uuid.rst | 2 +- Lib/uuid.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 40d6ac7f08ac6d..cafe0b8b084428 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -42,7 +42,7 @@ which relays any information about the UUID's safety, using this enumeration: .. versionadded:: 3.7 -.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, is_safe=SafeUUID.unknown) +.. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, *, is_safe=SafeUUID.unknown) Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the *bytes* argument, a string of 16 bytes in little-endian order as diff --git a/Lib/uuid.py b/Lib/uuid.py index ebb57e18a3d30e..a5594def677983 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -114,7 +114,8 @@ class UUID: """ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, - int=None, version=None, is_safe=SafeUUID.unknown): + int=None, version=None, + *, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six From fb3088ad09490baffe35681c2f1c1968df0b1efc Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Fri, 17 Feb 2017 10:23:03 -0500 Subject: [PATCH 10/11] Oops, fix indentation. --- Lib/uuid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index a5594def677983..c26469425e6962 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -115,7 +115,7 @@ class UUID: def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, - *, is_safe=SafeUUID.unknown): + *, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six From 7b29c47c18aa18b9ba163abbc56f6735137ce317 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Sat, 18 Feb 2017 15:17:27 -0500 Subject: [PATCH 11/11] Respond to review --- Doc/library/uuid.rst | 16 ++++++++-------- Lib/test/test_uuid.py | 2 +- Lib/uuid.py | 4 ++++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index cafe0b8b084428..ea9ea7dc7d9b82 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -27,20 +27,20 @@ which relays any information about the UUID's safety, using this enumeration: .. class:: SafeUUID -.. attribute:: SafeUUID.safe + .. versionadded:: 3.7 - The UUID was generated by the platform in a multiprocessing-safe way. + .. attribute:: SafeUUID.safe -.. attribute:: SafeUUID.unsafe + The UUID was generated by the platform in a multiprocessing-safe way. - The UUID was not generated in a multiprocessing-safe way. + .. attribute:: SafeUUID.unsafe -.. attribute:: SafeUUID.unknown + The UUID was not generated in a multiprocessing-safe way. - The platform does not provide information on whether the UUID was generated - safely or not. + .. attribute:: SafeUUID.unknown -.. versionadded:: 3.7 + The platform does not provide information on whether the UUID was + generated safely or not. .. class:: UUID(hex=None, bytes=None, bytes_le=None, fields=None, int=None, version=None, *, is_safe=SafeUUID.unknown) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index df0593311ca2e7..c912c02c2e17d0 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -340,9 +340,9 @@ def test_uuid1(self): equal(((u.clock_seq_hi_variant & 0x3f) << 8) | u.clock_seq_low, 0x3fff) - @unittest.skipUnless(importable('ctypes'), 'requires ctypes') @unittest.skipUnless(uuid._uuid_generate_time.restype is not None, 'requires uuid_generate_time_safe(3)') + @unittest.skipUnless(importable('ctypes'), 'requires ctypes') def test_uuid1_safe(self): u = uuid.uuid1() # uuid_generate_time_safe() may return 0 or -1 but what it returns is diff --git a/Lib/uuid.py b/Lib/uuid.py index c26469425e6962..d4259ae0b3bd67 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -111,6 +111,10 @@ class UUID: version the UUID version number (1 through 5, meaningful only when the variant is RFC_4122) + + is_safe An enum indicating whether the UUID has been generated in + a way that is safe for multiprocessing applications, via + uuid_generate_time_safe(3). """ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,