diff options
Diffstat (limited to 'Lib/uuid.py')
| -rw-r--r-- | Lib/uuid.py | 225 |
1 files changed, 123 insertions, 102 deletions
diff --git a/Lib/uuid.py b/Lib/uuid.py index fdd0c5c..5684ad7 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -13,7 +13,7 @@ Typical usage: >>> import uuid # make a UUID based on the host ID and current time - >>> uuid.uuid1() + >>> uuid.uuid1() # doctest: +SKIP UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') # make a UUID using an MD5 hash of a namespace UUID and a name @@ -21,7 +21,7 @@ Typical usage: UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') # make a random UUID - >>> uuid.uuid4() + >>> uuid.uuid4() # doctest: +SKIP UUID('16fd2706-8baf-433b-82eb-8c7fada847da') # make a UUID using a SHA-1 hash of a namespace UUID and a name @@ -37,7 +37,7 @@ Typical usage: # get the raw 16 bytes of the UUID >>> x.bytes - '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' + b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) @@ -50,6 +50,9 @@ RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ 'reserved for NCS compatibility', 'specified in RFC 4122', 'reserved for Microsoft compatibility', 'reserved for future definition'] +int_ = int # The built-in int type +bytes_ = bytes # The built-in bytes type + class UUID(object): """Instances of the UUID class represent UUIDs as specified in RFC 4122. UUID objects are immutable, hashable, and usable as dictionary keys. @@ -132,54 +135,84 @@ class UUID(object): hex = hex.strip('{}').replace('-', '') if len(hex) != 32: raise ValueError('badly formed hexadecimal UUID string') - int = long(hex, 16) + int = int_(hex, 16) if bytes_le is not None: if len(bytes_le) != 16: raise ValueError('bytes_le is not a 16-char string') - bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] + - bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] + + bytes = (bytes_(reversed(bytes_le[0:4])) + + bytes_(reversed(bytes_le[4:6])) + + bytes_(reversed(bytes_le[6:8])) + bytes_le[8:]) if bytes is not None: if len(bytes) != 16: raise ValueError('bytes is not a 16-char string') - int = long(('%02x'*16) % tuple(map(ord, bytes)), 16) + assert isinstance(bytes, bytes_), repr(bytes) + int = int_(('%02x'*16) % tuple(bytes), 16) if fields is not None: if len(fields) != 6: raise ValueError('fields is not a 6-tuple') (time_low, time_mid, time_hi_version, clock_seq_hi_variant, clock_seq_low, node) = fields - if not 0 <= time_low < 1<<32L: + if not 0 <= time_low < 1<<32: raise ValueError('field 1 out of range (need a 32-bit value)') - if not 0 <= time_mid < 1<<16L: + if not 0 <= time_mid < 1<<16: raise ValueError('field 2 out of range (need a 16-bit value)') - if not 0 <= time_hi_version < 1<<16L: + if not 0 <= time_hi_version < 1<<16: raise ValueError('field 3 out of range (need a 16-bit value)') - if not 0 <= clock_seq_hi_variant < 1<<8L: + if not 0 <= clock_seq_hi_variant < 1<<8: raise ValueError('field 4 out of range (need an 8-bit value)') - if not 0 <= clock_seq_low < 1<<8L: + if not 0 <= clock_seq_low < 1<<8: raise ValueError('field 5 out of range (need an 8-bit value)') - if not 0 <= node < 1<<48L: + if not 0 <= node < 1<<48: raise ValueError('field 6 out of range (need a 48-bit value)') - clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low - int = ((time_low << 96L) | (time_mid << 80L) | - (time_hi_version << 64L) | (clock_seq << 48L) | node) + clock_seq = (clock_seq_hi_variant << 8) | clock_seq_low + int = ((time_low << 96) | (time_mid << 80) | + (time_hi_version << 64) | (clock_seq << 48) | node) if int is not None: - if not 0 <= int < 1<<128L: + if not 0 <= int < 1<<128: raise ValueError('int is out of range (need a 128-bit value)') if version is not None: if not 1 <= version <= 5: raise ValueError('illegal version number') # Set the variant to RFC 4122. - int &= ~(0xc000 << 48L) - int |= 0x8000 << 48L + int &= ~(0xc000 << 48) + int |= 0x8000 << 48 # Set the version number. - int &= ~(0xf000 << 64L) - int |= version << 76L + int &= ~(0xf000 << 64) + int |= version << 76 self.__dict__['int'] = int - def __cmp__(self, other): + def __eq__(self, other): + if isinstance(other, UUID): + return self.int == other.int + return NotImplemented + + def __ne__(self, other): + if isinstance(other, UUID): + return self.int != other.int + return NotImplemented + + # Q. What's the value of being able to sort UUIDs? + # A. Use them as keys in a B-Tree or similar mapping. + + def __lt__(self, other): + if isinstance(other, UUID): + return self.int < other.int + return NotImplemented + + def __gt__(self, other): + if isinstance(other, UUID): + return self.int > other.int + return NotImplemented + + def __le__(self, other): + if isinstance(other, UUID): + return self.int <= other.int + return NotImplemented + + def __ge__(self, other): if isinstance(other, UUID): - return cmp(self.int, other.int) + return self.int >= other.int return NotImplemented def __hash__(self): @@ -199,97 +232,84 @@ class UUID(object): return '%s-%s-%s-%s-%s' % ( hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) - def get_bytes(self): - bytes = '' + @property + def bytes(self): + bytes = bytearray() for shift in range(0, 128, 8): - bytes = chr((self.int >> shift) & 0xff) + bytes - return bytes - - bytes = property(get_bytes) + bytes.insert(0, (self.int >> shift) & 0xff) + return bytes_(bytes) - def get_bytes_le(self): + @property + def bytes_le(self): bytes = self.bytes - return (bytes[3] + bytes[2] + bytes[1] + bytes[0] + - bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:]) + return (bytes_(reversed(bytes[0:4])) + + bytes_(reversed(bytes[4:6])) + + bytes_(reversed(bytes[6:8])) + + bytes[8:]) - bytes_le = property(get_bytes_le) - - def get_fields(self): + @property + def fields(self): return (self.time_low, self.time_mid, self.time_hi_version, self.clock_seq_hi_variant, self.clock_seq_low, self.node) - fields = property(get_fields) - - def get_time_low(self): - return self.int >> 96L - - time_low = property(get_time_low) - - def get_time_mid(self): - return (self.int >> 80L) & 0xffff - - time_mid = property(get_time_mid) - - def get_time_hi_version(self): - return (self.int >> 64L) & 0xffff + @property + def time_low(self): + return self.int >> 96 - time_hi_version = property(get_time_hi_version) + @property + def time_mid(self): + return (self.int >> 80) & 0xffff - def get_clock_seq_hi_variant(self): - return (self.int >> 56L) & 0xff + @property + def time_hi_version(self): + return (self.int >> 64) & 0xffff - clock_seq_hi_variant = property(get_clock_seq_hi_variant) + @property + def clock_seq_hi_variant(self): + return (self.int >> 56) & 0xff - def get_clock_seq_low(self): - return (self.int >> 48L) & 0xff + @property + def clock_seq_low(self): + return (self.int >> 48) & 0xff - clock_seq_low = property(get_clock_seq_low) + @property + def time(self): + return (((self.time_hi_version & 0x0fff) << 48) | + (self.time_mid << 32) | self.time_low) - def get_time(self): - return (((self.time_hi_version & 0x0fffL) << 48L) | - (self.time_mid << 32L) | self.time_low) - - time = property(get_time) - - def get_clock_seq(self): - return (((self.clock_seq_hi_variant & 0x3fL) << 8L) | + @property + def clock_seq(self): + return (((self.clock_seq_hi_variant & 0x3f) << 8) | self.clock_seq_low) - clock_seq = property(get_clock_seq) - - def get_node(self): + @property + def node(self): return self.int & 0xffffffffffff - node = property(get_node) - - def get_hex(self): + @property + def hex(self): return '%032x' % self.int - hex = property(get_hex) - - def get_urn(self): + @property + def urn(self): return 'urn:uuid:' + str(self) - urn = property(get_urn) - - def get_variant(self): - if not self.int & (0x8000 << 48L): + @property + def variant(self): + if not self.int & (0x8000 << 48): return RESERVED_NCS - elif not self.int & (0x4000 << 48L): + elif not self.int & (0x4000 << 48): return RFC_4122 - elif not self.int & (0x2000 << 48L): + elif not self.int & (0x2000 << 48): return RESERVED_MICROSOFT else: return RESERVED_FUTURE - variant = property(get_variant) - - def get_version(self): + @property + def version(self): # The version bits are only meaningful for RFC 4122 UUIDs. if self.variant == RFC_4122: - return int((self.int >> 76L) & 0xf) - - version = property(get_version) + return int((self.int >> 76) & 0xf) def _find_mac(command, args, hw_identifiers, get_index): import os @@ -387,12 +407,13 @@ def _netbios_getnode(): continue status._unpack() bytes = map(ord, status.adapter_address) - return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) + - (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5]) + return ((bytes[0]<<40) + (bytes[1]<<32) + (bytes[2]<<24) + + (bytes[3]<<16) + (bytes[4]<<8) + bytes[5]) # Thanks to Thomas Heller for ctypes and for his help with its use here. # If ctypes is available, use it to find system routines for UUID generation. +# XXX This makes the module non-thread-safe! _uuid_generate_random = _uuid_generate_time = _UuidCreate = None try: import ctypes, ctypes.util @@ -443,18 +464,18 @@ def _unixdll_getnode(): """Get the hardware address on Unix using ctypes.""" _buffer = ctypes.create_string_buffer(16) _uuid_generate_time(_buffer) - return UUID(bytes=_buffer.raw).node + return UUID(bytes=bytes_(_buffer.raw)).node def _windll_getnode(): """Get the hardware address on Windows using ctypes.""" _buffer = ctypes.create_string_buffer(16) if _UuidCreate(_buffer) == 0: - return UUID(bytes=_buffer.raw).node + return UUID(bytes=bytes_(_buffer.raw)).node def _random_getnode(): """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" import random - return random.randrange(0, 1<<48L) | 0x010000000000L + return random.randrange(0, 1<<48) | 0x010000000000 _node = None @@ -498,25 +519,25 @@ def uuid1(node=None, clock_seq=None): if _uuid_generate_time and node is clock_seq is None: _buffer = ctypes.create_string_buffer(16) _uuid_generate_time(_buffer) - return UUID(bytes=_buffer.raw) + return UUID(bytes=bytes_(_buffer.raw)) global _last_timestamp import time nanoseconds = int(time.time() * 1e9) # 0x01b21dd213814000 is the number of 100-ns intervals between the # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - timestamp = int(nanoseconds//100) + 0x01b21dd213814000L + timestamp = int(nanoseconds/100) + 0x01b21dd213814000 if _last_timestamp is not None and timestamp <= _last_timestamp: timestamp = _last_timestamp + 1 _last_timestamp = timestamp if clock_seq is None: import random - clock_seq = random.randrange(1<<14L) # instead of stable storage - time_low = timestamp & 0xffffffffL - time_mid = (timestamp >> 32L) & 0xffffL - time_hi_version = (timestamp >> 48L) & 0x0fffL - clock_seq_low = clock_seq & 0xffL - clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL + clock_seq = random.randrange(1<<14) # instead of stable storage + time_low = timestamp & 0xffffffff + time_mid = (timestamp >> 32) & 0xffff + time_hi_version = (timestamp >> 48) & 0x0fff + clock_seq_low = clock_seq & 0xff + clock_seq_hi_variant = (clock_seq >> 8) & 0x3f if node is None: node = getnode() return UUID(fields=(time_low, time_mid, time_hi_version, @@ -525,7 +546,7 @@ def uuid1(node=None, clock_seq=None): def uuid3(namespace, name): """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" from hashlib import md5 - hash = md5(namespace.bytes + name).digest() + hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() return UUID(bytes=hash[:16], version=3) def uuid4(): @@ -535,7 +556,7 @@ def uuid4(): if _uuid_generate_random: _buffer = ctypes.create_string_buffer(16) _uuid_generate_random(_buffer) - return UUID(bytes=_buffer.raw) + return UUID(bytes=bytes_(_buffer.raw)) # Otherwise, get randomness from urandom or the 'random' module. try: @@ -543,13 +564,13 @@ def uuid4(): return UUID(bytes=os.urandom(16), version=4) except: import random - bytes = [chr(random.randrange(256)) for i in range(16)] + bytes = bytes_(random.randrange(256) for i in range(16)) return UUID(bytes=bytes, version=4) def uuid5(namespace, name): """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" from hashlib import sha1 - hash = sha1(namespace.bytes + name).digest() + hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest() return UUID(bytes=hash[:16], version=5) # The following standard UUIDs are for use with uuid3() or uuid5(). |
