Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
uuid.py1008 linesDownload Raw Back to Lib
1r"""UUID objects (universally unique identifiers) according to RFC 4122/9562.2 3This module provides immutable UUID objects (class UUID) and functions for4generating UUIDs corresponding to a specific UUID version as specified in5RFC 4122/9562, e.g., uuid1() for UUID version 1, uuid3() for UUID version 3,6and so on.7 8Note that UUID version 2 is deliberately omitted as it is outside the scope9of the RFC.10 11If all you want is a unique ID, you should probably call uuid1() or uuid4().12Note that uuid1() may compromise privacy since it creates a UUID containing13the computer's network address.  uuid4() creates a random UUID.14 15Typical usage:16 17    >>> import uuid18 19    # make a UUID based on the host ID and current time20    >>> uuid.uuid1()    # doctest: +SKIP21    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')22 23    # make a UUID using an MD5 hash of a namespace UUID and a name24    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')25    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')26 27    # make a random UUID28    >>> uuid.uuid4()    # doctest: +SKIP29    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')30 31    # make a UUID using a SHA-1 hash of a namespace UUID and a name32    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')33    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')34 35    # make a UUID from a string of hex digits (braces and hyphens ignored)36    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')37 38    # convert a UUID to a string of hex digits in standard form39    >>> str(x)40    '00010203-0405-0607-0809-0a0b0c0d0e0f'41 42    # get the raw 16 bytes of the UUID43    >>> x.bytes44    b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'45 46    # make a UUID from a 16-byte string47    >>> uuid.UUID(bytes=x.bytes)48    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')49 50    # get the Nil UUID51    >>> uuid.NIL52    UUID('00000000-0000-0000-0000-000000000000')53 54    # get the Max UUID55    >>> uuid.MAX56    UUID('ffffffff-ffff-ffff-ffff-ffffffffffff')57"""58 59import os60import sys61import time62 63from enum import Enum, _simple_enum64 65 66__author__ = 'Ka-Ping Yee <ping@zesty.ca>'67 68# The recognized platforms - known behaviors69if sys.platform in {'win32', 'darwin', 'emscripten', 'wasi'}:70    _AIX = _LINUX = False71elif sys.platform == 'linux':72    _LINUX = True73    _AIX = False74else:75    import platform76    _platform_system = platform.system()77    _AIX     = _platform_system == 'AIX'78    _LINUX   = _platform_system in ('Linux', 'Android')79 80_MAC_DELIM = b':'81_MAC_OMITS_LEADING_ZEROES = False82if _AIX:83    _MAC_DELIM = b'.'84    _MAC_OMITS_LEADING_ZEROES = True85 86RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [87    'reserved for NCS compatibility', 'specified in RFC 4122',88    'reserved for Microsoft compatibility', 'reserved for future definition']89 90int_ = int      # The built-in int type91bytes_ = bytes  # The built-in bytes type92 93 94@_simple_enum(Enum)95class SafeUUID:96    safe = 097    unsafe = -198    unknown = None99 100 101_UINT_128_MAX = (1 << 128) - 1102# 128-bit mask to clear the variant and version bits of a UUID integral value103_RFC_4122_CLEARFLAGS_MASK = ~((0xf000 << 64) | (0xc000 << 48))104# RFC 4122 variant bits and version bits to activate on a UUID integral value.105_RFC_4122_VERSION_1_FLAGS = ((1 << 76) | (0x8000 << 48))106_RFC_4122_VERSION_3_FLAGS = ((3 << 76) | (0x8000 << 48))107_RFC_4122_VERSION_4_FLAGS = ((4 << 76) | (0x8000 << 48))108_RFC_4122_VERSION_5_FLAGS = ((5 << 76) | (0x8000 << 48))109_RFC_4122_VERSION_6_FLAGS = ((6 << 76) | (0x8000 << 48))110_RFC_4122_VERSION_7_FLAGS = ((7 << 76) | (0x8000 << 48))111_RFC_4122_VERSION_8_FLAGS = ((8 << 76) | (0x8000 << 48))112 113 114class UUID:115    """Instances of the UUID class represent UUIDs as specified in RFC 4122.116    UUID objects are immutable, hashable, and usable as dictionary keys.117    Converting a UUID to a string with str() yields something in the form118    '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts119    five possible forms: a similar string of hexadecimal digits, or a tuple120    of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and121    48-bit values respectively) as an argument named 'fields', or a string122    of 16 bytes (with all the integer fields in big-endian order) as an123    argument named 'bytes', or a string of 16 bytes (with the first three124    fields in little-endian order) as an argument named 'bytes_le', or a125    single 128-bit integer as an argument named 'int'.126 127    UUIDs have these read-only attributes:128 129        bytes       the UUID as a 16-byte string (containing the six130                    integer fields in big-endian byte order)131 132        bytes_le    the UUID as a 16-byte string (with time_low, time_mid,133                    and time_hi_version in little-endian byte order)134 135        fields      a tuple of the six integer fields of the UUID,136                    which are also available as six individual attributes137                    and two derived attributes. Those attributes are not138                    always relevant to all UUID versions:139 140                        The 'time_*' attributes are only relevant to version 1.141 142                        The 'clock_seq*' and 'node' attributes are only relevant143                        to versions 1 and 6.144 145                        The 'time' attribute is only relevant to versions 1, 6146                        and 7.147 148            time_low                the first 32 bits of the UUID149            time_mid                the next 16 bits of the UUID150            time_hi_version         the next 16 bits of the UUID151            clock_seq_hi_variant    the next 8 bits of the UUID152            clock_seq_low           the next 8 bits of the UUID153            node                    the last 48 bits of the UUID154 155            time                    the 60-bit timestamp for UUIDv1/v6,156                                    or the 48-bit timestamp for UUIDv7157            clock_seq               the 14-bit sequence number158 159        hex         the UUID as a 32-character hexadecimal string160 161        int         the UUID as a 128-bit integer162 163        urn         the UUID as a URN as specified in RFC 4122/9562164 165        variant     the UUID variant (one of the constants RESERVED_NCS,166                    RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)167 168        version     the UUID version number (1 through 8, meaningful only169                    when the variant is RFC_4122)170 171        is_safe     An enum indicating whether the UUID has been generated in172                    a way that is safe for multiprocessing applications, via173                    uuid_generate_time_safe(3).174    """175 176    __slots__ = ('int', 'is_safe', '__weakref__')177 178    def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,179                       int=None, version=None,180                       *, is_safe=SafeUUID.unknown):181        r"""Create a UUID from either a string of 32 hexadecimal digits,182        a string of 16 bytes as the 'bytes' argument, a string of 16 bytes183        in little-endian order as the 'bytes_le' argument, a tuple of six184        integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,185        8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as186        the 'fields' argument, or a single 128-bit integer as the 'int'187        argument.  When a string of hex digits is given, curly braces,188        hyphens, and a URN prefix are all optional.  For example, these189        expressions all yield the same UUID:190 191        UUID('{12345678-1234-5678-1234-567812345678}')192        UUID('12345678123456781234567812345678')193        UUID('urn:uuid:12345678-1234-5678-1234-567812345678')194        UUID(bytes='\x12\x34\x56\x78'*4)195        UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +196                      '\x12\x34\x56\x78\x12\x34\x56\x78')197        UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))198        UUID(int=0x12345678123456781234567812345678)199 200        Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must201        be given.  The 'version' argument is optional; if given, the resulting202        UUID will have its variant and version set according to RFC 4122,203        overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.204 205        is_safe is an enum exposed as an attribute on the instance.  It206        indicates whether the UUID has been generated in a way that is safe207        for multiprocessing applications, via uuid_generate_time_safe(3).208        """209 210        if [hex, bytes, bytes_le, fields, int].count(None) != 4:211            raise TypeError('one of the hex, bytes, bytes_le, fields, '212                            'or int arguments must be given')213        if int is not None:214            pass215        elif hex is not None:216            hex = hex.replace('urn:', '').replace('uuid:', '')217            hex = hex.strip('{}').replace('-', '')218            if len(hex) != 32:219                raise ValueError('badly formed hexadecimal UUID string')220            int = int_(hex, 16)221        elif bytes_le is not None:222            if len(bytes_le) != 16:223                raise ValueError('bytes_le is not a 16-char string')224            assert isinstance(bytes_le, bytes_), repr(bytes_le)225            bytes = (bytes_le[4-1::-1] + bytes_le[6-1:4-1:-1] +226                     bytes_le[8-1:6-1:-1] + bytes_le[8:])227            int = int_.from_bytes(bytes)  # big endian228        elif bytes is not None:229            if len(bytes) != 16:230                raise ValueError('bytes is not a 16-char string')231            assert isinstance(bytes, bytes_), repr(bytes)232            int = int_.from_bytes(bytes)  # big endian233        elif fields is not None:234            if len(fields) != 6:235                raise ValueError('fields is not a 6-tuple')236            (time_low, time_mid, time_hi_version,237             clock_seq_hi_variant, clock_seq_low, node) = fields238            if not 0 <= time_low < (1 << 32):239                raise ValueError('field 1 out of range (need a 32-bit value)')240            if not 0 <= time_mid < (1 << 16):241                raise ValueError('field 2 out of range (need a 16-bit value)')242            if not 0 <= time_hi_version < (1 << 16):243                raise ValueError('field 3 out of range (need a 16-bit value)')244            if not 0 <= clock_seq_hi_variant < (1 << 8):245                raise ValueError('field 4 out of range (need an 8-bit value)')246            if not 0 <= clock_seq_low < (1 << 8):247                raise ValueError('field 5 out of range (need an 8-bit value)')248            if not 0 <= node < (1 << 48):249                raise ValueError('field 6 out of range (need a 48-bit value)')250            clock_seq = (clock_seq_hi_variant << 8) | clock_seq_low251            int = ((time_low << 96) | (time_mid << 80) |252                   (time_hi_version << 64) | (clock_seq << 48) | node)253        if not 0 <= int <= _UINT_128_MAX:254            raise ValueError('int is out of range (need a 128-bit value)')255        if version is not None:256            if not 1 <= version <= 8:257                raise ValueError('illegal version number')258            # clear the variant and the version number bits259            int &= _RFC_4122_CLEARFLAGS_MASK260            # Set the variant to RFC 4122/9562.261            int |= 0x8000_0000_0000_0000  # (0x8000 << 48)262            # Set the version number.263            int |= version << 76264        object.__setattr__(self, 'int', int)265        object.__setattr__(self, 'is_safe', is_safe)266 267    @classmethod268    def _from_int(cls, value):269        """Create a UUID from an integer *value*. Internal use only."""270        assert 0 <= value <= _UINT_128_MAX, repr(value)271        self = object.__new__(cls)272        object.__setattr__(self, 'int', value)273        object.__setattr__(self, 'is_safe', SafeUUID.unknown)274        return self275 276    def __getstate__(self):277        d = {'int': self.int}278        if self.is_safe != SafeUUID.unknown:279            # is_safe is a SafeUUID instance.  Return just its value, so that280            # it can be un-pickled in older Python versions without SafeUUID.281            d['is_safe'] = self.is_safe.value282        return d283 284    def __setstate__(self, state):285        object.__setattr__(self, 'int', state['int'])286        # is_safe was added in 3.7; it is also omitted when it is "unknown"287        object.__setattr__(self, 'is_safe',288                           SafeUUID(state['is_safe'])289                           if 'is_safe' in state else SafeUUID.unknown)290 291    def __eq__(self, other):292        if isinstance(other, UUID):293            return self.int == other.int294        return NotImplemented295 296    # Q. What's the value of being able to sort UUIDs?297    # A. Use them as keys in a B-Tree or similar mapping.298 299    def __lt__(self, other):300        if isinstance(other, UUID):301            return self.int < other.int302        return NotImplemented303 304    def __gt__(self, other):305        if isinstance(other, UUID):306            return self.int > other.int307        return NotImplemented308 309    def __le__(self, other):310        if isinstance(other, UUID):311            return self.int <= other.int312        return NotImplemented313 314    def __ge__(self, other):315        if isinstance(other, UUID):316            return self.int >= other.int317        return NotImplemented318 319    def __hash__(self):320        return hash(self.int)321 322    def __int__(self):323        return self.int324 325    def __repr__(self):326        return '%s(%r)' % (self.__class__.__name__, str(self))327 328    def __setattr__(self, name, value):329        raise TypeError('UUID objects are immutable')330 331    def __str__(self):332        x = self.hex333        return f'{x[:8]}-{x[8:12]}-{x[12:16]}-{x[16:20]}-{x[20:]}'334 335    @property336    def bytes(self):337        return self.int.to_bytes(16)  # big endian338 339    @property340    def bytes_le(self):341        bytes = self.bytes342        return (bytes[4-1::-1] + bytes[6-1:4-1:-1] + bytes[8-1:6-1:-1] +343                bytes[8:])344 345    @property346    def fields(self):347        return (self.time_low, self.time_mid, self.time_hi_version,348                self.clock_seq_hi_variant, self.clock_seq_low, self.node)349 350    @property351    def time_low(self):352        return self.int >> 96353 354    @property355    def time_mid(self):356        return (self.int >> 80) & 0xffff357 358    @property359    def time_hi_version(self):360        return (self.int >> 64) & 0xffff361 362    @property363    def clock_seq_hi_variant(self):364        return (self.int >> 56) & 0xff365 366    @property367    def clock_seq_low(self):368        return (self.int >> 48) & 0xff369 370    @property371    def time(self):372        if self.version == 6:373            # time_hi (32) | time_mid (16) | ver (4) | time_lo (12) | ... (64)374            time_hi = self.int >> 96375            time_lo = (self.int >> 64) & 0x0fff376            return time_hi << 28 | (self.time_mid << 12) | time_lo377        elif self.version == 7:378            # unix_ts_ms (48) | ... (80)379            return self.int >> 80380        else:381            # time_lo (32) | time_mid (16) | ver (4) | time_hi (12) | ... (64)382            #383            # For compatibility purposes, we do not warn or raise when the384            # version is not 1 (timestamp is irrelevant to other versions).385            time_hi = (self.int >> 64) & 0x0fff386            time_lo = self.int >> 96387            return time_hi << 48 | (self.time_mid << 32) | time_lo388 389    @property390    def clock_seq(self):391        return (((self.clock_seq_hi_variant & 0x3f) << 8) |392                self.clock_seq_low)393 394    @property395    def node(self):396        return self.int & 0xffffffffffff397 398    @property399    def hex(self):400        return self.bytes.hex()401 402    @property403    def urn(self):404        return 'urn:uuid:' + str(self)405 406    @property407    def variant(self):408        if not self.int & (0x8000 << 48):409            return RESERVED_NCS410        elif not self.int & (0x4000 << 48):411            return RFC_4122412        elif not self.int & (0x2000 << 48):413            return RESERVED_MICROSOFT414        else:415            return RESERVED_FUTURE416 417    @property418    def version(self):419        # The version bits are only meaningful for RFC 4122/9562 UUIDs.420        if self.variant == RFC_4122:421            return int((self.int >> 76) & 0xf)422 423 424def _get_command_stdout(command, *args):425    import io, os, shutil, subprocess426 427    try:428        path_dirs = os.environ.get('PATH', os.defpath).split(os.pathsep)429        path_dirs.extend(['/sbin', '/usr/sbin'])430        executable = shutil.which(command, path=os.pathsep.join(path_dirs))431        if executable is None:432            return None433        # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output434        # on stderr (Note: we don't have an example where the words we search435        # for are actually localized, but in theory some system could do so.)436        env = dict(os.environ)437        env['LC_ALL'] = 'C'438        # Empty strings will be quoted by popen so we should just omit it439        if args != ('',):440            command = (executable, *args)441        else:442            command = (executable,)443        proc = subprocess.Popen(command,444                                stdout=subprocess.PIPE,445                                stderr=subprocess.DEVNULL,446                                env=env)447        if not proc:448            return None449        stdout, stderr = proc.communicate()450        return io.BytesIO(stdout)451    except (OSError, subprocess.SubprocessError):452        return None453 454 455# For MAC (a.k.a. IEEE 802, or EUI-48) addresses, the second least significant456# bit of the first octet signifies whether the MAC address is universally (0)457# or locally (1) administered.  Network cards from hardware manufacturers will458# always be universally administered to guarantee global uniqueness of the MAC459# address, but any particular machine may have other interfaces which are460# locally administered.  An example of the latter is the bridge interface to461# the Touch Bar on MacBook Pros.462#463# This bit works out to be the 42nd bit counting from 1 being the least464# significant, or 1<<41.  We'll prefer universally administered MAC addresses465# over locally administered ones since the former are globally unique, but466# we'll return the first of the latter found if that's all the machine has.467#468# See https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local_(U/L_bit)469 470def _is_universal(mac):471    return not (mac & (1 << 41))472 473 474def _find_mac_near_keyword(command, args, keywords, get_word_index):475    """Searches a command's output for a MAC address near a keyword.476 477    Each line of words in the output is case-insensitively searched for478    any of the given keywords.  Upon a match, get_word_index is invoked479    to pick a word from the line, given the index of the match.  For480    example, lambda i: 0 would get the first word on the line, while481    lambda i: i - 1 would get the word preceding the keyword.482    """483    stdout = _get_command_stdout(command, args)484    if stdout is None:485        return None486 487    first_local_mac = None488    for line in stdout:489        words = line.lower().rstrip().split()490        for i in range(len(words)):491            if words[i] in keywords:492                try:493                    word = words[get_word_index(i)]494                    mac = int(word.replace(_MAC_DELIM, b''), 16)495                except (ValueError, IndexError):496                    # Virtual interfaces, such as those provided by497                    # VPNs, do not have a colon-delimited MAC address498                    # as expected, but a 16-byte HWAddr separated by499                    # dashes. These should be ignored in favor of a500                    # real MAC address501                    pass502                else:503                    if _is_universal(mac):504                        return mac505                    first_local_mac = first_local_mac or mac506    return first_local_mac or None507 508 509def _parse_mac(word):510    # Accept 'HH:HH:HH:HH:HH:HH' MAC address (ex: '52:54:00:9d:0e:67'),511    # but reject IPv6 address (ex: 'fe80::5054:ff:fe9' or '123:2:3:4:5:6:7:8').512    #513    # Virtual interfaces, such as those provided by VPNs, do not have a514    # colon-delimited MAC address as expected, but a 16-byte HWAddr separated515    # by dashes. These should be ignored in favor of a real MAC address516    parts = word.split(_MAC_DELIM)517    if len(parts) != 6:518        return519    if _MAC_OMITS_LEADING_ZEROES:520        # (Only) on AIX the macaddr value given is not prefixed by 0, e.g.521        # en0   1500  link#2      fa.bc.de.f7.62.4 110854824     0 160133733     0     0522        # not523        # en0   1500  link#2      fa.bc.de.f7.62.04 110854824     0 160133733     0     0524        if not all(1 <= len(part) <= 2 for part in parts):525            return526        hexstr = b''.join(part.rjust(2, b'0') for part in parts)527    else:528        if not all(len(part) == 2 for part in parts):529            return530        hexstr = b''.join(parts)531    try:532        return int(hexstr, 16)533    except ValueError:534        return535 536 537def _find_mac_under_heading(command, args, heading):538    """Looks for a MAC address under a heading in a command's output.539 540    The first line of words in the output is searched for the given541    heading. Words at the same word index as the heading in subsequent542    lines are then examined to see if they look like MAC addresses.543    """544    stdout = _get_command_stdout(command, args)545    if stdout is None:546        return None547 548    keywords = stdout.readline().rstrip().split()549    try:550        column_index = keywords.index(heading)551    except ValueError:552        return None553 554    first_local_mac = None555    for line in stdout:556        words = line.rstrip().split()557        try:558            word = words[column_index]559        except IndexError:560            continue561 562        mac = _parse_mac(word)563        if mac is None:564            continue565        if _is_universal(mac):566            return mac567        if first_local_mac is None:568            first_local_mac = mac569 570    return first_local_mac571 572 573# The following functions call external programs to 'get' a macaddr value to574# be used as basis for an uuid575def _ifconfig_getnode():576    """Get the hardware address on Unix by running ifconfig."""577    # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.578    keywords = (b'hwaddr', b'ether', b'address:', b'lladdr')579    for args in ('', '-a', '-av'):580        mac = _find_mac_near_keyword('ifconfig', args, keywords, lambda i: i+1)581        if mac:582            return mac583    return None584 585def _ip_getnode():586    """Get the hardware address on Unix by running ip."""587    # This works on Linux with iproute2.588    mac = _find_mac_near_keyword('ip', 'link', [b'link/ether'], lambda i: i+1)589    if mac:590        return mac591    return None592 593def _arp_getnode():594    """Get the hardware address on Unix by running arp."""595    import os, socket596    if not hasattr(socket, "gethostbyname"):597        return None598    try:599        ip_addr = socket.gethostbyname(socket.gethostname())600    except OSError:601        return None602 603    # Try getting the MAC addr from arp based on our IP address (Solaris).604    mac = _find_mac_near_keyword('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1)605    if mac:606        return mac607 608    # This works on OpenBSD609    mac = _find_mac_near_keyword('arp', '-an', [os.fsencode(ip_addr)], lambda i: i+1)610    if mac:611        return mac612 613    # This works on Linux, FreeBSD and NetBSD614    mac = _find_mac_near_keyword('arp', '-an', [os.fsencode('(%s)' % ip_addr)],615                    lambda i: i+2)616    # Return None instead of 0.617    if mac:618        return mac619    return None620 621def _lanscan_getnode():622    """Get the hardware address on Unix by running lanscan."""623    # This might work on HP-UX.624    return _find_mac_near_keyword('lanscan', '-ai', [b'lan0'], lambda i: 0)625 626def _netstat_getnode():627    """Get the hardware address on Unix by running netstat."""628    # This works on AIX and might work on Tru64 UNIX.629    return _find_mac_under_heading('netstat', '-ian', b'Address')630 631 632# Import optional C extension at toplevel, to help disabling it when testing633try:634    import _uuid635    _generate_time_safe = getattr(_uuid, "generate_time_safe", None)636    _has_stable_extractable_node = _uuid.has_stable_extractable_node637    _UuidCreate = getattr(_uuid, "UuidCreate", None)638except ImportError:639    _uuid = None640    _generate_time_safe = None641    _has_stable_extractable_node = False642    _UuidCreate = None643 644 645def _unix_getnode():646    """Get the hardware address on Unix using the _uuid extension module."""647    if _generate_time_safe and _has_stable_extractable_node:648        uuid_time, _ = _generate_time_safe()649        return UUID(bytes=uuid_time).node650 651def _windll_getnode():652    """Get the hardware address on Windows using the _uuid extension module."""653    if _UuidCreate and _has_stable_extractable_node:654        uuid_bytes = _UuidCreate()655        return UUID(bytes_le=uuid_bytes).node656 657def _random_getnode():658    """Get a random node ID."""659    # RFC 9562, §6.10-3 says that660    #661    #   Implementations MAY elect to obtain a 48-bit cryptographic-quality662    #   random number as per Section 6.9 to use as the Node ID. [...] [and]663    #   implementations MUST set the least significant bit of the first octet664    #   of the Node ID to 1. This bit is the unicast or multicast bit, which665    #   will never be set in IEEE 802 addresses obtained from network cards.666    #667    # The "multicast bit" of a MAC address is defined to be "the least668    # significant bit of the first octet".  This works out to be the 41st bit669    # counting from 1 being the least significant bit, or 1<<40.670    #671    # See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit)672    return int.from_bytes(os.urandom(6)) | (1 << 40)673 674 675# _OS_GETTERS, when known, are targeted for a specific OS or platform.676# The order is by 'common practice' on the specified platform.677# Note: 'posix' and 'windows' _OS_GETTERS are prefixed by a dll/dlload() method678# which, when successful, means none of these "external" methods are called.679# _GETTERS is (also) used by test_uuid.py to SkipUnless(), e.g.,680#     @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, ...)681if _LINUX:682    _OS_GETTERS = [_ip_getnode, _ifconfig_getnode]683elif sys.platform == 'darwin':684    _OS_GETTERS = [_ifconfig_getnode, _arp_getnode, _netstat_getnode]685elif sys.platform == 'win32':686    # bpo-40201: _windll_getnode will always succeed, so these are not needed687    _OS_GETTERS = []688elif _AIX:689    _OS_GETTERS = [_netstat_getnode]690else:691    _OS_GETTERS = [_ifconfig_getnode, _ip_getnode, _arp_getnode,692                   _netstat_getnode, _lanscan_getnode]693if os.name == 'posix':694    _GETTERS = [_unix_getnode] + _OS_GETTERS695elif os.name == 'nt':696    _GETTERS = [_windll_getnode] + _OS_GETTERS697else:698    _GETTERS = _OS_GETTERS699 700_node = None701 702def getnode():703    """Get the hardware address as a 48-bit positive integer.704 705    The first time this runs, it may launch a separate program, which could706    be quite slow.  If all attempts to obtain the hardware address fail, we707    choose a random 48-bit number with its eighth bit set to 1 as recommended708    in RFC 4122.709    """710    global _node711    if _node is not None:712        return _node713 714    for getter in _GETTERS + [_random_getnode]:715        try:716            _node = getter()717        except:718            continue719        if (_node is not None) and (0 <= _node < (1 << 48)):720            return _node721    assert False, '_random_getnode() returned invalid value: {}'.format(_node)722 723 724_last_timestamp = None725 726def uuid1(node=None, clock_seq=None):727    """Generate a UUID from a host ID, sequence number, and the current time.728    If 'node' is not given, getnode() is used to obtain the hardware729    address.  If 'clock_seq' is given, it is used as the sequence number;730    otherwise a random 14-bit sequence number is chosen."""731 732    # When the system provides a version-1 UUID generator, use it (but don't733    # use UuidCreate here because its UUIDs don't conform to RFC 4122).734    if _generate_time_safe is not None and node is clock_seq is None:735        uuid_time, safely_generated = _generate_time_safe()736        try:737            is_safe = SafeUUID(safely_generated)738        except ValueError:739            is_safe = SafeUUID.unknown740        return UUID(bytes=uuid_time, is_safe=is_safe)741 742    global _last_timestamp743    nanoseconds = time.time_ns()744    # 0x01b21dd213814000 is the number of 100-ns intervals between the745    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.746    timestamp = nanoseconds // 100 + 0x01b21dd213814000747    if _last_timestamp is not None and timestamp <= _last_timestamp:748        timestamp = _last_timestamp + 1749    _last_timestamp = timestamp750    if clock_seq is None:751        import random752        clock_seq = random.getrandbits(14) # instead of stable storage753    time_low = timestamp & 0xffffffff754    time_mid = (timestamp >> 32) & 0xffff755    time_hi_version = (timestamp >> 48) & 0x0fff756    clock_seq_low = clock_seq & 0xff757    clock_seq_hi_variant = (clock_seq >> 8) & 0x3f758    if node is None:759        node = getnode()760    return UUID(fields=(time_low, time_mid, time_hi_version,761                        clock_seq_hi_variant, clock_seq_low, node), version=1)762 763def uuid3(namespace, name):764    """Generate a UUID from the MD5 hash of a namespace UUID and a name."""765    if isinstance(name, str):766        name = bytes(name, "utf-8")767    import hashlib768    h = hashlib.md5(namespace.bytes + name, usedforsecurity=False)769    int_uuid_3 = int.from_bytes(h.digest())770    int_uuid_3 &= _RFC_4122_CLEARFLAGS_MASK771    int_uuid_3 |= _RFC_4122_VERSION_3_FLAGS772    return UUID._from_int(int_uuid_3)773 774def uuid4():775    """Generate a random UUID."""776    int_uuid_4 = int.from_bytes(os.urandom(16))777    int_uuid_4 &= _RFC_4122_CLEARFLAGS_MASK778    int_uuid_4 |= _RFC_4122_VERSION_4_FLAGS779    return UUID._from_int(int_uuid_4)780 781def uuid5(namespace, name):782    """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""783    if isinstance(name, str):784        name = bytes(name, "utf-8")785    import hashlib786    h = hashlib.sha1(namespace.bytes + name, usedforsecurity=False)787    int_uuid_5 = int.from_bytes(h.digest()[:16])788    int_uuid_5 &= _RFC_4122_CLEARFLAGS_MASK789    int_uuid_5 |= _RFC_4122_VERSION_5_FLAGS790    return UUID._from_int(int_uuid_5)791 792 793_last_timestamp_v6 = None794 795def uuid6(node=None, clock_seq=None):796    """Similar to :func:`uuid1` but where fields are ordered differently797    for improved DB locality.798 799    More precisely, given a 60-bit timestamp value as specified for UUIDv1,800    for UUIDv6 the first 48 most significant bits are stored first, followed801    by the 4-bit version (same position), followed by the remaining 12 bits802    of the original 60-bit timestamp.803    """804    global _last_timestamp_v6805    import time806    nanoseconds = time.time_ns()807    # 0x01b21dd213814000 is the number of 100-ns intervals between the808    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.809    timestamp = nanoseconds // 100 + 0x01b21dd213814000810    if _last_timestamp_v6 is not None and timestamp <= _last_timestamp_v6:811        timestamp = _last_timestamp_v6 + 1812    _last_timestamp_v6 = timestamp813    if clock_seq is None:814        import random815        clock_seq = random.getrandbits(14)  # instead of stable storage816    time_hi_and_mid = (timestamp >> 12) & 0xffff_ffff_ffff817    time_lo = timestamp & 0x0fff  # keep 12 bits and clear version bits818    clock_s = clock_seq & 0x3fff  # keep 14 bits and clear variant bits819    if node is None:820        node = getnode()821    # --- 32 + 16 ---   -- 4 --   -- 12 --  -- 2 --   -- 14 ---    48822    # time_hi_and_mid | version | time_lo | variant | clock_seq | node823    int_uuid_6 = time_hi_and_mid << 80824    int_uuid_6 |= time_lo << 64825    int_uuid_6 |= clock_s << 48826    int_uuid_6 |= node & 0xffff_ffff_ffff827    # by construction, the variant and version bits are already cleared828    int_uuid_6 |= _RFC_4122_VERSION_6_FLAGS829    return UUID._from_int(int_uuid_6)830 831 832_last_timestamp_v7 = None833_last_counter_v7 = 0  # 42-bit counter834 835def _uuid7_get_counter_and_tail():836    rand = int.from_bytes(os.urandom(10))837    # 42-bit counter with MSB set to 0838    counter = (rand >> 32) & 0x1ff_ffff_ffff839    # 32-bit random data840    tail = rand & 0xffff_ffff841    return counter, tail842 843 844def uuid7():845    """Generate a UUID from a Unix timestamp in milliseconds and random bits.846 847    UUIDv7 objects feature monotonicity within a millisecond.848    """849    # --- 48 ---   -- 4 --   --- 12 ---   -- 2 --   --- 30 ---   - 32 -850    # unix_ts_ms | version | counter_hi | variant | counter_lo | random851    #852    # 'counter = counter_hi | counter_lo' is a 42-bit counter constructed853    # with Method 1 of RFC 9562, §6.2, and its MSB is set to 0.854    #855    # 'random' is a 32-bit random value regenerated for every new UUID.856    #857    # If multiple UUIDs are generated within the same millisecond, the LSB858    # of 'counter' is incremented by 1. When overflowing, the timestamp is859    # advanced and the counter is reset to a random 42-bit integer with MSB860    # set to 0.861 862    global _last_timestamp_v7863    global _last_counter_v7864 865    nanoseconds = time.time_ns()866    timestamp_ms = nanoseconds // 1_000_000867 868    if _last_timestamp_v7 is None or timestamp_ms > _last_timestamp_v7:869        counter, tail = _uuid7_get_counter_and_tail()870    else:871        if timestamp_ms < _last_timestamp_v7:872            timestamp_ms = _last_timestamp_v7 + 1873        # advance the 42-bit counter874        counter = _last_counter_v7 + 1875        if counter > 0x3ff_ffff_ffff:876            # advance the 48-bit timestamp877            timestamp_ms += 1878            counter, tail = _uuid7_get_counter_and_tail()879        else:880            # 32-bit random data881            tail = int.from_bytes(os.urandom(4))882 883    unix_ts_ms = timestamp_ms & 0xffff_ffff_ffff884    counter_msbs = counter >> 30885    # keep 12 counter's MSBs and clear variant bits886    counter_hi = counter_msbs & 0x0fff887    # keep 30 counter's LSBs and clear version bits888    counter_lo = counter & 0x3fff_ffff889    # ensure that the tail is always a 32-bit integer (by construction,890    # it is already the case, but future interfaces may allow the user891    # to specify the random tail)892    tail &= 0xffff_ffff893 894    int_uuid_7 = unix_ts_ms << 80895    int_uuid_7 |= counter_hi << 64896    int_uuid_7 |= counter_lo << 32897    int_uuid_7 |= tail898    # by construction, the variant and version bits are already cleared899    int_uuid_7 |= _RFC_4122_VERSION_7_FLAGS900    res = UUID._from_int(int_uuid_7)901 902    # defer global update until all computations are done903    _last_timestamp_v7 = timestamp_ms904    _last_counter_v7 = counter905    return res906 907 908def uuid8(a=None, b=None, c=None):909    """Generate a UUID from three custom blocks.910 911    * 'a' is the first 48-bit chunk of the UUID (octets 0-5);912    * 'b' is the mid 12-bit chunk (octets 6-7);913    * 'c' is the last 62-bit chunk (octets 8-15).914 915    When a value is not specified, a pseudo-random value is generated.916    """917    if a is None:918        import random919        a = random.getrandbits(48)920    if b is None:921        import random922        b = random.getrandbits(12)923    if c is None:924        import random925        c = random.getrandbits(62)926    int_uuid_8 = (a & 0xffff_ffff_ffff) << 80927    int_uuid_8 |= (b & 0xfff) << 64928    int_uuid_8 |= c & 0x3fff_ffff_ffff_ffff929    # by construction, the variant and version bits are already cleared930    int_uuid_8 |= _RFC_4122_VERSION_8_FLAGS931    return UUID._from_int(int_uuid_8)932 933 934def main():935    """Run the uuid command line interface."""936    uuid_funcs = {937        "uuid1": uuid1,938        "uuid3": uuid3,939        "uuid4": uuid4,940        "uuid5": uuid5,941        "uuid6": uuid6,942        "uuid7": uuid7,943        "uuid8": uuid8,944    }945    uuid_namespace_funcs = ("uuid3", "uuid5")946    namespaces = {947        "@dns": NAMESPACE_DNS,948        "@url": NAMESPACE_URL,949        "@oid": NAMESPACE_OID,950        "@x500": NAMESPACE_X500951    }952 953    import argparse954    parser = argparse.ArgumentParser(955        formatter_class=argparse.ArgumentDefaultsHelpFormatter,956        description="Generate a UUID using the selected UUID function.",957        color=True,958    )959    parser.add_argument("-u", "--uuid",960                        choices=uuid_funcs.keys(),961                        default="uuid4",962                        help="function to generate the UUID")963    parser.add_argument("-n", "--namespace",964                        choices=["any UUID", *namespaces.keys()],965                        help="uuid3/uuid5 only: "966                        "a UUID, or a well-known predefined UUID addressed "967                        "by namespace name")968    parser.add_argument("-N", "--name",969                        help="uuid3/uuid5 only: "970                        "name used as part of generating the UUID")971    parser.add_argument("-C", "--count", metavar="NUM", type=int, default=1,972                        help="generate NUM fresh UUIDs")973 974    args = parser.parse_args()975    uuid_func = uuid_funcs[args.uuid]976    namespace = args.namespace977    name = args.name978 979    if args.uuid in uuid_namespace_funcs:980        if not namespace or not name:981            parser.error(982                "Incorrect number of arguments. "983                f"{args.uuid} requires a namespace and a name. "984                "Run 'python -m uuid -h' for more information."985            )986        namespace = namespaces[namespace] if namespace in namespaces else UUID(namespace)987        for _ in range(args.count):988            print(uuid_func(namespace, name))989    else:990        for _ in range(args.count):991            print(uuid_func())992 993 994# The following standard UUIDs are for use with uuid3() or uuid5().995 996NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')997NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')998NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')999NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')1000 1001# RFC 9562 Sections 5.9 and 5.10 define the special Nil and Max UUID formats.1002 1003NIL = UUID('00000000-0000-0000-0000-000000000000')1004MAX = UUID('ffffffff-ffff-ffff-ffff-ffffffffffff')1005 1006if __name__ == "__main__":1007    main()1008 
codekingpro/portable-devtools · Team Ai