00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
00019 'reserved for NCS compatibility', 'specified in RFC 4122',
00020 'reserved for Microsoft compatibility', 'reserved for future definition']
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 class UUID(object):
00035
00036 def __init__(self, hex=None, bytes=None, fields=None, int=None,
00037 version=None):
00038 r"""Create a UUID from either a string of 32 hexadecimal digits,
00039 a string of 16 bytes as the 'bytes' argument, a tuple of six
00040 integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
00041 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
00042 the 'fields' argument, or a single 128-bit integer as the 'int'
00043 argument. When a string of hex digits is given, curly braces,
00044 hyphens, and a URN prefix are all optional. For example, these
00045 expressions all yield the same UUID:
00046
00047 UUID('{12345678-1234-5678-1234-567812345678}')
00048 UUID('12345678123456781234567812345678')
00049 UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
00050 UUID(bytes='\x12\x34\x56\x78'*4)
00051 UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
00052 UUID(int=0x12345678123456781234567812345678)
00053
00054 Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
00055 The 'version' argument is optional; if given, the resulting UUID
00056 will have its variant and version number set according to RFC 4122,
00057 overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
00058 """
00059
00060 if [hex, bytes, fields, int].count(None) != 3:
00061 raise TypeError('need just one of hex, bytes, fields, or int')
00062 if hex:
00063 hex = hex.replace('urn:', '').replace('uuid:', '')
00064 hex = hex.strip('{}').replace('-', '')
00065 if len(hex) != 32:
00066 raise ValueError('badly formed hexadecimal UUID string')
00067 int = long(hex, 16)
00068 if bytes:
00069 if len(bytes) != 16:
00070 raise ValueError('bytes is not a 16-char string')
00071 int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
00072 if fields:
00073 if len(fields) != 6:
00074 raise ValueError('fields is not a 6-tuple')
00075 (time_low, time_mid, time_hi_version,
00076 clock_seq_hi_variant, clock_seq_low, node) = fields
00077 if not 0 <= time_low < 1<<32L:
00078 raise ValueError('field 1 out of range (need a 32-bit value)')
00079 if not 0 <= time_mid < 1<<16L:
00080 raise ValueError('field 2 out of range (need a 16-bit value)')
00081 if not 0 <= time_hi_version < 1<<16L:
00082 raise ValueError('field 3 out of range (need a 16-bit value)')
00083 if not 0 <= clock_seq_hi_variant < 1<<8L:
00084 raise ValueError('field 4 out of range (need an 8-bit value)')
00085 if not 0 <= clock_seq_low < 1<<8L:
00086 raise ValueError('field 5 out of range (need an 8-bit value)')
00087 if not 0 <= node < 1<<48L:
00088 raise ValueError('field 6 out of range (need a 48-bit value)')
00089 clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
00090 int = ((time_low << 96L) | (time_mid << 80L) |
00091 (time_hi_version << 64L) | (clock_seq << 48L) | node)
00092 if int:
00093 if not 0 <= int < 1<<128L:
00094 raise ValueError('int is out of range (need a 128-bit value)')
00095 if version:
00096 if not 1 <= version <= 5:
00097 raise ValueError('illegal version number')
00098
00099 int &= ~(0xc000 << 48L)
00100 int |= 0x8000 << 48L
00101
00102 int &= ~(0xf000 << 64L)
00103 int |= version << 76L
00104 self.__dict__['int'] = int
00105
00106 def __cmp__(self, other):
00107 if isinstance(other, UUID):
00108 return cmp(self.int, other.int)
00109 return NotImplemented
00110
00111 def __hash__(self):
00112 return hash(self.int)
00113
00114 def __int__(self):
00115 return self.int
00116
00117 def __repr__(self):
00118 return 'UUID(%r)' % str(self)
00119
00120 def __setattr__(self, name, value):
00121 raise TypeError('UUID objects are immutable')
00122
00123 def __str__(self):
00124 hex = '%032x' % self.int
00125 return '%s-%s-%s-%s-%s' % (
00126 hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
00127
00128 def get_bytes(self):
00129 bytes = ''
00130 for shift in range(0, 128, 8):
00131 bytes = chr((self.int >> shift) & 0xff) + bytes
00132 return bytes
00133
00134 bytes = property(get_bytes)
00135
00136 def get_fields(self):
00137 return (self.time_low, self.time_mid, self.time_hi_version,
00138 self.clock_seq_hi_variant, self.clock_seq_low, self.node)
00139
00140 fields = property(get_fields)
00141
00142 def get_time_low(self):
00143 return self.int >> 96L
00144
00145 time_low = property(get_time_low)
00146
00147 def get_time_mid(self):
00148 return (self.int >> 80L) & 0xffff
00149
00150 time_mid = property(get_time_mid)
00151
00152 def get_time_hi_version(self):
00153 return (self.int >> 64L) & 0xffff
00154
00155 time_hi_version = property(get_time_hi_version)
00156
00157 def get_clock_seq_hi_variant(self):
00158 return (self.int >> 56L) & 0xff
00159
00160 clock_seq_hi_variant = property(get_clock_seq_hi_variant)
00161
00162 def get_clock_seq_low(self):
00163 return (self.int >> 48L) & 0xff
00164
00165 clock_seq_low = property(get_clock_seq_low)
00166
00167 def get_time(self):
00168 return (((self.time_hi_version & 0x0fffL) << 48L) |
00169 (self.time_mid << 32L) | self.time_low)
00170
00171 time = property(get_time)
00172
00173 def get_clock_seq(self):
00174 return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
00175 self.clock_seq_low)
00176
00177 clock_seq = property(get_clock_seq)
00178
00179 def get_node(self):
00180 return self.int & 0xffffffffffff
00181
00182 node = property(get_node)
00183
00184 def get_hex(self):
00185 return '%032x' % self.int
00186
00187 hex = property(get_hex)
00188
00189 def get_urn(self):
00190 return 'urn:uuid:' + str(self)
00191
00192 urn = property(get_urn)
00193
00194 def get_variant(self):
00195 if not self.int & (0x8000 << 48L):
00196 return RESERVED_NCS
00197 elif not self.int & (0x4000 << 48L):
00198 return RFC_4122
00199 elif not self.int & (0x2000 << 48L):
00200 return RESERVED_MICROSOFT
00201 else:
00202 return RESERVED_FUTURE
00203
00204 variant = property(get_variant)
00205
00206 def get_version(self):
00207
00208 if self.variant == RFC_4122:
00209 return int((self.int >> 76L) & 0xf)
00210
00211 version = property(get_version)
00212
00213 def _ifconfig_getnode():
00214 """Get the hardware address on Unix by running ifconfig."""
00215 import os
00216 dir = '/sbin/'
00217 pipe = os.popen(os.path.join(dir, 'ifconfig'))
00218
00219 for line in pipe:
00220 words = line.lower().split()
00221 for i in range(len(words)):
00222 if words[i] in ['hwaddr', 'ether']:
00223 return int(words[i + 1].replace(':', ''), 16)
00224
00225 def _ipconfig_getnode():
00226 """Get the hardware address on Windows by running ipconfig.exe."""
00227 import os, re
00228 dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
00229 try:
00230 import ctypes
00231 buffer = ctypes.create_string_buffer(300)
00232 ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
00233 dirs.insert(0, buffer.value.decode('mbcs'))
00234 except:
00235 pass
00236 for dir in dirs:
00237 try:
00238 pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
00239 except IOError:
00240 continue
00241 for line in pipe:
00242 value = line.split(':')[-1].strip().lower()
00243 if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
00244 return int(value.replace('-', ''), 16)
00245
00246 def _netbios_getnode():
00247 """Get the hardware address on Windows using NetBIOS calls.
00248 See http://support.microsoft.com/kb/118623 for details."""
00249 import win32wnet, netbios
00250 ncb = netbios.NCB()
00251 ncb.Command = netbios.NCBENUM
00252 ncb.Buffer = adapters = netbios.LANA_ENUM()
00253 adapters._pack()
00254 if win32wnet.Netbios(ncb) != 0:
00255 return
00256 adapters._unpack()
00257 for i in range(adapters.length):
00258 ncb.Reset()
00259 ncb.Command = netbios.NCBRESET
00260 ncb.Lana_num = ord(adapters.lana[i])
00261 if win32wnet.Netbios(ncb) != 0:
00262 continue
00263 ncb.Reset()
00264 ncb.Command = netbios.NCBASTAT
00265 ncb.Lana_num = ord(adapters.lana[i])
00266 ncb.Callname = '*'.ljust(16)
00267 ncb.Buffer = status = netbios.ADAPTER_STATUS()
00268 if win32wnet.Netbios(ncb) != 0:
00269 continue
00270 status._unpack()
00271 bytes = map(ord, status.adapter_address)
00272 return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
00273 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
00274
00275
00276
00277
00278 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None
00279 try:
00280 import ctypes, ctypes.util
00281 _buffer = ctypes.create_string_buffer(16)
00282
00283
00284
00285 for libname in ['uuid', 'c']:
00286 try:
00287 lib = ctypes.CDLL(ctypes.util.find_library(libname))
00288 except:
00289 continue
00290 if hasattr(lib, 'uuid_generate_random'):
00291 _uuid_generate_random = lib.uuid_generate_random
00292 if hasattr(lib, 'uuid_generate_time'):
00293 _uuid_generate_time = lib.uuid_generate_time
00294
00295
00296
00297
00298
00299 try:
00300 lib = ctypes.windll.rpcrt4
00301 except:
00302 lib = None
00303 _UuidCreate = getattr(lib, 'UuidCreateSequential',
00304 getattr(lib, 'UuidCreate', None))
00305 except:
00306 pass
00307
00308 def _unixdll_getnode():
00309 """Get the hardware address on Unix using ctypes."""
00310 _uuid_generate_time(_buffer)
00311 return UUID(bytes=_buffer.raw).node
00312
00313 def _windll_getnode():
00314 """Get the hardware address on Windows using ctypes."""
00315 if _UuidCreate(_buffer) == 0:
00316 return UUID(bytes=_buffer.raw).node
00317
00318 def _random_getnode():
00319 """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
00320 import random
00321 return random.randrange(0, 1<<48L) | 0x010000000000L
00322
00323 _node = None
00324
00325 def getnode():
00326 """Get the hardware address as a 48-bit integer. The first time this
00327 runs, it may launch a separate program, which could be quite slow. If
00328 all attempts to obtain the hardware address fail, we choose a random
00329 48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
00330
00331 global _node
00332 if _node:
00333 return _node
00334
00335 import sys
00336 if sys.platform == 'win32':
00337 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
00338 else:
00339 getters = [_unixdll_getnode, _ifconfig_getnode]
00340
00341 for getter in getters + [_random_getnode]:
00342 try:
00343 _node = getter()
00344 except:
00345 continue
00346 if _node:
00347 return _node
00348
00349 def uuid1(node=None, clock_seq=None):
00350 """Generate a UUID from a host ID, sequence number, and the current time.
00351 If 'node' is not given, getnode() is used to obtain the hardware
00352 address. If 'clock_seq' is given, it is used as the sequence number;
00353 otherwise a random 14-bit sequence number is chosen."""
00354
00355
00356
00357 if _uuid_generate_time and node is clock_seq is None:
00358 _uuid_generate_time(_buffer)
00359 return UUID(bytes=_buffer.raw)
00360
00361 import time
00362 nanoseconds = int(time.time() * 1e9)
00363
00364
00365 timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
00366 if clock_seq is None:
00367 import random
00368 clock_seq = random.randrange(1<<14L)
00369 time_low = timestamp & 0xffffffffL
00370 time_mid = (timestamp >> 32L) & 0xffffL
00371 time_hi_version = (timestamp >> 48L) & 0x0fffL
00372 clock_seq_low = clock_seq & 0xffL
00373 clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
00374 if node is None:
00375 node = getnode()
00376 return UUID(fields=(time_low, time_mid, time_hi_version,
00377 clock_seq_hi_variant, clock_seq_low, node), version=1)
00378
00379 def uuid3(namespace, name):
00380 """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
00381 import md5
00382 hash = md5.md5(namespace.bytes + name).digest()
00383 return UUID(bytes=hash[:16], version=3)
00384
00385 def uuid4():
00386 """Generate a random UUID."""
00387
00388
00389 if _uuid_generate_random:
00390 _uuid_generate_random(_buffer)
00391 return UUID(bytes=_buffer.raw)
00392
00393
00394 try:
00395 import os
00396 return UUID(bytes=os.urandom(16), version=4)
00397 except:
00398 import random
00399 bytes = [chr(random.randrange(256)) for i in range(16)]
00400 return UUID(bytes=bytes, version=4)
00401
00402 def uuid5(namespace, name):
00403 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
00404 import sha
00405 hash = sha.sha(namespace.bytes + name).digest()
00406 return UUID(bytes=hash[:16], version=5)
00407
00408
00409
00410 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
00411 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
00412 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
00413 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')