Kaydet (Commit) b1cb56ad authored tarafından Ka-Ping Yee's avatar Ka-Ping Yee

Update code and tests to support the 'bytes_le' attribute (for

little-endian byte order on Windows), and to work around clocks
with low resolution yielding duplicate UUIDs.

Anthony Baxter has approved this change.
üst d112bc79
This diff is collapsed.
...@@ -45,8 +45,6 @@ Typical usage: ...@@ -45,8 +45,6 @@ Typical usage:
""" """
__author__ = 'Ka-Ping Yee <ping@zesty.ca>' __author__ = 'Ka-Ping Yee <ping@zesty.ca>'
__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
__version__ = '$Revision: 1.30 $'.split()[1]
RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
'reserved for NCS compatibility', 'specified in RFC 4122', 'reserved for NCS compatibility', 'specified in RFC 4122',
...@@ -57,15 +55,21 @@ class UUID(object): ...@@ -57,15 +55,21 @@ class UUID(object):
UUID objects are immutable, hashable, and usable as dictionary keys. UUID objects are immutable, hashable, and usable as dictionary keys.
Converting a UUID to a string with str() yields something in the form Converting a UUID to a string with str() yields something in the form
'12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
four possible forms: a similar string of hexadecimal digits, or a five possible forms: a similar string of hexadecimal digits, or a tuple
string of 16 raw bytes as an argument named 'bytes', or a tuple of of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and 48-bit values respectively) as an argument named 'fields', or a string
48-bit values respectively) as an argument named 'fields', or a single of 16 bytes (with all the integer fields in big-endian order) as an
128-bit integer as an argument named 'int'. argument named 'bytes', or a string of 16 bytes (with the first three
fields in little-endian order) as an argument named 'bytes_le', or a
single 128-bit integer as an argument named 'int'.
UUIDs have these read-only attributes: UUIDs have these read-only attributes:
bytes the UUID as a 16-byte string bytes the UUID as a 16-byte string (containing the six
integer fields in big-endian byte order)
bytes_le the UUID as a 16-byte string (with time_low, time_mid,
and time_hi_version in little-endian byte order)
fields a tuple of the six integer fields of the UUID, fields a tuple of the six integer fields of the UUID,
which are also available as six individual attributes which are also available as six individual attributes
...@@ -94,10 +98,11 @@ class UUID(object): ...@@ -94,10 +98,11 @@ class UUID(object):
when the variant is RFC_4122) when the variant is RFC_4122)
""" """
def __init__(self, hex=None, bytes=None, fields=None, int=None, def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
version=None): int=None, version=None):
r"""Create a UUID from either a string of 32 hexadecimal digits, r"""Create a UUID from either a string of 32 hexadecimal digits,
a string of 16 bytes as the 'bytes' argument, a tuple of six a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
in little-endian order as the 'bytes_le' argument, a tuple of six
integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version, integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
the 'fields' argument, or a single 128-bit integer as the 'int' the 'fields' argument, or a single 128-bit integer as the 'int'
...@@ -109,23 +114,31 @@ class UUID(object): ...@@ -109,23 +114,31 @@ class UUID(object):
UUID('12345678123456781234567812345678') UUID('12345678123456781234567812345678')
UUID('urn:uuid:12345678-1234-5678-1234-567812345678') UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
UUID(bytes='\x12\x34\x56\x78'*4) UUID(bytes='\x12\x34\x56\x78'*4)
UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
'\x12\x34\x56\x78\x12\x34\x56\x78')
UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
UUID(int=0x12345678123456781234567812345678) UUID(int=0x12345678123456781234567812345678)
Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given. Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
The 'version' argument is optional; if given, the resulting UUID be given. The 'version' argument is optional; if given, the resulting
will have its variant and version number set according to RFC 4122, UUID will have its variant and version set according to RFC 4122,
overriding bits in the given 'hex', 'bytes', 'fields', or 'int'. overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
""" """
if [hex, bytes, fields, int].count(None) != 3: if [hex, bytes, bytes_le, fields, int].count(None) != 4:
raise TypeError('need just one of hex, bytes, fields, or int') raise TypeError('need one of hex, bytes, bytes_le, fields, or int')
if hex is not None: if hex is not None:
hex = hex.replace('urn:', '').replace('uuid:', '') hex = hex.replace('urn:', '').replace('uuid:', '')
hex = hex.strip('{}').replace('-', '') hex = hex.strip('{}').replace('-', '')
if len(hex) != 32: if len(hex) != 32:
raise ValueError('badly formed hexadecimal UUID string') raise ValueError('badly formed hexadecimal UUID string')
int = long(hex, 16) int = long(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_le[8:])
if bytes is not None: if bytes is not None:
if len(bytes) != 16: if len(bytes) != 16:
raise ValueError('bytes is not a 16-char string') raise ValueError('bytes is not a 16-char string')
...@@ -194,6 +207,13 @@ class UUID(object): ...@@ -194,6 +207,13 @@ class UUID(object):
bytes = property(get_bytes) bytes = property(get_bytes)
def get_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:])
bytes_le = property(get_bytes_le)
def get_fields(self): def get_fields(self):
return (self.time_low, self.time_mid, self.time_hi_version, return (self.time_low, self.time_mid, self.time_hi_version,
self.clock_seq_hi_variant, self.clock_seq_low, self.node) self.clock_seq_hi_variant, self.clock_seq_low, self.node)
...@@ -448,6 +468,8 @@ def getnode(): ...@@ -448,6 +468,8 @@ def getnode():
if _node is not None: if _node is not None:
return _node return _node
_last_timestamp = None
def uuid1(node=None, clock_seq=None): def uuid1(node=None, clock_seq=None):
"""Generate a UUID from a host ID, sequence number, and the current time. """Generate a UUID from a host ID, sequence number, and the current time.
If 'node' is not given, getnode() is used to obtain the hardware If 'node' is not given, getnode() is used to obtain the hardware
...@@ -460,11 +482,15 @@ def uuid1(node=None, clock_seq=None): ...@@ -460,11 +482,15 @@ def uuid1(node=None, clock_seq=None):
_uuid_generate_time(_buffer) _uuid_generate_time(_buffer)
return UUID(bytes=_buffer.raw) return UUID(bytes=_buffer.raw)
global _last_timestamp
import time import time
nanoseconds = int(time.time() * 1e9) nanoseconds = int(time.time() * 1e9)
# 0x01b21dd213814000 is the number of 100-ns intervals between the # 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. # 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) + 0x01b21dd213814000L
if timestamp == _last_timestamp:
timestamp += 1
_last_timestamp = timestamp
if clock_seq is None: if clock_seq is None:
import random import random
clock_seq = random.randrange(1<<14L) # instead of stable storage clock_seq = random.randrange(1<<14L) # instead of stable storage
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment