codekingpro/portable-devtools
114k
1"""Adapted from2https://github.com/oittaa/uuid6-python/blob/main/src/uuid6/__init__.py#L953Bundled in to avoid install issues with uuid6 package4"""5 6from __future__ import annotations7 8import random9import time10import uuid11 12_last_v6_timestamp = None13 14 15class UUID(uuid.UUID):16 r"""UUID draft version objects"""17 18 __slots__ = ()19 20 def __init__(21 self,22 hex: str | None = None,23 bytes: bytes | None = None,24 bytes_le: bytes | None = None,25 fields: tuple[int, int, int, int, int, int] | None = None,26 int: int | None = None,27 version: int | None = None,28 *,29 is_safe: uuid.SafeUUID = uuid.SafeUUID.unknown,30 ) -> None:31 r"""Create a UUID."""32 33 if int is None or [hex, bytes, bytes_le, fields].count(None) != 4:34 return super().__init__(35 hex=hex,36 bytes=bytes,37 bytes_le=bytes_le,38 fields=fields,39 int=int,40 version=version,41 is_safe=is_safe,42 )43 if not 0 <= int < 1 << 128:44 raise ValueError("int is out of range (need a 128-bit value)")45 if version is not None:46 if not 6 <= version <= 8:47 raise ValueError("illegal version number")48 # Set the variant to RFC 4122.49 int &= ~(0xC000 << 48)50 int |= 0x8000 << 4851 # Set the version number.52 int &= ~(0xF000 << 64)53 int |= version << 7654 super().__init__(int=int, is_safe=is_safe)55 56 @property57 def subsec(self) -> int:58 return ((self.int >> 64) & 0x0FFF) << 8 | ((self.int >> 54) & 0xFF)59 60 @property61 def time(self) -> int:62 if self.version == 6:63 return (64 (self.time_low << 28)65 | (self.time_mid << 12)66 | (self.time_hi_version & 0x0FFF)67 )68 if self.version == 7:69 return self.int >> 8070 if self.version == 8:71 return (self.int >> 80) * 10**6 + _subsec_decode(self.subsec)72 return super().time73 74 75def _subsec_decode(value: int) -> int:76 return -(-value * 10**6 // 2**20)77 78 79def uuid6(node: int | None = None, clock_seq: int | None = None) -> UUID:80 r"""UUID version 6 is a field-compatible version of UUIDv1, reordered for81 improved DB locality. It is expected that UUIDv6 will primarily be82 used in contexts where there are existing v1 UUIDs. Systems that do83 not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.84 85 If 'node' is not given, a random 48-bit number is chosen.86 87 If 'clock_seq' is given, it is used as the sequence number;88 otherwise a random 14-bit sequence number is chosen."""89 90 global _last_v6_timestamp91 92 nanoseconds = time.time_ns()93 # 0x01b21dd213814000 is the number of 100-ns intervals between the94 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.95 timestamp = nanoseconds // 100 + 0x01B21DD21381400096 if _last_v6_timestamp is not None and timestamp <= _last_v6_timestamp:97 timestamp = _last_v6_timestamp + 198 _last_v6_timestamp = timestamp99 if clock_seq is None:100 clock_seq = random.getrandbits(14) # instead of stable storage101 if node is None:102 node = random.getrandbits(48)103 time_high_and_time_mid = (timestamp >> 12) & 0xFFFFFFFFFFFF104 time_low_and_version = timestamp & 0x0FFF105 uuid_int = time_high_and_time_mid << 80106 uuid_int |= time_low_and_version << 64107 uuid_int |= (clock_seq & 0x3FFF) << 48108 uuid_int |= node & 0xFFFFFFFFFFFF109 return UUID(int=uuid_int, version=6)110 