8000 gh-89083: support UUID version 7 (monotonous version) (RFC 9562) [abandoned proposal] by picnixz · Pull Request #120830 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-89083: support UUID version 7 (monotonous version) (RFC 9562) [abandoned proposal] #120830

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

Closed
wants to merge 15 commits into from
Prev Previous commit
Next Next commit
add tests
  • Loading branch information
picnixz committed Jun 17, 2024
commit 16565f29d7197d0a2eaf25d66f4cd2ff052b6f5b
86 changes: 83 additions & 3 deletions Lib/test/test_uuid.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import random
import unittest
from test import support
from test.support import import_helper
Expand All @@ -10,6 +11,7 @@
import pickle
import sys
import weakref
from itertools import product
from unittest import mock

py_uuid = import_helper.import_fresh_module('uuid', blocked=['_uuid'])
Expand Down Expand Up @@ -267,7 +269,7 @@ def test_exceptions(self):

# Version number out of range.
badvalue(lambda: self.uuid.UUID('00'*16, version=0))
badvalue(lambda: self.uuid.UUID('00'*16, version=6))
badvalue(lambda: self.uuid.UUID('00'*16, version=42))

# Integer value out of range.
badvalue(lambda: self.uuid.UUID(int=-1))
Expand Down Expand Up @@ -588,15 +590,15 @@ def test_uuid1_bogus_return_value(self):

def test_uuid1_time(self):
with mock.patch.object(self.uuid, '_generate_time_safe', None), \
mock.patch.object(self.uuid, '_last_timestamp', None), \
mock.patch.object(self.uuid, '_last_timestamp_v1', None), \
mock.patch.object(self.uuid, 'getnode', return_value=93328246233727), \
mock.patch('time.time_ns', return_value=1545052026752910643), \
mock.patch('random.getrandbits', return_value=5317): # guaranteed to be random
u = self.uuid.uuid1()
self.assertEqual(u, self.uuid.UUID('a7a55b92-01fc-11e9-94c5-54e1acf6da7f'))

with mock.patch.object(self.uuid, '_generate_time_safe', None), \
mock.patch.object(self.uuid, '_last_timestamp', None), \
mock.patch.object(self.uuid, '_last_timestamp_v1', None), \
mock.patch('time.time_ns', return_value=1545052026752910643):
u = self.uuid.uuid1(node=93328246233727, clock_seq=5317)
self.assertEqual(u, self.uuid.UUID('a7a55b92-01fc-11e9-94c5-54e1acf6da7f'))
Expand Down Expand Up @@ -681,6 +683,84 @@ def test_uuid5(self):
equal(u, self.uuid.UUID(v))
equal(str(u), v)

def test_uuid6(self):
equal = self.assertEqual
u = self.uuid.uuid6()
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 6)

fake_nanoseconds = 1545052026752910643
fake_node_value = 93328246233727
fake_clock_seq = 5317
with mock.patch.object(self.uuid, '_generate_time_safe', None), \
mock.patch.object(self.uuid, '_last_timestamp_v6', None), \
mock.patch.object(self.uuid, 'getnode', return_value=fake_node_value), \
mock.patch('time.time_ns', return_value=fake_nanoseconds), \
mock.patch('random.getrandbits', return_value=fake_clock_seq):
u = self.uuid.uuid6()
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 6)

# time_hi time_mid time_lo
# 00011110100100000001111111001010 0111101001010101 101110010010
timestamp = 137643448267529106
equal(u.time_hi, 0b00011110100100000001111111001010)
equal(u.time_mid, 0b0111101001010101)
equal(u.time_low, 0b101110010010)
equal(u.time, timestamp)
equal(u.fields[0], u.time_hi)
equal(u.fields[1], u.time_mid)
equal(u.fields[2], u.time_hi_version)

def test_uuid7(self):
equal = self.assertEqual
u = self.uuid.uuid7()
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 7)

fake_nanoseconds = 1545052026752910643
# some fake 74 = 12 + 62 random bits speared over 76 bits
# are generated by generating a random 76-bit number, and
# split into chunks of 62 (hi) and 12 (lo) bits. It is a
rand_a = random.getrandbits(12)
rand_b = random.getrandbits(62)
fake_bytes = (rand_b << 12) | rand_a
fake_bytes = fake_bytes.to_bytes(19, byteorder='big')

with mock.patch.object(self.uuid, '_last_timestamp_v7', None), \
mock.patch('time.time_ns', return_value=fake_nanoseconds), \
mock.patch('os.urandom', return_value=fake_bytes):
u = self.uuid.uuid7()
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 7)
fake_milliseconds = (fake_nanoseconds // 1_000_000) & 0xffffffffffff
equal((u.int >> 80) & 0xffffffffffff, fake_milliseconds)
equal((u.int >> 64) & 0x0fff, rand_a)
equal(u.int & 0x3fffffffffffffff, rand_b)

def test_uuid8(self):
equal = self.assertEqual
u = self.uuid.uuid8()

equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 8)

for (_, hi, mid, lo) in product(
range(10), # repeat 10 times
[None, 0, random.getrandbits(48)],
[None, 0, random.getrandbits(12)],
[None, 0, random.getrandbits(62)],
):
u = self.uuid.uuid8(hi, mid, lo)
equal(u.variant, self.uuid.RFC_4122)
equal(u.version, 8)
if hi is not None:
equal((u.int >> 80) & 0xffffffffffff, hi)
if mid is not None:
equal((u.int >> 64) & 0xfff, mid)
if lo is not None:
equal(u.int & 0x3fffffffffffffff, lo)

@support.requires_fork()
def testIssue8621(self):
# On at least some versions of OSX self.uuid.uuid4 generates
Expand Down
0