7ce01be6 |
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 | |
56 | class UUID(object): |
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 | r"""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 | # Set the variant to RFC 4122. |
161 | int &= ~(0xc000 << 48L) |
162 | int |= 0x8000 << 48L |
163 | # Set the version number. |
164 | int &= ~(0xf000 << 64L) |
165 | int |= version << 76L |
166 | self.__dict__['int'] = int |
167 | |
168 | def __cmp__(self, other): |
169 | if isinstance(other, UUID): |
170 | return cmp(self.int, other.int) |
171 | return NotImplemented |
172 | |
173 | def __hash__(self): |
174 | return hash(self.int) |
175 | |
176 | def __int__(self): |
177 | return self.int |
178 | |
179 | def __repr__(self): |
180 | return 'UUID(%r)' % str(self) |
181 | |
182 | def __setattr__(self, name, value): |
183 | raise TypeError('UUID objects are immutable') |
184 | |
185 | def __str__(self): |
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 | |
190 | def get_bytes(self): |
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 | |
198 | def get_fields(self): |
199 | return (self.time_low, self.time_mid, self.time_hi_version, |
200 | self.clock_seq_hi_variant, self.clock_seq_low, self.node) |
201 | |
202 | fields = property(get_fields) |
203 | |
204 | def get_time_low(self): |
205 | return self.int >> 96L |
206 | |
207 | time_low = property(get_time_low) |
208 | |
209 | def get_time_mid(self): |
210 | return (self.int >> 80L) & 0xffff |
211 | |
212 | time_mid = property(get_time_mid) |
213 | |
214 | def get_time_hi_version(self): |
215 | return (self.int >> 64L) & 0xffff |
216 | |
217 | time_hi_version = property(get_time_hi_version) |
218 | |
219 | def get_clock_seq_hi_variant(self): |
220 | return (self.int >> 56L) & 0xff |
221 | |
222 | clock_seq_hi_variant = property(get_clock_seq_hi_variant) |
223 | |
224 | def get_clock_seq_low(self): |
225 | return (self.int >> 48L) & 0xff |
226 | |
227 | clock_seq_low = property(get_clock_seq_low) |
228 | |
229 | def get_time(self): |
230 | return (((self.time_hi_version & 0x0fffL) << 48L) | |
231 | (self.time_mid << 32L) | self.time_low) |
232 | |
233 | time = property(get_time) |
234 | |
235 | def get_clock_seq(self): |
236 | return (((self.clock_seq_hi_variant & 0x3fL) << 8L) | |
237 | self.clock_seq_low) |
238 | |
239 | clock_seq = property(get_clock_seq) |
240 | |
241 | def get_node(self): |
242 | return self.int & 0xffffffffffff |
243 | |
244 | node = property(get_node) |
245 | |
246 | def get_hex(self): |
247 | return '%032x' % self.int |
248 | |
249 | hex = property(get_hex) |
250 | |
251 | def get_urn(self): |
252 | return 'urn:uuid:' + str(self) |
253 | |
254 | urn = property(get_urn) |
255 | |
256 | def get_variant(self): |
257 | if not self.int & (0x8000 << 48L): |
258 | return RESERVED_NCS |
259 | elif not self.int & (0x4000 << 48L): |
260 | return RFC_4122 |
261 | elif not self.int & (0x2000 << 48L): |
262 | return RESERVED_MICROSOFT |
263 | else: |
264 | return RESERVED_FUTURE |
265 | |
266 | variant = property(get_variant) |
267 | |
268 | def get_version(self): |
269 | # The version bits are only meaningful for RFC 4122 UUIDs. |
270 | if self.variant == RFC_4122: |
271 | return int((self.int >> 76L) & 0xf) |
272 | |
273 | version = property(get_version) |
274 | |
275 | def _ifconfig_getnode(): |
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 | |
289 | def _ipconfig_getnode(): |
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 | |
310 | def _netbios_getnode(): |
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 | # Thanks to Thomas Heller for ctypes and for his help with its use here. |
340 | |
341 | # If ctypes is available, use it to find system routines for UUID generation. |
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 | # The uuid_generate_* routines are provided by libuuid on at least |
348 | # Linux and FreeBSD, and provided by libc on Mac OS X. |
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 | # On Windows prior to 2000, UuidCreate gives a UUID containing the |
360 | # hardware address. On Windows 2000 and later, UuidCreate makes a |
361 | # random UUID and UuidCreateSequential gives a UUID containing the |
362 | # hardware address. These routines are provided by the RPC runtime. |
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 | |
372 | def _unixdll_getnode(): |
373 | """Get the hardware address on Unix using ctypes.""" |
374 | _uuid_generate_time(_buffer) |
375 | return UUID(bytes=_buffer.raw).node |
376 | |
377 | def _windll_getnode(): |
378 | """Get the hardware address on Windows using ctypes.""" |
379 | if _UuidCreate(_buffer) == 0: |
380 | return UUID(bytes=_buffer.raw).node |
381 | |
382 | def _random_getnode(): |
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 | |
389 | def getnode(): |
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 | # When the system provides a version-1 UUID generator, use it (but don't |
420 | # use UuidCreate here because its UUIDs don't conform to RFC 4122). |
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 | # 0x01b21dd213814000 is the number of 100-ns intervals between the |
428 | # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. |
429 | timestamp = int(nanoseconds/100) + 0x01b21dd213814000L |
430 | if clock_seq is None: |
431 | import random |
432 | clock_seq = random.randrange(1<<14L) # instead of stable storage |
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 | |
449 | def uuid4(): |
450 | """Generate a random UUID.""" |
451 | |
452 | # When the system provides a version-4 UUID generator, use it. |
453 | if _uuid_generate_random: |
454 | _uuid_generate_random(_buffer) |
455 | return UUID(bytes=_buffer.raw) |
456 | |
457 | # Otherwise, get randomness from urandom or the 'random' module. |
458 | try: |
459 | import os |
460 | return UUID(bytes=os.urandom(16), version=4) |
461 | except: |
462 | import random |
463 | bytes = [chr(random.randrange(256)) for i in range(16)] |
464 | return UUID(bytes=bytes, version=4) |
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 | # The following standard UUIDs are for use with uuid3() or uuid5(). |
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') |