blob: 3b590e84d53181d799b28e01f2d27052c819190e [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:
279 pipe = os.popen(os.path.join(dir, 'ifconfig'))
280 except IOError:
281 continue
282 for line in pipe:
283 words = line.lower().split()
284 for i in range(len(words)):
285 if words[i] in ['hwaddr', 'ether']:
286 return int(words[i + 1].replace(':', ''), 16)
287
288def _ipconfig_getnode():
289 """Get the hardware address on Windows by running ipconfig.exe."""
290 import os, re
291 dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
292 try:
293 import ctypes
294 buffer = ctypes.create_string_buffer(300)
295 ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
296 dirs.insert(0, buffer.value.decode('mbcs'))
297 except:
298 pass
299 for dir in dirs:
300 try:
301 pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
302 except IOError:
303 continue
304 for line in pipe:
305 value = line.split(':')[-1].strip().lower()
306 if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
307 return int(value.replace('-', ''), 16)
308
309def _netbios_getnode():
310 """Get the hardware address on Windows using NetBIOS calls.
311 See http://support.microsoft.com/kb/118623 for details."""
312 import win32wnet, netbios
313 ncb = netbios.NCB()
314 ncb.Command = netbios.NCBENUM
315 ncb.Buffer = adapters = netbios.LANA_ENUM()
316 adapters._pack()
317 if win32wnet.Netbios(ncb) != 0:
318 return
319 adapters._unpack()
320 for i in range(adapters.length):
321 ncb.Reset()
322 ncb.Command = netbios.NCBRESET
323 ncb.Lana_num = ord(adapters.lana[i])
324 if win32wnet.Netbios(ncb) != 0:
325 continue
326 ncb.Reset()
327 ncb.Command = netbios.NCBASTAT
328 ncb.Lana_num = ord(adapters.lana[i])
329 ncb.Callname = '*'.ljust(16)
330 ncb.Buffer = status = netbios.ADAPTER_STATUS()
331 if win32wnet.Netbios(ncb) != 0:
332 continue
333 status._unpack()
334 bytes = map(ord, status.adapter_address)
335 return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
336 (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
337
338# Thanks to Thomas Heller for ctypes and for his help with its use here.
339
340# If ctypes is available, use it to find system routines for UUID generation.
341_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
342try:
343 import ctypes, ctypes.util
344 _buffer = ctypes.create_string_buffer(16)
345
346 # The uuid_generate_* routines are provided by libuuid on at least
347 # Linux and FreeBSD, and provided by libc on Mac OS X.
348 for libname in ['uuid', 'c']:
349 try:
350 lib = ctypes.CDLL(ctypes.util.find_library(libname))
351 except:
352 continue
353 if hasattr(lib, 'uuid_generate_random'):
354 _uuid_generate_random = lib.uuid_generate_random
355 if hasattr(lib, 'uuid_generate_time'):
356 _uuid_generate_time = lib.uuid_generate_time
357
358 # On Windows prior to 2000, UuidCreate gives a UUID containing the
359 # hardware address. On Windows 2000 and later, UuidCreate makes a
360 # random UUID and UuidCreateSequential gives a UUID containing the
361 # hardware address. These routines are provided by the RPC runtime.
362 try:
363 lib = ctypes.windll.rpcrt4
364 except:
365 lib = None
366 _UuidCreate = getattr(lib, 'UuidCreateSequential',
367 getattr(lib, 'UuidCreate', None))
368except:
369 pass
370
371def _unixdll_getnode():
372 """Get the hardware address on Unix using ctypes."""
373 _uuid_generate_time(_buffer)
374 return UUID(bytes=_buffer.raw).node
375
376def _windll_getnode():
377 """Get the hardware address on Windows using ctypes."""
378 if _UuidCreate(_buffer) == 0:
379 return UUID(bytes=_buffer.raw).node
380
381def _random_getnode():
382 """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
383 import random
384 return random.randrange(0, 1<<48L) | 0x010000000000L
385
386_node = None
387
388def getnode():
389 """Get the hardware address as a 48-bit integer. The first time this
390 runs, it may launch a separate program, which could be quite slow. If
391 all attempts to obtain the hardware address fail, we choose a random
392 48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
393
394 global _node
395 if _node is not None:
396 return _node
397
398 import sys
399 if sys.platform == 'win32':
400 getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
401 else:
402 getters = [_unixdll_getnode, _ifconfig_getnode]
403
404 for getter in getters + [_random_getnode]:
405 try:
406 _node = getter()
407 except:
408 continue
409 if _node is not None:
410 return _node
411
412def uuid1(node=None, clock_seq=None):
413 """Generate a UUID from a host ID, sequence number, and the current time.
414 If 'node' is not given, getnode() is used to obtain the hardware
415 address. If 'clock_seq' is given, it is used as the sequence number;
416 otherwise a random 14-bit sequence number is chosen."""
417
418 # When the system provides a version-1 UUID generator, use it (but don't
419 # use UuidCreate here because its UUIDs don't conform to RFC 4122).
420 if _uuid_generate_time and node is clock_seq is None:
421 _uuid_generate_time(_buffer)
422 return UUID(bytes=_buffer.raw)
423
424 import time
425 nanoseconds = int(time.time() * 1e9)
426 # 0x01b21dd213814000 is the number of 100-ns intervals between the
427 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
428 timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
429 if clock_seq is None:
430 import random
431 clock_seq = random.randrange(1<<14L) # instead of stable storage
432 time_low = timestamp & 0xffffffffL
433 time_mid = (timestamp >> 32L) & 0xffffL
434 time_hi_version = (timestamp >> 48L) & 0x0fffL
435 clock_seq_low = clock_seq & 0xffL
436 clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
437 if node is None:
438 node = getnode()
439 return UUID(fields=(time_low, time_mid, time_hi_version,
440 clock_seq_hi_variant, clock_seq_low, node), version=1)
441
442def uuid3(namespace, name):
443 """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
444 import md5
445 hash = md5.md5(namespace.bytes + name).digest()
446 return UUID(bytes=hash[:16], version=3)
447
448def uuid4():
449 """Generate a random UUID."""
450
451 # When the system provides a version-4 UUID generator, use it.
452 if _uuid_generate_random:
453 _uuid_generate_random(_buffer)
454 return UUID(bytes=_buffer.raw)
455
456 # Otherwise, get randomness from urandom or the 'random' module.
457 try:
458 import os
459 return UUID(bytes=os.urandom(16), version=4)
460 except:
461 import random
462 bytes = [chr(random.randrange(256)) for i in range(16)]
463 return UUID(bytes=bytes, version=4)
464
465def uuid5(namespace, name):
466 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
467 import sha
468 hash = sha.sha(namespace.bytes + name).digest()
469 return UUID(bytes=hash[:16], version=5)
470
471# The following standard UUIDs are for use with uuid3() or uuid5().
472
473NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
474NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
475NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
476NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')