1 r"""UUID objects (universally unique identifiers) according to RFC 4122.
2
3 This module provides immutable UUID objects (class UUID) and the functions
4 uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
5 UUIDs as specified in RFC 4122.
6
7 If all you want is a unique ID, you should probably call uuid1() or uuid4().
8 Note that uuid1() may compromise privacy since it creates a UUID containing
9 the computer's network address. uuid4() creates a random UUID.
10
11 Typical usage:
12
13 >>> import uuid
14
15 # make a UUID based on the host ID and current time
16 >>> uuid.uuid1()
17 UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
18
19 # make a UUID using an MD5 hash of a namespace UUID and a name
20 >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
21 UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
22
23 # make a random UUID
24 >>> uuid.uuid4()
25 UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
26
27 # make a UUID using a SHA-1 hash of a namespace UUID and a name
28 >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
29 UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
30
31 # make a UUID from a string of hex digits (braces and hyphens ignored)
32 >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
33
34 # convert a UUID to a string of hex digits in standard form
35 >>> str(x)
36 '00010203-0405-0607-0809-0a0b0c0d0e0f'
37
38 # get the raw 16 bytes of the UUID
39 >>> x.bytes
40 '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
41
42 # make a UUID from a 16-byte string
43 >>> uuid.UUID(bytes=x.bytes)
44 UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
45
46 This module works with Python 2.3 or higher."""
47
48 __author__ = 'Ka-Ping Yee <ping@zesty.ca>'
49 __date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
50 __version__ = '$Revision: 1.30 $'.split()[1]
51
52 RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
53 'reserved for NCS compatibility', 'specified in RFC 4122',
54 'reserved for Microsoft compatibility', 'reserved for future definition']
55
57 """Instances of the UUID class represent UUIDs as specified in RFC 4122.
58 UUID objects are immutable, hashable, and usable as dictionary keys.
59 Converting a UUID to a string with str() yields something in the form
60 '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
61 four possible forms: a similar string of hexadecimal digits, or a
62 string of 16 raw bytes as an argument named 'bytes', or a tuple of
63 six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
64 48-bit values respectively) as an argument named 'fields', or a single
65 128-bit integer as an argument named 'int'.
66
67 UUIDs have these read-only attributes:
68
69 bytes the UUID as a 16-byte string
70
71 fields a tuple of the six integer fields of the UUID,
72 which are also available as six individual attributes
73 and two derived attributes:
74
75 time_low the first 32 bits of the UUID
76 time_mid the next 16 bits of the UUID
77 time_hi_version the next 16 bits of the UUID
78 clock_seq_hi_variant the next 8 bits of the UUID
79 clock_seq_low the next 8 bits of the UUID
80 node the last 48 bits of the UUID
81
82 time the 60-bit timestamp
83 clock_seq the 14-bit sequence number
84
85 hex the UUID as a 32-character hexadecimal string
86
87 int the UUID as a 128-bit integer
88
89 urn the UUID as a URN as specified in RFC 4122
90
91 variant the UUID variant (one of the constants RESERVED_NCS,
92 RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
93
94 version the UUID version number (1 through 5, meaningful only
95 when the variant is RFC_4122)
96 """
97
98 - def __init__(self, hex=None, bytes=None, fields=None, int=None,
99 version=None):
100 """Create a UUID from either a string of 32 hexadecimal digits,
101 a string of 16 bytes as the 'bytes' argument, a tuple of six
102 integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
103 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
104 the 'fields' argument, or a single 128-bit integer as the 'int'
105 argument. When a string of hex digits is given, curly braces,
106 hyphens, and a URN prefix are all optional. For example, these
107 expressions all yield the same UUID:
108
109 UUID('{12345678-1234-5678-1234-567812345678}')
110 UUID('12345678123456781234567812345678')
111 UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
112 UUID(bytes='\x12\x34\x56\x78'*4)
113 UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
114 UUID(int=0x12345678123456781234567812345678)
115
116 Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
117 The 'version' argument is optional; if given, the resulting UUID
118 will have its variant and version number set according to RFC 4122,
119 overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
120 """
121
122 if [hex, bytes, fields, int].count(None) != 3:
123 raise TypeError('need just one of hex, bytes, fields, or int')
124 if hex is not None:
125 hex = hex.replace('urn:', '').replace('uuid:', '')
126 hex = hex.strip('{}').replace('-', '')
127 if len(hex) != 32:
128 raise ValueError('badly formed hexadecimal UUID string')
129 int = long(hex, 16)
130 if bytes is not None:
131 if len(bytes) != 16:
132 raise ValueError('bytes is not a 16-char string')
133 int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
134 if fields is not None:
135 if len(fields) != 6:
136 raise ValueError('fields is not a 6-tuple')
137 (time_low, time_mid, time_hi_version,
138 clock_seq_hi_variant, clock_seq_low, node) = fields
139 if not 0 <= time_low < 1<<32L:
140 raise ValueError('field 1 out of range (need a 32-bit value)')
141 if not 0 <= time_mid < 1<<16L:
142 raise ValueError('field 2 out of range (need a 16-bit value)')
143 if not 0 <= time_hi_version < 1<<16L:
144 raise ValueError('field 3 out of range (need a 16-bit value)')
145 if not 0 <= clock_seq_hi_variant < 1<<8L:
146 raise ValueError('field 4 out of range (need an 8-bit value)')
147 if not 0 <= clock_seq_low < 1<<8L:
148 raise ValueError('field 5 out of range (need an 8-bit value)')
149 if not 0 <= node < 1<<48L:
150 raise ValueError('field 6 out of range (need a 48-bit value)')
151 clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
152 int = ((time_low << 96L) | (time_mid << 80L) |
153 (time_hi_version << 64L) | (clock_seq << 48L) | node)
154 if int is not None:
155 if not 0 <= int < 1<<128L:
156 raise ValueError('int is out of range (need a 128-bit value)')
157 if version is not None:
158 if not 1 <= version <= 5:
159 raise ValueError('illegal version number')
160
161 int &= ~(0xc000 << 48L)
162 int |= 0x8000 << 48L
163
164 int &= ~(0xf000 << 64L)
165 int |= version << 76L
166 self.__dict__['int'] = int
167
169 if isinstance(other, UUID):
170 return cmp(self.int, other.int)
171 return NotImplemented
172
174 return hash(self.int)
175
178
180 return 'UUID(%r)' % str(self)
181
183 raise TypeError('UUID objects are immutable')
184
186 hex = '%032x' % self.int
187 return '%s-%s-%s-%s-%s' % (
188 hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
189
191 bytes = ''
192 for shift in range(0, 128, 8):
193 bytes = chr((self.int >> shift) & 0xff) + bytes
194 return bytes
195
196 bytes = property(get_bytes)
197
201
202 fields = property(get_fields)
203
205 return self.int >> 96L
206
207 time_low = property(get_time_low)
208
210 return (self.int >> 80L) & 0xffff
211
212 time_mid = property(get_time_mid)
213
215 return (self.int >> 64L) & 0xffff
216
217 time_hi_version = property(get_time_hi_version)
218
220 return (self.int >> 56L) & 0xff
221
222 clock_seq_hi_variant = property(get_clock_seq_hi_variant)
223
225 return (self.int >> 48L) & 0xff
226
227 clock_seq_low = property(get_clock_seq_low)
228
232
233 time = property(get_time)
234
238
239 clock_seq = property(get_clock_seq)
240
242 return self.int & 0xffffffffffff
243
244 node = property(get_node)
245
247 return '%032x' % self.int
248
249 hex = property(get_hex)
250
252 return 'urn:uuid:' + str(self)
253
254 urn = property(get_urn)
255
265
266 variant = property(get_variant)
267
269
270 if self.variant == RFC_4122:
271 return int((self.int >> 76L) & 0xf)
272
273 version = property(get_version)
274
276 """Get the hardware address on Unix by running ifconfig."""
277 import os
278 for dir in ['', '/sbin/', '/usr/sbin']:
279 try:
280 pipe = os.popen(os.path.join(dir, 'ifconfig'))
281 except IOError:
282 continue
283 for line in pipe:
284 words = line.lower().split()
285 for i in range(len(words)):
286 if words[i] in ['hwaddr', 'ether']:
287 return int(words[i + 1].replace(':', ''), 16)
288
290 """Get the hardware address on Windows by running ipconfig.exe."""
291 import os, re
292 dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
293 try:
294 import ctypes
295 buffer = ctypes.create_string_buffer(300)
296 ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
297 dirs.insert(0, buffer.value.decode('mbcs'))
298 except:
299 pass
300 for dir in dirs:
301 try:
302 pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
303 except IOError:
304 continue
305 for line in pipe:
306 value = line.split(':')[-1].strip().lower()
307 if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
308 return int(value.replace('-', ''), 16)
309
311 """Get the hardware address on Windows using NetBIOS calls.
312 See http://support.microsoft.com/kb/118623 for details."""
313 import win32wnet, netbios
314 ncb = netbios.NCB()
315 ncb.Command = netbios.NCBENUM
316 ncb.Buffer = adapters = netbios.LANA_ENUM()
317 adapters._pack()
318 if win32wnet.Netbios(ncb) != 0:
319 return
320 adapters._unpack()
321 for i in range(adapters.length):
322 ncb.Reset()
323 ncb.Command = netbios.NCBRESET
324 ncb.Lana_num = ord(adapters.lana[i])
325 if win32wnet.Netbios(ncb) != 0:
326 continue
327 ncb.Reset()
328 ncb.Command = netbios.NCBASTAT
329 ncb.Lana_num = ord(adapters.lana[i])
330 ncb.Callname = '*'.ljust(16)
331 ncb.Buffer = status = netbios.ADAPTER_STATUS()
332 if win32wnet.Netbios(ncb) != 0:
333 continue
334 status._unpack()
335 bytes = map(ord, status.adapter_address)
336 return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
337 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
338
339
340
341
342 _uuid_generate_random = _uuid_generate_time = _UuidCreate = None
343 try:
344 import ctypes, ctypes.util
345 _buffer = ctypes.create_string_buffer(16)
346
347
348
349 for libname in ['uuid', 'c']:
350 try:
351 lib = ctypes.CDLL(ctypes.util.find_library(libname))
352 except:
353 continue
354 if hasattr(lib, 'uuid_generate_random'):
355 _uuid_generate_random = lib.uuid_generate_random
356 if hasattr(lib, 'uuid_generate_time'):
357 _uuid_generate_time = lib.uuid_generate_time
358
359
360
361
362
363 try:
364 lib = ctypes.windll.rpcrt4
365 except:
366 lib = None
367 _UuidCreate = getattr(lib, 'UuidCreateSequential',
368 getattr(lib, 'UuidCreate', None))
369 except:
370 pass
371
376
381
383 """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
384 import random
385 return random.randrange(0, 1<<48L) | 0x010000000000L
386
387 _node = None
388
390 """Get the hardware address as a 48-bit integer. The first time this
391 runs, it may launch a separate program, which could be quite slow. If
392 all attempts to obtain the hardware address fail, we choose a random
393 48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
394
395 global _node
396 if _node is not None:
397 return _node
398
399 import sys
400 if sys.platform == 'win32':
401 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
402 else:
403 getters = [_unixdll_getnode, _ifconfig_getnode]
404
405 for getter in getters + [_random_getnode]:
406 try:
407 _node = getter()
408 except:
409 continue
410 if _node is not None:
411 return _node
412
413 -def uuid1(node=None, clock_seq=None):
414 """Generate a UUID from a host ID, sequence number, and the current time.
415 If 'node' is not given, getnode() is used to obtain the hardware
416 address. If 'clock_seq' is given, it is used as the sequence number;
417 otherwise a random 14-bit sequence number is chosen."""
418
419
420
421 if _uuid_generate_time and node is clock_seq is None:
422 _uuid_generate_time(_buffer)
423 return UUID(bytes=_buffer.raw)
424
425 import time
426 nanoseconds = int(time.time() * 1e9)
427
428
429 timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
430 if clock_seq is None:
431 import random
432 clock_seq = random.randrange(1<<14L)
433 time_low = timestamp & 0xffffffffL
434 time_mid = (timestamp >> 32L) & 0xffffL
435 time_hi_version = (timestamp >> 48L) & 0x0fffL
436 clock_seq_low = clock_seq & 0xffL
437 clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
438 if node is None:
439 node = getnode()
440 return UUID(fields=(time_low, time_mid, time_hi_version,
441 clock_seq_hi_variant, clock_seq_low, node), version=1)
442
443 -def uuid3(namespace, name):
444 """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
445 import md5
446 hash = md5.md5(namespace.bytes + name).digest()
447 return UUID(bytes=hash[:16], version=3)
448
465
466 -def uuid5(namespace, name):
467 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
468 import sha
469 hash = sha.sha(namespace.bytes + name).digest()
470 return UUID(bytes=hash[:16], version=5)
471
472
473
474 NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
475 NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
476 NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
477 NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
478