-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-22807: Expose platform UUID generation safety information. #138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bbdef4c
ccefb3a
9040ce0
440f560
1b3d88e
ace5c0f
7787df6
27753e2
c898201
fb3088a
4956e88
7b29c47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,9 @@ | |
|
||
import os | ||
|
||
from enum import Enum | ||
|
||
|
||
__author__ = 'Ka-Ping Yee <ping@zesty.ca>' | ||
|
||
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 | ||
|
@@ -101,10 +111,15 @@ class UUID(object): | |
|
||
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, | ||
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 +143,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 +201,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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you want to assert the type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure it's worth type checking |
||
|
||
def __eq__(self, other): | ||
if isinstance(other, UUID): | ||
|
@@ -472,10 +492,17 @@ def _netbios_getnode(): | |
for libname in _libnames: | ||
try: | ||
lib = ctypes.CDLL(ctypes.util.find_library(libname)) | ||
except Exception: | ||
except Exception: # pragma: nocover | ||
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'): # pragma: nocover | ||
_uuid_generate_time = lib.uuid_generate_time | ||
# void uuid_generate_time(uuid_t out); | ||
_uuid_generate_time.restype = None | ||
break | ||
del _libnames | ||
|
||
|
@@ -566,8 +593,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 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a suggestion: Using
self.subTest()
would make the following four tests much shorter and IMO easier to understand.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've played a bit with
subTest()
and I'm not entirely thrilled with it. AFAICT, subtests only print output when they fail, not when they succeed. In verbose mode, I'd want to see all 4 tests printed individually. (That's one of the things I'd like to eventually fix.) For now, I think I'll leave them as separate tests.