@@ -950,6 +950,7 @@ def test_uuid7_monotonicity(self):
950950 self .uuid ,
951951 _last_timestamp_v7 = 0 ,
952952 _last_counter_v7 = 0 ,
953+ _last_counter_v7_overflow = False ,
953954 ):
954955 # 1 Jan 2023 12:34:56.123_456_789
955956 timestamp_ns = 1672533296_123_456_789 # ns precision
@@ -1024,6 +1025,7 @@ def test_uuid7_timestamp_backwards(self):
10241025 self .uuid ,
10251026 _last_timestamp_v7 = fake_last_timestamp_v7 ,
10261027 _last_counter_v7 = counter ,
1028+ _last_counter_v7_overflow = False ,
10271029 ),
10281030 mock .patch ('time.time_ns' , return_value = timestamp_ns ),
10291031 mock .patch ('os.urandom' , return_value = tail_bytes ) as urand
@@ -1049,9 +1051,13 @@ def test_uuid7_overflow_counter(self):
10491051 timestamp_ns = 1672533296_123_456_789 # ns precision
10501052 timestamp_ms , _ = divmod (timestamp_ns , 1_000_000 )
10511053
1054+ # By design, counters have their MSB set to 0 so they
1055+ # will not be able to doubly overflow (they are still
1056+ # 42-bit integers).
10521057 new_counter_hi = random .getrandbits (11 )
10531058 new_counter_lo = random .getrandbits (30 )
10541059 new_counter = (new_counter_hi << 30 ) | new_counter_lo
1060+ new_counter &= 0x1ff_ffff_ffff
10551061
10561062 tail = random .getrandbits (32 )
10571063 random_bits = (new_counter << 32 ) | tail
@@ -1063,11 +1069,14 @@ def test_uuid7_overflow_counter(self):
10631069 _last_timestamp_v7 = timestamp_ms ,
10641070 # same timestamp, but force an overflow on the counter
10651071 _last_counter_v7 = 0x3ff_ffff_ffff ,
1072+ _last_counter_v7_overflow = False ,
10661073 ),
10671074 mock .patch ('time.time_ns' , return_value = timestamp_ns ),
10681075 mock .patch ('os.urandom' , return_value = random_data ) as urand
10691076 ):
1077+ self .assertFalse (self .uuid ._last_counter_v7_overflow )
10701078 u = self .uuid .uuid7 ()
1079+ self .assertTrue (self .uuid ._last_counter_v7_overflow )
10711080 urand .assert_called_with (10 )
10721081 equal (u .variant , self .uuid .RFC_4122 )
10731082 equal (u .version , 7 )
@@ -1082,6 +1091,16 @@ def test_uuid7_overflow_counter(self):
10821091 equal ((u .int >> 32 ) & 0x3fff_ffff , new_counter_lo )
10831092 equal (u .int & 0xffff_ffff , tail )
10841093
1094+ # Reflect the global state changes from the previous UUIDv7 call.
1095+ # Check that the timestamp of future UUIDs created within
1096+ # the same logical millisecond does not advance after the
1097+ # counter overflowed.
1098+ #
1099+ # See https://github.com/python/cpython/issues/138862.
1100+ v = self .uuid .uuid7 ()
1101+ equal (v .time , unix_ts_ms )
1102+ self .assertFalse (self .uuid ._last_counter_v7_overflow )
1103+
10851104 def test_uuid8 (self ):
10861105 equal = self .assertEqual
10871106 u = self .uuid .uuid8 ()
0 commit comments