@@ -760,6 +760,14 @@ def uuid5(namespace, name):
760760_last_timestamp_v7 = None
761761_last_counter_v7 = 0 # 42-bit counter
762762
763+ def _uuid7_get_counter_and_tail ():
764+ rand = int .from_bytes (os .urandom (10 ))
765+ # 42-bit counter with MSB set to 0
766+ counter = (rand >> 32 ) & 0x1ff_ffff_ffff
767+ # 32-bit random data
768+ tail = rand & 0xffff_ffff
769+ return counter , tail
770+
763771def uuid7 ():
764772 """Generate a UUID from a Unix timestamp in milliseconds and random bits.
765773
@@ -778,14 +786,6 @@ def uuid7():
778786 # advanced and the counter is reset to a random 42-bit integer with MSB
779787 # set to 0.
780788
781- def get_counter_and_tail ():
782- rand = int .from_bytes (os .urandom (10 ))
783- # 42-bit counter with MSB set to 0
784- counter = (rand >> 32 ) & 0x1ff_ffff_ffff
785- # 32-bit random data
786- tail = rand & 0xffff_ffff
787- return counter , tail
788-
789789 global _last_timestamp_v7
790790 global _last_counter_v7
791791
@@ -794,33 +794,40 @@ def get_counter_and_tail():
794794 timestamp_ms = nanoseconds // 1_000_000
795795
796796 if _last_timestamp_v7 is None or timestamp_ms > _last_timestamp_v7 :
797- counter , tail = get_counter_and_tail ()
797+ counter , tail = _uuid7_get_counter_and_tail ()
798798 else :
799799 if timestamp_ms < _last_timestamp_v7 :
800800 timestamp_ms = _last_timestamp_v7 + 1
801801 # advance the 42-bit counter
802802 counter = _last_counter_v7 + 1
803803 if counter > 0x3ff_ffff_ffff :
804- timestamp_ms += 1 # advance the 48-bit timestamp
805- counter , tail = get_counter_and_tail ()
804+ # advance the 48-bit timestamp
805+ timestamp_ms += 1
806+ counter , tail = _uuid7_get_counter_and_tail ()
806807 else :
808+ # 32-bit random data
807809 tail = int .from_bytes (os .urandom (4 ))
808810
809- _last_timestamp_v7 = timestamp_ms
810- _last_counter_v7 = counter
811-
812811 unix_ts_ms = timestamp_ms & 0xffff_ffff_ffff
813812 counter_msbs = counter >> 30
814- counter_hi = counter_msbs & 0x0fff # keep 12 bits and clear variant bits
815- counter_lo = counter & 0x3fff_ffff # keep 30 bits and clear version bits
813+ # keep 12 counter's MSBs and clear variant bits
814+ counter_hi = counter_msbs & 0x0fff
815+ # keep 30 counter's LSBs and clear version bits
816+ counter_lo = counter & 0x3fff_ffff
817+ # ensure that the fail is always a 32-bit integer
818+ tail &= 0xffff_ffff
816819
817820 int_uuid_7 = unix_ts_ms << 80
818821 int_uuid_7 |= counter_hi << 64
819822 int_uuid_7 |= counter_lo << 32
820- int_uuid_7 |= tail & 0xffff_ffff
823+ int_uuid_7 |= tail
821824 # by construction, the variant and version bits are already cleared
822825 int_uuid_7 |= _RFC_4122_VERSION_7_FLAGS
823- return UUID ._from_int (int_uuid_7 )
826+ res = UUID ._from_int (int_uuid_7 )
827+ # defer global update until all computations are done
828+ _last_timestamp_v7 = timestamp_ms
829+ _last_counter_v7 = counter
830+ return res
824831
825832def uuid8 (a = None , b = None , c = None ):
826833 """Generate a UUID from three custom blocks.
0 commit comments