Skip to content

Commit a0c0729

Browse files
author
Jaap Roes
authored
Merge pull request #9 from leukeleu/HIDP-8-uuidv7
Add uuid7 function
2 parents 7e91496 + cd85a79 commit a0c0729

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

backend/hidp/compat/__init__.py

Whitespace-only changes.

backend/hidp/compat/uuid7.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
Generate time-sortable UUIDs (version 7)
3+
4+
Provides a `uuid7` function that's either directly imported from Python's `uuid` module
5+
(if it's available) or an implementation based on a pull request to add it to CPython.
6+
"""
7+
8+
import uuid
9+
10+
if hasattr(uuid, "uuid7"):
11+
# Future Python versions will (hopefully) have this function built-in
12+
# Issue: https://github.com/python/cpython/issues/89083
13+
uuid7 = uuid.uuid7
14+
else:
15+
# Taken from the CPython pull request:
16+
# * https://github.com/python/cpython/pull/120650
17+
# * Commit (2024-06-19T07:39:18Z)
18+
# * https://github.com/python/cpython/blob/295d82d513717adb96d9faab7e255dbedb237d88/Lib/uuid.py#L770-L790
19+
# Modifications:
20+
# * Added noqa comments to supress ruff warnings
21+
# * Manually set the variant and version bits.
22+
23+
_last_timestamp_v7 = None
24+
25+
def uuid7():
26+
"""Generate a UUID from a Unix timestamp in milliseconds and random bits."""
27+
global _last_timestamp_v7 # noqa: PLW0603 (global-statement)
28+
import os # noqa: PLC0415 (import-outside-toplevel)
29+
import time # noqa: PLC0415 (import-outside-toplevel)
30+
31+
nanoseconds = time.time_ns()
32+
timestamp_ms = nanoseconds // 10**6 # may be improved
33+
if _last_timestamp_v7 is not None and timestamp_ms <= _last_timestamp_v7:
34+
timestamp_ms = _last_timestamp_v7 + 1
35+
_last_timestamp_v7 = timestamp_ms
36+
int_uuid_7 = (timestamp_ms & 0xFFFFFFFFFFFF) << 80
37+
# Ideally, we would have 'rand_a' = first 12 bits of 'rand'
38+
# and 'rand_b' = lowest 62 bits, but it is easier to test
39+
# when we pick 'rand_a' from the lowest bits of 'rand' and
40+
# 'rand_b' from the next 62 bits, ignoring the 6 first bits
41+
# of 'rand'.
42+
rand = int.from_bytes(os.urandom(10)) # 80 random bits (ignore 6 first)
43+
int_uuid_7 |= (rand & 0x0FFF) << 64 # rand_a
44+
int_uuid_7 |= (rand >> 12) & 0x3FFFFFFFFFFFFFFF # rand_b
45+
46+
# Manually set the variant and version bits, to avoid a
47+
# `ValueError('illegal version number')` when calling the UUID constructor
48+
# with `version` set to 7.
49+
# Copied from UUID.__init__, hardcoded version:
50+
# https://github.com/python/cpython/blob/a86e6255c371e14cab8680dee979a7393b339ce5/Lib/uuid.py#L219-L224
51+
52+
# Set the variant to RFC 4122.
53+
int_uuid_7 &= ~(0xC000 << 48)
54+
int_uuid_7 |= 0x8000 << 48
55+
# Set the version number to 7.
56+
int_uuid_7 &= ~(0xF000 << 64)
57+
int_uuid_7 |= 7 << 76
58+
59+
return uuid.UUID(int=int_uuid_7)

0 commit comments

Comments
 (0)