blob: 11e0da3c9bedf8f5f26b0fab223b27832910aa74 [file] [log] [blame]
Tim Peters2adc6262006-06-13 00:30:50 +00001r"""UUID objects (universally unique identifiers) according to RFC 4122.
2
3This module provides immutable UUID objects (class UUID) and the functions
4uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
5UUIDs as specified in RFC 4122.
6
7If all you want is a unique ID, you should probably call uuid1() or uuid4().
8Note that uuid1() may compromise privacy since it creates a UUID containing
9the computer's network address. uuid4() creates a random UUID.
10
11Typical 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')
Ka-Ping Yee3dbc8912006-06-19 22:49:36 +000045"""
Tim Peters2adc6262006-06-13 00:30:50 +000046
47__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
48__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
49__version__ = '$Revision: 1.30 $'.split()[1]
50
51RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
52 'reserved for NCS compatibility', 'specified in RFC 4122',
53 'reserved for Microsoft compatibility', 'reserved for future definition']
54
55class UUID(object):
56 """Instances of the UUID class represent UUIDs as specified in RFC 4122.
57 UUID objects are immutable, hashable, and usable as dictionary keys.
58 Converting a UUID to a string with str() yields something in the form
59 '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
60 four possible forms: a similar string of hexadecimal digits, or a
61 string of 16 raw bytes as an argument named 'bytes', or a tuple of
62 six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
63 48-bit values respectively) as an argument named 'fields', or a single
64 128-bit integer as an argument named 'int'.
65
66 UUIDs have these read-only attributes:
67
68 bytes the UUID as a 16-byte string
69
70 fields a tuple of the six integer fields of the UUID,
71 which are also available as six individual attributes
72 and two derived attributes:
73
74 time_low the first 32 bits of the UUID
75 time_mid the next 16 bits of the UUID
76 time_hi_version the next 16 bits of the UUID
77 clock_seq_hi_variant the next 8 bits of the UUID
78 clock_seq_low the next 8 bits of the UUID
79 node the last 48 bits of the UUID
80
81 time the 60-bit timestamp
82 clock_seq the 14-bit sequence number
83
84 hex the UUID as a 32-character hexadecimal string
85
86 int the UUID as a 128-bit integer
87
88 urn the UUID as a URN as specified in RFC 4122
89
90 variant the UUID variant (one of the constants RESERVED_NCS,
91 RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
92
93 version the UUID version number (1 through 5, meaningful only
94 when the variant is RFC_4122)
95 """
96
97 def __init__(self, hex=None, bytes=None, fields=None, int=None,
98 version=None):
99 r"""Create a UUID from either a string of 32 hexadecimal digits,
100 a string of 16 bytes as the 'bytes' argument, a tuple of six
101 integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
102 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
103 the 'fields' argument, or a single 128-bit integer as the 'int'
104 argument. When a string of hex digits is given, curly braces,
105 hyphens, and a URN prefix are all optional. For example, these
106 expressions all yield the same UUID:
107
108 UUID('{12345678-1234-5678-1234-567812345678}')
109 UUID('12345678123456781234567812345678')
110 UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
111 UUID(bytes='\x12\x34\x56\x78'*4)
112 UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
113 UUID(int=0x12345678123456781234567812345678)
114
115 Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
116 The 'version' argument is optional; if given, the resulting UUID
117 will have its variant and version number set according to RFC 4122,
118 overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
119 """
120
121 if [hex, bytes, fields, int].count(None) != 3:
122 raise TypeError('need just one of hex, bytes, fields, or int')
123 if hex is not None:
124 hex = hex.replace('urn:', '').replace('uuid:', '')
125 hex = hex.strip('{}').replace('-', '')
126 if len(hex) != 32:
127 raise ValueError('badly formed hexadecimal UUID string')
128 int = long(hex, 16)
129 if bytes is not None:
130 if len(bytes) != 16:
131 raise ValueError('bytes is not a 16-char string')
132 int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
133 if fields is not None:
134 if len(fields) != 6:
135 raise ValueError('fields is not a 6-tuple')
136 (time_low, time_mid, time_hi_version,
137 clock_seq_hi_variant, clock_seq_low, node) = fields
138 if not 0 <= time_low < 1<<32L:
139 raise ValueError('field 1 out of range (need a 32-bit value)')
140 if not 0 <= time_mid < 1<<16L:
141 raise ValueError('field 2 out of range (need a 16-bit value)')
142 if not 0 <= time_hi_version < 1<<16L:
143 raise ValueError('field 3 out of range (need a 16-bit value)')
144 if not 0 <= clock_seq_hi_variant < 1<<8L:
145 raise ValueError('field 4 out of range (need an 8-bit value)')
146 if not 0 <= clock_seq_low < 1<<8L:
147 raise ValueError('field 5 out of range (need an 8-bit value)')
148 if not 0 <= node < 1<<48L:
149 raise ValueError('field 6 out of range (need a 48-bit value)')
150 clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
151 int = ((time_low << 96L) | (time_mid << 80L) |
152 (time_hi_version << 64L) | (clock_seq << 48L) | node)
153 if int is not None:
154 if not 0 <= int < 1<<128L:
155 raise ValueError('int is out of range (need a 128-bit value)')
156 if version is not None:
157 if not 1 <= version <= 5:
158 raise ValueError('illegal version number')
159 # Set the variant to RFC 4122.
160 int &= ~(0xc000 << 48L)
161 int |= 0x8000 << 48L
162 # Set the version number.
163 int &= ~(0xf000 << 64L)
164 int |= version << 76L
165 self.__dict__['int'] = int
166
167 def __cmp__(self, other):
168 if isinstance(other, UUID):
169 return cmp(self.int, other.int)
170 return NotImplemented
171
172 def __hash__(self):
173 return hash(self.int)
174
175 def __int__(self):
176 return self.int
177
178 def __repr__(self):
179 return 'UUID(%r)' % str(self)
180
181 def __setattr__(self, name, value):
182 raise TypeError('UUID objects are immutable')
183
184 def __str__(self):
185 hex = '%032x' % self.int
186 return '%s-%s-%s-%s-%s' % (
187 hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
188
189 def get_bytes(self):
190 bytes = ''
191 for shift in range(0, 128, 8):
192 bytes = chr((self.int >> shift) & 0xff) + bytes
193 return bytes
194
195 bytes = property(get_bytes)
196
197 def get_fields(self):
198 return (self.time_low, self.time_mid, self.time_hi_version,
199 self.clock_seq_hi_variant, self.clock_seq_low, self.node)
200
201 fields = property(get_fields)
202
203 def get_time_low(self):
204 return self.int >> 96L
205
206 time_low = property(get_time_low)
207
208 def get_time_mid(self):
209 return (self.int >> 80L) & 0xffff
210
211 time_mid = property(get_time_mid)
212
213 def get_time_hi_version(self):
214 return (self.int >> 64L) & 0xffff
215
216 time_hi_version = property(get_time_hi_version)
217
218 def get_clock_seq_hi_variant(self):
219 return (self.int >> 56L) & 0xff
220
221 clock_seq_hi_variant = property(get_clock_seq_hi_variant)
222
223 def get_clock_seq_low(self):
224 return (self.int >> 48L) & 0xff
225
226 clock_seq_low = property(get_clock_seq_low)
227
228 def get_time(self):
229 return (((self.time_hi_version & 0x0fffL) << 48L) |
230 (self.time_mid << 32L) | self.time_low)
231
232 time = property(get_time)
233
234 def get_clock_seq(self):
235 return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
236 self.clock_seq_low)
237
238 clock_seq = property(get_clock_seq)
239
240 def get_node(self):
241 return self.int & 0xffffffffffff
242
243 node = property(get_node)
244
245 def get_hex(self):
246 return '%032x' % self.int
247
248 hex = property(get_hex)
249
250 def get_urn(self):
251 return 'urn:uuid:' + str(self)
252
253 urn = property(get_urn)
254
255 def get_variant(self):
256 if not self.int & (0x8000 << 48L):
257 return RESERVED_NCS
258 elif not self.int & (0x4000 << 48L):
259 return RFC_4122
260 elif not self.int & (0x2000 << 48L):
261 return RESERVED_MICROSOFT
262 else:
263 return RESERVED_FUTURE
264
265 variant = property(get_variant)
266
267 def get_version(self):
268 # The version bits are only meaningful for RFC 4122 UUIDs.
269 if self.variant == RFC_4122:
270 return int((self.int >> 76L) & 0xf)
271
272 version = property(get_version)
273
274def _ifconfig_getnode():
275 """Get the hardware address on Unix by running ifconfig."""
276 import os
277 for dir in ['', '/sbin/', '/usr/sbin']:
278 try:
Georg Brandl75a832d2006-07-27 16:08:15 +0000279 # LC_ALL to get English output, 2>/dev/null to
280 # prevent output on stderr
281 cmd = 'LC_ALL=C %s 2>/dev/null' % os.path.join(dir, 'ifconfig')
282 pipe = os.popen(cmd)
Tim Peters2adc6262006-06-13 00:30:50 +0000283 except IOError:
284 continue
285 for line in pipe:
286 words = line.lower().split()
287 for i in range(len(words)):
288 if words[i] in ['hwaddr', 'ether']:
289 return int(words[i + 1].replace(':', ''), 16)
290
291def _ipconfig_getnode():
292 """Get the hardware address on Windows by running ipconfig.exe."""
293 import os, re
294 dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
295 try:
296 import ctypes
297 buffer = ctypes.create_string_buffer(300)
298 ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
299 dirs.insert(0, buffer.value.decode('mbcs'))
300 except:
301 pass
302 for dir in dirs:
303 try:
304 pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
305 except IOError:
306 continue
307 for line in pipe:
308 value = line.split(':')[-1].strip().lower()
309 if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
310 return int(value.replace('-', ''), 16)
311
312def _netbios_getnode():
313 """Get the hardware address on Windows using NetBIOS calls.
314 See http://support.microsoft.com/kb/118623 for details."""
315 import win32wnet, netbios
316 ncb = netbios.NCB()
317 ncb.Command = netbios.NCBENUM
318 ncb.Buffer = adapters = netbios.LANA_ENUM()
319 adapters._pack()
320 if win32wnet.Netbios(ncb) != 0:
321 return
322 adapters._unpack()
323 for i in range(adapters.length):
324 ncb.Reset()
325 ncb.Command = netbios.NCBRESET
326 ncb.Lana_num = ord(adapters.lana[i])
327 if win32wnet.Netbios(ncb) != 0:
328 continue
329 ncb.Reset()
330 ncb.Command = netbios.NCBASTAT
331 ncb.Lana_num = ord(adapters.lana[i])
332 ncb.Callname = '*'.ljust(16)
333 ncb.Buffer = status = netbios.ADAPTER_STATUS()
334 if win32wnet.Netbios(ncb) != 0:
335 continue
336 status._unpack()
337 bytes = map(ord, status.adapter_address)
338 return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
339 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
340
341# Thanks to Thomas Heller for ctypes and for his help with its use here.
342
343# If ctypes is available, use it to find system routines for UUID generation.
344_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
345try:
346 import ctypes, ctypes.util
347 _buffer = ctypes.create_string_buffer(16)
348
349 # The uuid_generate_* routines are provided by libuuid on at least
350 # Linux and FreeBSD, and provided by libc on Mac OS X.
351 for libname in ['uuid', 'c']:
352 try:
353 lib = ctypes.CDLL(ctypes.util.find_library(libname))
354 except:
355 continue
356 if hasattr(lib, 'uuid_generate_random'):
357 _uuid_generate_random = lib.uuid_generate_random
358 if hasattr(lib, 'uuid_generate_time'):
359 _uuid_generate_time = lib.uuid_generate_time
360
361 # On Windows prior to 2000, UuidCreate gives a UUID containing the
362 # hardware address. On Windows 2000 and later, UuidCreate makes a
363 # random UUID and UuidCreateSequential gives a UUID containing the
364 # hardware address. These routines are provided by the RPC runtime.
365 try:
366 lib = ctypes.windll.rpcrt4
367 except:
368 lib = None
369 _UuidCreate = getattr(lib, 'UuidCreateSequential',
370 getattr(lib, 'UuidCreate', None))
371except:
372 pass
373
374def _unixdll_getnode():
375 """Get the hardware address on Unix using ctypes."""
376 _uuid_generate_time(_buffer)
377 return UUID(bytes=_buffer.raw).node
378
379def _windll_getnode():
380 """Get the hardware address on Windows using ctypes."""
381 if _UuidCreate(_buffer) == 0:
382 return UUID(bytes=_buffer.raw).node
383
384def _random_getnode():
385 """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
386 import random
387 return random.randrange(0, 1<<48L) | 0x010000000000L
388
389_node = None
390
391def getnode():
392 """Get the hardware address as a 48-bit integer. The first time this
393 runs, it may launch a separate program, which could be quite slow. If
394 all attempts to obtain the hardware address fail, we choose a random
395 48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
396
397 global _node
398 if _node is not None:
399 return _node
400
401 import sys
402 if sys.platform == 'win32':
403 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
404 else:
405 getters = [_unixdll_getnode, _ifconfig_getnode]
406
407 for getter in getters + [_random_getnode]:
408 try:
409 _node = getter()
410 except:
411 continue
412 if _node is not None:
413 return _node
414
415def uuid1(node=None, clock_seq=None):
416 """Generate a UUID from a host ID, sequence number, and the current time.
417 If 'node' is not given, getnode() is used to obtain the hardware
418 address. If 'clock_seq' is given, it is used as the sequence number;
419 otherwise a random 14-bit sequence number is chosen."""
420
421 # When the system provides a version-1 UUID generator, use it (but don't
422 # use UuidCreate here because its UUIDs don't conform to RFC 4122).
423 if _uuid_generate_time and node is clock_seq is None:
424 _uuid_generate_time(_buffer)
425 return UUID(bytes=_buffer.raw)
426
427 import time
428 nanoseconds = int(time.time() * 1e9)
429 # 0x01b21dd213814000 is the number of 100-ns intervals between the
430 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
431 timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
432 if clock_seq is None:
433 import random
434 clock_seq = random.randrange(1<<14L) # instead of stable storage
435 time_low = timestamp & 0xffffffffL
436 time_mid = (timestamp >> 32L) & 0xffffL
437 time_hi_version = (timestamp >> 48L) & 0x0fffL
438 clock_seq_low = clock_seq & 0xffL
439 clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
440 if node is None:
441 node = getnode()
442 return UUID(fields=(time_low, time_mid, time_hi_version,
443 clock_seq_hi_variant, clock_seq_low, node), version=1)
444
445def uuid3(namespace, name):
446 """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
447 import md5
448 hash = md5.md5(namespace.bytes + name).digest()
449 return UUID(bytes=hash[:16], version=3)
450
451def uuid4():
452 """Generate a random UUID."""
453
454 # When the system provides a version-4 UUID generator, use it.
455 if _uuid_generate_random:
456 _uuid_generate_random(_buffer)
457 return UUID(bytes=_buffer.raw)
458
459 # Otherwise, get randomness from urandom or the 'random' module.
460 try:
461 import os
462 return UUID(bytes=os.urandom(16), version=4)
463 except:
464 import random
465 bytes = [chr(random.randrange(256)) for i in range(16)]
466 return UUID(bytes=bytes, version=4)
467
468def uuid5(namespace, name):
469 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
470 import sha
471 hash = sha.sha(namespace.bytes + name).digest()
472 return UUID(bytes=hash[:16], version=5)
473
474# The following standard UUIDs are for use with uuid3() or uuid5().
475
476NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
477NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
478NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
479NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')