Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Doc/library/uuid.rst
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ The :mod:`!uuid` module defines the following functions:
If *node* or *clock_seq* exceed their expected bit count,
only their least significant bits are kept.

.. versionchanged:: next
On Windows, when neither *node* nor *clock_seq* is given, the UUID is
now generated by the system ``UuidCreateSequential()`` function and
reported as safe by :attr:`UUID.is_safe`.


.. function:: uuid3(namespace, name)

Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,8 +636,17 @@ def test_uuid1_bogus_return_value(self):
self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown)
self.assertEqual(u.version, 1)

def test_uuid1_windows_safe(self):
if self.uuid._UuidCreate is None:
self.skipTest('requires _uuid.UuidCreate')
u = self.uuid.uuid1()
self.assertEqual(u.is_safe, self.uuid.SafeUUID.safe)
self.assertEqual(u.version, 1)
self.assertEqual(u.variant, self.uuid.RFC_4122)

def test_uuid1_time(self):
with mock.patch.object(self.uuid, '_generate_time_safe', None), \
mock.patch.object(self.uuid, '_UuidCreate', None), \
mock.patch.object(self.uuid, '_last_timestamp', None), \
mock.patch.object(self.uuid, 'getnode', return_value=93328246233727), \
mock.patch('time.time_ns', return_value=1545052026752910643), \
Expand Down
24 changes: 14 additions & 10 deletions Lib/uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,16 +729,20 @@ def uuid1(node=None, clock_seq=None):
address. If 'clock_seq' is given, it is used as the sequence number;
otherwise a random 14-bit sequence number is chosen."""

# When the system provides a version-1 UUID generator, use it (but don't
# use UuidCreate here because its UUIDs don't conform to RFC 4122).
if _generate_time_safe is not None and node is clock_seq is None:
uuid_time, safely_generated = _generate_time_safe()
try:
is_safe = SafeUUID(safely_generated)
except ValueError:
is_safe = SafeUUID.unknown
# The version field is assumed to be handled by _generate_time_safe().
return UUID(bytes=uuid_time, is_safe=is_safe)
# When the system provides a version-1 UUID generator, use it.
if node is clock_seq is None:
if _generate_time_safe is not None:
uuid_time, safely_generated = _generate_time_safe()
try:
is_safe = SafeUUID(safely_generated)
except ValueError:
is_safe = SafeUUID.unknown
# The version field is assumed to be handled by
# _generate_time_safe().
return UUID(bytes=uuid_time, is_safe=is_safe)
if _UuidCreate is not None:
uuid_bytes = _UuidCreate()
return UUID(bytes_le=uuid_bytes, is_safe=SafeUUID.safe)

global _last_timestamp
nanoseconds = time.time_ns()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
On Windows, :func:`uuid.uuid1` now uses the system
``UuidCreateSequential()`` function when neither *node* nor *clock_seq* is
given, so concurrent processes no longer produce colliding UUIDs and the
result is reported as safe by :attr:`uuid.UUID.is_safe`.
Loading