1r"""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() # doctest: +SKIP 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() # doctest: +SKIP 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 b'\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 47import os 48import sys 49 50from enum import Enum, _simple_enum 51 52 53__author__ = 'Ka-Ping Yee <ping@zesty.ca>' 54 55# The recognized platforms - known behaviors 56if sys.platform in {'win32', 'darwin', 'emscripten', 'wasi'}: 57 _AIX = _LINUX = False 58elif sys.platform == 'linux': 59 _LINUX = True 60 _AIX = False 61else: 62 import platform 63 _platform_system = platform.system() 64 _AIX = _platform_system == 'AIX' 65 _LINUX = _platform_system in ('Linux', 'Android') 66 67_MAC_DELIM = b':' 68_MAC_OMITS_LEADING_ZEROES = False 69if _AIX: 70 _MAC_DELIM = b'.' 71 _MAC_OMITS_LEADING_ZEROES = True 72 73RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ 74 'reserved for NCS compatibility', 'specified in RFC 4122', 75 'reserved for Microsoft compatibility', 'reserved for future definition'] 76 77int_ = int # The built-in int type 78bytes_ = bytes # The built-in bytes type 79 80 81@_simple_enum(Enum) 82class SafeUUID: 83 safe = 0 84 unsafe = -1 85 unknown = None 86 87 88class UUID: 89 """Instances of the UUID class represent UUIDs as specified in RFC 4122. 90 UUID objects are immutable, hashable, and usable as dictionary keys. 91 Converting a UUID to a string with str() yields something in the form 92 '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts 93 five possible forms: a similar string of hexadecimal digits, or a tuple 94 of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and 95 48-bit values respectively) as an argument named 'fields', or a string 96 of 16 bytes (with all the integer fields in big-endian order) as an 97 argument named 'bytes', or a string of 16 bytes (with the first three 98 fields in little-endian order) as an argument named 'bytes_le', or a 99 single 128-bit integer as an argument named 'int'. 100 101 UUIDs have these read-only attributes: 102 103 bytes the UUID as a 16-byte string (containing the six 104 integer fields in big-endian byte order) 105 106 bytes_le the UUID as a 16-byte string (with time_low, time_mid, 107 and time_hi_version in little-endian byte order) 108 109 fields a tuple of the six integer fields of the UUID, 110 which are also available as six individual attributes 111 and two derived attributes: 112 113 time_low the first 32 bits of the UUID 114 time_mid the next 16 bits of the UUID 115 time_hi_version the next 16 bits of the UUID 116 clock_seq_hi_variant the next 8 bits of the UUID 117 clock_seq_low the next 8 bits of the UUID 118 node the last 48 bits of the UUID 119 120 time the 60-bit timestamp 121 clock_seq the 14-bit sequence number 122 123 hex the UUID as a 32-character hexadecimal string 124 125 int the UUID as a 128-bit integer 126 127 urn the UUID as a URN as specified in RFC 4122 128 129 variant the UUID variant (one of the constants RESERVED_NCS, 130 RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) 131 132 version the UUID version number (1 through 5, meaningful only 133 when the variant is RFC_4122) 134 135 is_safe An enum indicating whether the UUID has been generated in 136 a way that is safe for multiprocessing applications, via 137 uuid_generate_time_safe(3). 138 """ 139 140 __slots__ = ('int', 'is_safe', '__weakref__') 141 142 def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, 143 int=None, version=None, 144 *, is_safe=SafeUUID.unknown): 145 r"""Create a UUID from either a string of 32 hexadecimal digits, 146 a string of 16 bytes as the 'bytes' argument, a string of 16 bytes 147 in little-endian order as the 'bytes_le' argument, a tuple of six 148 integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version, 149 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as 150 the 'fields' argument, or a single 128-bit integer as the 'int' 151 argument. When a string of hex digits is given, curly braces, 152 hyphens, and a URN prefix are all optional. For example, these 153 expressions all yield the same UUID: 154 155 UUID('{12345678-1234-5678-1234-567812345678}') 156 UUID('12345678123456781234567812345678') 157 UUID('urn:uuid:12345678-1234-5678-1234-567812345678') 158 UUID(bytes='\x12\x34\x56\x78'*4) 159 UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' + 160 '\x12\x34\x56\x78\x12\x34\x56\x78') 161 UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) 162 UUID(int=0x12345678123456781234567812345678) 163 164 Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must 165 be given. The 'version' argument is optional; if given, the resulting 166 UUID will have its variant and version set according to RFC 4122, 167 overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'. 168 169 is_safe is an enum exposed as an attribute on the instance. It 170 indicates whether the UUID has been generated in a way that is safe 171 for multiprocessing applications, via uuid_generate_time_safe(3). 172 """ 173 174 if [hex, bytes, bytes_le, fields, int].count(None) != 4: 175 raise TypeError('one of the hex, bytes, bytes_le, fields, ' 176 'or int arguments must be given') 177 if hex is not None: 178 hex = hex.replace('urn:', '').replace('uuid:', '') 179 hex = hex.strip('{}').replace('-', '') 180 if len(hex) != 32: 181 raise ValueError('badly formed hexadecimal UUID string') 182 int = int_(hex, 16) 183 if bytes_le is not None: 184 if len(bytes_le) != 16: 185 raise ValueError('bytes_le is not a 16-char string') 186 bytes = (bytes_le[4-1::-1] + bytes_le[6-1:4-1:-1] + 187 bytes_le[8-1:6-1:-1] + bytes_le[8:]) 188 if bytes is not None: 189 if len(bytes) != 16: 190 raise ValueError('bytes is not a 16-char string') 191 assert isinstance(bytes, bytes_), repr(bytes) 192 int = int_.from_bytes(bytes) # big endian 193 if fields is not None: 194 if len(fields) != 6: 195 raise ValueError('fields is not a 6-tuple') 196 (time_low, time_mid, time_hi_version, 197 clock_seq_hi_variant, clock_seq_low, node) = fields 198 if not 0 <= time_low < 1<<32: 199 raise ValueError('field 1 out of range (need a 32-bit value)') 200 if not 0 <= time_mid < 1<<16: 201 raise ValueError('field 2 out of range (need a 16-bit value)') 202 if not 0 <= time_hi_version < 1<<16: 203 raise ValueError('field 3 out of range (need a 16-bit value)') 204 if not 0 <= clock_seq_hi_variant < 1<<8: 205 raise ValueError('field 4 out of range (need an 8-bit value)') 206 if not 0 <= clock_seq_low < 1<<8: 207 raise ValueError('field 5 out of range (need an 8-bit value)') 208 if not 0 <= node < 1<<48: 209 raise ValueError('field 6 out of range (need a 48-bit value)') 210 clock_seq = (clock_seq_hi_variant << 8) | clock_seq_low 211 int = ((time_low << 96) | (time_mid << 80) | 212 (time_hi_version << 64) | (clock_seq << 48) | node) 213 if int is not None: 214 if not 0 <= int < 1<<128: 215 raise ValueError('int is out of range (need a 128-bit value)') 216 if version is not None: 217 if not 1 <= version <= 5: 218 raise ValueError('illegal version number') 219 # Set the variant to RFC 4122. 220 int &= ~(0xc000 << 48) 221 int |= 0x8000 << 48 222 # Set the version number. 223 int &= ~(0xf000 << 64) 224 int |= version << 76 225 object.__setattr__(self, 'int', int) 226 object.__setattr__(self, 'is_safe', is_safe) 227 228 def __getstate__(self): 229 d = {'int': self.int} 230 if self.is_safe != SafeUUID.unknown: 231 # is_safe is a SafeUUID instance. Return just its value, so that 232 # it can be un-pickled in older Python versions without SafeUUID. 233 d['is_safe'] = self.is_safe.value 234 return d 235 236 def __setstate__(self, state): 237 object.__setattr__(self, 'int', state['int']) 238 # is_safe was added in 3.7; it is also omitted when it is "unknown" 239 object.__setattr__(self, 'is_safe', 240 SafeUUID(state['is_safe']) 241 if 'is_safe' in state else SafeUUID.unknown) 242 243 def __eq__(self, other): 244 if isinstance(other, UUID): 245 return self.int == other.int 246 return NotImplemented 247 248 # Q. What's the value of being able to sort UUIDs? 249 # A. Use them as keys in a B-Tree or similar mapping. 250 251 def __lt__(self, other): 252 if isinstance(other, UUID): 253 return self.int < other.int 254 return NotImplemented 255 256 def __gt__(self, other): 257 if isinstance(other, UUID): 258 return self.int > other.int 259 return NotImplemented 260 261 def __le__(self, other): 262 if isinstance(other, UUID): 263 return self.int <= other.int 264 return NotImplemented 265 266 def __ge__(self, other): 267 if isinstance(other, UUID): 268 return self.int >= other.int 269 return NotImplemented 270 271 def __hash__(self): 272 return hash(self.int) 273 274 def __int__(self): 275 return self.int 276 277 def __repr__(self): 278 return '%s(%r)' % (self.__class__.__name__, str(self)) 279 280 def __setattr__(self, name, value): 281 raise TypeError('UUID objects are immutable') 282 283 def __str__(self): 284 hex = '%032x' % self.int 285 return '%s-%s-%s-%s-%s' % ( 286 hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) 287 288 @property 289 def bytes(self): 290 return self.int.to_bytes(16) # big endian 291 292 @property 293 def bytes_le(self): 294 bytes = self.bytes 295 return (bytes[4-1::-1] + bytes[6-1:4-1:-1] + bytes[8-1:6-1:-1] + 296 bytes[8:]) 297 298 @property 299 def fields(self): 300 return (self.time_low, self.time_mid, self.time_hi_version, 301 self.clock_seq_hi_variant, self.clock_seq_low, self.node) 302 303 @property 304 def time_low(self): 305 return self.int >> 96 306 307 @property 308 def time_mid(self): 309 return (self.int >> 80) & 0xffff 310 311 @property 312 def time_hi_version(self): 313 return (self.int >> 64) & 0xffff 314 315 @property 316 def clock_seq_hi_variant(self): 317 return (self.int >> 56) & 0xff 318 319 @property 320 def clock_seq_low(self): 321 return (self.int >> 48) & 0xff 322 323 @property 324 def time(self): 325 return (((self.time_hi_version & 0x0fff) << 48) | 326 (self.time_mid << 32) | self.time_low) 327 328 @property 329 def clock_seq(self): 330 return (((self.clock_seq_hi_variant & 0x3f) << 8) | 331 self.clock_seq_low) 332 333 @property 334 def node(self): 335 return self.int & 0xffffffffffff 336 337 @property 338 def hex(self): 339 return '%032x' % self.int 340 341 @property 342 def urn(self): 343 return 'urn:uuid:' + str(self) 344 345 @property 346 def variant(self): 347 if not self.int & (0x8000 << 48): 348 return RESERVED_NCS 349 elif not self.int & (0x4000 << 48): 350 return RFC_4122 351 elif not self.int & (0x2000 << 48): 352 return RESERVED_MICROSOFT 353 else: 354 return RESERVED_FUTURE 355 356 @property 357 def version(self): 358 # The version bits are only meaningful for RFC 4122 UUIDs. 359 if self.variant == RFC_4122: 360 return int((self.int >> 76) & 0xf) 361 362 363def _get_command_stdout(command, *args): 364 import io, os, shutil, subprocess 365 366 try: 367 path_dirs = os.environ.get('PATH', os.defpath).split(os.pathsep) 368 path_dirs.extend(['/sbin', '/usr/sbin']) 369 executable = shutil.which(command, path=os.pathsep.join(path_dirs)) 370 if executable is None: 371 return None 372 # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output 373 # on stderr (Note: we don't have an example where the words we search 374 # for are actually localized, but in theory some system could do so.) 375 env = dict(os.environ) 376 env['LC_ALL'] = 'C' 377 # Empty strings will be quoted by popen so we should just ommit it 378 if args != ('',): 379 command = (executable, *args) 380 else: 381 command = (executable,) 382 proc = subprocess.Popen(command, 383 stdout=subprocess.PIPE, 384 stderr=subprocess.DEVNULL, 385 env=env) 386 if not proc: 387 return None 388 stdout, stderr = proc.communicate() 389 return io.BytesIO(stdout) 390 except (OSError, subprocess.SubprocessError): 391 return None 392 393 394# For MAC (a.k.a. IEEE 802, or EUI-48) addresses, the second least significant 395# bit of the first octet signifies whether the MAC address is universally (0) 396# or locally (1) administered. Network cards from hardware manufacturers will 397# always be universally administered to guarantee global uniqueness of the MAC 398# address, but any particular machine may have other interfaces which are 399# locally administered. An example of the latter is the bridge interface to 400# the Touch Bar on MacBook Pros. 401# 402# This bit works out to be the 42nd bit counting from 1 being the least 403# significant, or 1<<41. We'll prefer universally administered MAC addresses 404# over locally administered ones since the former are globally unique, but 405# we'll return the first of the latter found if that's all the machine has. 406# 407# See https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit) 408 409def _is_universal(mac): 410 return not (mac & (1 << 41)) 411 412 413def _find_mac_near_keyword(command, args, keywords, get_word_index): 414 """Searches a command's output for a MAC address near a keyword. 415 416 Each line of words in the output is case-insensitively searched for 417 any of the given keywords. Upon a match, get_word_index is invoked 418 to pick a word from the line, given the index of the match. For 419 example, lambda i: 0 would get the first word on the line, while 420 lambda i: i - 1 would get the word preceding the keyword. 421 """ 422 stdout = _get_command_stdout(command, args) 423 if stdout is None: 424 return None 425 426 first_local_mac = None 427 for line in stdout: 428 words = line.lower().rstrip().split() 429 for i in range(len(words)): 430 if words[i] in keywords: 431 try: 432 word = words[get_word_index(i)] 433 mac = int(word.replace(_MAC_DELIM, b''), 16) 434 except (ValueError, IndexError): 435 # Virtual interfaces, such as those provided by 436 # VPNs, do not have a colon-delimited MAC address 437 # as expected, but a 16-byte HWAddr separated by 438 # dashes. These should be ignored in favor of a 439 # real MAC address 440 pass 441 else: 442 if _is_universal(mac): 443 return mac 444 first_local_mac = first_local_mac or mac 445 return first_local_mac or None 446 447 448def _parse_mac(word): 449 # Accept 'HH:HH:HH:HH:HH:HH' MAC address (ex: '52:54:00:9d:0e:67'), 450 # but reject IPv6 address (ex: 'fe80::5054:ff:fe9' or '123:2:3:4:5:6:7:8'). 451 # 452 # Virtual interfaces, such as those provided by VPNs, do not have a 453 # colon-delimited MAC address as expected, but a 16-byte HWAddr separated 454 # by dashes. These should be ignored in favor of a real MAC address 455 parts = word.split(_MAC_DELIM) 456 if len(parts) != 6: 457 return 458 if _MAC_OMITS_LEADING_ZEROES: 459 # (Only) on AIX the macaddr value given is not prefixed by 0, e.g. 460 # en0 1500 link#2 fa.bc.de.f7.62.4 110854824 0 160133733 0 0 461 # not 462 # en0 1500 link#2 fa.bc.de.f7.62.04 110854824 0 160133733 0 0 463 if not all(1 <= len(part) <= 2 for part in parts): 464 return 465 hexstr = b''.join(part.rjust(2, b'0') for part in parts) 466 else: 467 if not all(len(part) == 2 for part in parts): 468 return 469 hexstr = b''.join(parts) 470 try: 471 return int(hexstr, 16) 472 except ValueError: 473 return 474 475 476def _find_mac_under_heading(command, args, heading): 477 """Looks for a MAC address under a heading in a command's output. 478 479 The first line of words in the output is searched for the given 480 heading. Words at the same word index as the heading in subsequent 481 lines are then examined to see if they look like MAC addresses. 482 """ 483 stdout = _get_command_stdout(command, args) 484 if stdout is None: 485 return None 486 487 keywords = stdout.readline().rstrip().split() 488 try: 489 column_index = keywords.index(heading) 490 except ValueError: 491 return None 492 493 first_local_mac = None 494 for line in stdout: 495 words = line.rstrip().split() 496 try: 497 word = words[column_index] 498 except IndexError: 499 continue 500 501 mac = _parse_mac(word) 502 if mac is None: 503 continue 504 if _is_universal(mac): 505 return mac 506 if first_local_mac is None: 507 first_local_mac = mac 508 509 return first_local_mac 510 511 512# The following functions call external programs to 'get' a macaddr value to 513# be used as basis for an uuid 514def _ifconfig_getnode(): 515 """Get the hardware address on Unix by running ifconfig.""" 516 # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. 517 keywords = (b'hwaddr', b'ether', b'address:', b'lladdr') 518 for args in ('', '-a', '-av'): 519 mac = _find_mac_near_keyword('ifconfig', args, keywords, lambda i: i+1) 520 if mac: 521 return mac 522 return None 523 524def _ip_getnode(): 525 """Get the hardware address on Unix by running ip.""" 526 # This works on Linux with iproute2. 527 mac = _find_mac_near_keyword('ip', 'link', [b'link/ether'], lambda i: i+1) 528 if mac: 529 return mac 530 return None 531 532def _arp_getnode(): 533 """Get the hardware address on Unix by running arp.""" 534 import os, socket 535 if not hasattr(socket, "gethostbyname"): 536 return None 537 try: 538 ip_addr = socket.gethostbyname(socket.gethostname()) 539 except OSError: 540 return None 541 542 # Try getting the MAC addr from arp based on our IP address (Solaris). 543 mac = _find_mac_near_keyword('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1) 544 if mac: 545 return mac 546 547 # This works on OpenBSD 548 mac = _find_mac_near_keyword('arp', '-an', [os.fsencode(ip_addr)], lambda i: i+1) 549 if mac: 550 return mac 551 552 # This works on Linux, FreeBSD and NetBSD 553 mac = _find_mac_near_keyword('arp', '-an', [os.fsencode('(%s)' % ip_addr)], 554 lambda i: i+2) 555 # Return None instead of 0. 556 if mac: 557 return mac 558 return None 559 560def _lanscan_getnode(): 561 """Get the hardware address on Unix by running lanscan.""" 562 # This might work on HP-UX. 563 return _find_mac_near_keyword('lanscan', '-ai', [b'lan0'], lambda i: 0) 564 565def _netstat_getnode(): 566 """Get the hardware address on Unix by running netstat.""" 567 # This works on AIX and might work on Tru64 UNIX. 568 return _find_mac_under_heading('netstat', '-ian', b'Address') 569 570 571# Import optional C extension at toplevel, to help disabling it when testing 572try: 573 import _uuid 574 _generate_time_safe = getattr(_uuid, "generate_time_safe", None) 575 _UuidCreate = getattr(_uuid, "UuidCreate", None) 576except ImportError: 577 _uuid = None 578 _generate_time_safe = None 579 _UuidCreate = None 580 581 582def _unix_getnode(): 583 """Get the hardware address on Unix using the _uuid extension module.""" 584 if _generate_time_safe: 585 uuid_time, _ = _generate_time_safe() 586 return UUID(bytes=uuid_time).node 587 588def _windll_getnode(): 589 """Get the hardware address on Windows using the _uuid extension module.""" 590 if _UuidCreate: 591 uuid_bytes = _UuidCreate() 592 return UUID(bytes_le=uuid_bytes).node 593 594def _random_getnode(): 595 """Get a random node ID.""" 596 # RFC 4122, $4.1.6 says "For systems with no IEEE address, a randomly or 597 # pseudo-randomly generated value may be used; see Section 4.5. The 598 # multicast bit must be set in such addresses, in order that they will 599 # never conflict with addresses obtained from network cards." 600 # 601 # The "multicast bit" of a MAC address is defined to be "the least 602 # significant bit of the first octet". This works out to be the 41st bit 603 # counting from 1 being the least significant bit, or 1<<40. 604 # 605 # See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit) 606 import random 607 return random.getrandbits(48) | (1 << 40) 608 609 610# _OS_GETTERS, when known, are targeted for a specific OS or platform. 611# The order is by 'common practice' on the specified platform. 612# Note: 'posix' and 'windows' _OS_GETTERS are prefixed by a dll/dlload() method 613# which, when successful, means none of these "external" methods are called. 614# _GETTERS is (also) used by test_uuid.py to SkipUnless(), e.g., 615# @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, ...) 616if _LINUX: 617 _OS_GETTERS = [_ip_getnode, _ifconfig_getnode] 618elif sys.platform == 'darwin': 619 _OS_GETTERS = [_ifconfig_getnode, _arp_getnode, _netstat_getnode] 620elif sys.platform == 'win32': 621 # bpo-40201: _windll_getnode will always succeed, so these are not needed 622 _OS_GETTERS = [] 623elif _AIX: 624 _OS_GETTERS = [_netstat_getnode] 625else: 626 _OS_GETTERS = [_ifconfig_getnode, _ip_getnode, _arp_getnode, 627 _netstat_getnode, _lanscan_getnode] 628if os.name == 'posix': 629 _GETTERS = [_unix_getnode] + _OS_GETTERS 630elif os.name == 'nt': 631 _GETTERS = [_windll_getnode] + _OS_GETTERS 632else: 633 _GETTERS = _OS_GETTERS 634 635_node = None 636 637def getnode(): 638 """Get the hardware address as a 48-bit positive integer. 639 640 The first time this runs, it may launch a separate program, which could 641 be quite slow. If all attempts to obtain the hardware address fail, we 642 choose a random 48-bit number with its eighth bit set to 1 as recommended 643 in RFC 4122. 644 """ 645 global _node 646 if _node is not None: 647 return _node 648 649 for getter in _GETTERS + [_random_getnode]: 650 try: 651 _node = getter() 652 except: 653 continue 654 if (_node is not None) and (0 <= _node < (1 << 48)): 655 return _node 656 assert False, '_random_getnode() returned invalid value: {}'.format(_node) 657 658 659_last_timestamp = None 660 661def uuid1(node=None, clock_seq=None): 662 """Generate a UUID from a host ID, sequence number, and the current time. 663 If 'node' is not given, getnode() is used to obtain the hardware 664 address. If 'clock_seq' is given, it is used as the sequence number; 665 otherwise a random 14-bit sequence number is chosen.""" 666 667 # When the system provides a version-1 UUID generator, use it (but don't 668 # use UuidCreate here because its UUIDs don't conform to RFC 4122). 669 if _generate_time_safe is not None and node is clock_seq is None: 670 uuid_time, safely_generated = _generate_time_safe() 671 try: 672 is_safe = SafeUUID(safely_generated) 673 except ValueError: 674 is_safe = SafeUUID.unknown 675 return UUID(bytes=uuid_time, is_safe=is_safe) 676 677 global _last_timestamp 678 import time 679 nanoseconds = time.time_ns() 680 # 0x01b21dd213814000 is the number of 100-ns intervals between the 681 # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. 682 timestamp = nanoseconds // 100 + 0x01b21dd213814000 683 if _last_timestamp is not None and timestamp <= _last_timestamp: 684 timestamp = _last_timestamp + 1 685 _last_timestamp = timestamp 686 if clock_seq is None: 687 import random 688 clock_seq = random.getrandbits(14) # instead of stable storage 689 time_low = timestamp & 0xffffffff 690 time_mid = (timestamp >> 32) & 0xffff 691 time_hi_version = (timestamp >> 48) & 0x0fff 692 clock_seq_low = clock_seq & 0xff 693 clock_seq_hi_variant = (clock_seq >> 8) & 0x3f 694 if node is None: 695 node = getnode() 696 return UUID(fields=(time_low, time_mid, time_hi_version, 697 clock_seq_hi_variant, clock_seq_low, node), version=1) 698 699def uuid3(namespace, name): 700 """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" 701 if isinstance(name, str): 702 name = bytes(name, "utf-8") 703 from hashlib import md5 704 digest = md5( 705 namespace.bytes + name, 706 usedforsecurity=False 707 ).digest() 708 return UUID(bytes=digest[:16], version=3) 709 710def uuid4(): 711 """Generate a random UUID.""" 712 return UUID(bytes=os.urandom(16), version=4) 713 714def uuid5(namespace, name): 715 """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" 716 if isinstance(name, str): 717 name = bytes(name, "utf-8") 718 from hashlib import sha1 719 hash = sha1(namespace.bytes + name).digest() 720 return UUID(bytes=hash[:16], version=5) 721 722 723def main(): 724 """Run the uuid command line interface.""" 725 uuid_funcs = { 726 "uuid1": uuid1, 727 "uuid3": uuid3, 728 "uuid4": uuid4, 729 "uuid5": uuid5 730 } 731 uuid_namespace_funcs = ("uuid3", "uuid5") 732 namespaces = { 733 "@dns": NAMESPACE_DNS, 734 "@url": NAMESPACE_URL, 735 "@oid": NAMESPACE_OID, 736 "@x500": NAMESPACE_X500 737 } 738 739 import argparse 740 parser = argparse.ArgumentParser( 741 description="Generates a uuid using the selected uuid function.") 742 parser.add_argument("-u", "--uuid", choices=uuid_funcs.keys(), default="uuid4", 743 help="The function to use to generate the uuid. " 744 "By default uuid4 function is used.") 745 parser.add_argument("-n", "--namespace", 746 help="The namespace is a UUID, or '@ns' where 'ns' is a " 747 "well-known predefined UUID addressed by namespace name. " 748 "Such as @dns, @url, @oid, and @x500. " 749 "Only required for uuid3/uuid5 functions.") 750 parser.add_argument("-N", "--name", 751 help="The name used as part of generating the uuid. " 752 "Only required for uuid3/uuid5 functions.") 753 754 args = parser.parse_args() 755 uuid_func = uuid_funcs[args.uuid] 756 namespace = args.namespace 757 name = args.name 758 759 if args.uuid in uuid_namespace_funcs: 760 if not namespace or not name: 761 parser.error( 762 "Incorrect number of arguments. " 763 f"{args.uuid} requires a namespace and a name. " 764 "Run 'python -m uuid -h' for more information." 765 ) 766 namespace = namespaces[namespace] if namespace in namespaces else UUID(namespace) 767 print(uuid_func(namespace, name)) 768 else: 769 print(uuid_func()) 770 771 772# The following standard UUIDs are for use with uuid3() or uuid5(). 773 774NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') 775NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') 776NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') 777NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') 778 779if __name__ == "__main__": 780 main() 781