From 16a048a552982107883a24db55cef0afdcc6e451 Mon Sep 17 00:00:00 2001 From: Narawit Rakket Date: Wed, 1 Dec 2021 19:53:11 +0700 Subject: [PATCH 1/2] feat(uuid): update uuid to version 3.9.9 --- Lib/uuid.py | 499 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 306 insertions(+), 193 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 200c800b3..5ae0a3e5f 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -45,9 +45,28 @@ Typical usage: """ import os +import sys + +from enum import Enum + __author__ = 'Ka-Ping Yee ' +# The recognized platforms - known behaviors +if sys.platform in ('win32', 'darwin'): + _AIX = _LINUX = False +else: + import platform + _platform_system = platform.system() + _AIX = _platform_system == 'AIX' + _LINUX = _platform_system == 'Linux' + +_MAC_DELIM = b':' +_MAC_OMITS_LEADING_ZEROES = False +if _AIX: + _MAC_DELIM = b'.' + _MAC_OMITS_LEADING_ZEROES = True + RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ 'reserved for NCS compatibility', 'specified in RFC 4122', 'reserved for Microsoft compatibility', 'reserved for future definition'] @@ -55,7 +74,14 @@ RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ int_ = int # The built-in int type bytes_ = bytes # The built-in bytes type -class UUID(object): + +class SafeUUID(Enum): + safe = 0 + unsafe = -1 + unknown = None + + +class UUID: """Instances of the UUID class represent UUIDs as specified in RFC 4122. UUID objects are immutable, hashable, and usable as dictionary keys. Converting a UUID to a string with str() yields something in the form @@ -101,10 +127,17 @@ class UUID(object): version the UUID version number (1 through 5, meaningful only when the variant is RFC_4122) + + is_safe An enum indicating whether the UUID has been generated in + a way that is safe for multiprocessing applications, via + uuid_generate_time_safe(3). """ + __slots__ = ('int', 'is_safe', '__weakref__') + def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None, - int=None, version=None): + int=None, version=None, + *, is_safe=SafeUUID.unknown): r"""Create a UUID from either a string of 32 hexadecimal digits, a string of 16 bytes as the 'bytes' argument, a string of 16 bytes in little-endian order as the 'bytes_le' argument, a tuple of six @@ -128,6 +161,10 @@ class UUID(object): be given. The 'version' argument is optional; if given, the resulting UUID will have its variant and version set according to RFC 4122, overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'. + + is_safe is an enum exposed as an attribute on the instance. It + indicates whether the UUID has been generated in a way that is safe + for multiprocessing applications, via uuid_generate_time_safe(3). """ if [hex, bytes, bytes_le, fields, int].count(None) != 4: @@ -181,7 +218,23 @@ class UUID(object): # Set the version number. int &= ~(0xf000 << 64) int |= version << 76 - self.__dict__['int'] = int + object.__setattr__(self, 'int', int) + object.__setattr__(self, 'is_safe', is_safe) + + def __getstate__(self): + d = {'int': self.int} + if self.is_safe != SafeUUID.unknown: + # is_safe is a SafeUUID instance. Return just its value, so that + # it can be un-pickled in older Python versions without SafeUUID. + d['is_safe'] = self.is_safe.value + return d + + def __setstate__(self, state): + object.__setattr__(self, 'int', state['int']) + # is_safe was added in 3.7; it is also omitted when it is "unknown" + object.__setattr__(self, 'is_safe', + SafeUUID(state['is_safe']) + if 'is_safe' in state else SafeUUID.unknown) def __eq__(self, other): if isinstance(other, UUID): @@ -302,64 +355,170 @@ class UUID(object): if self.variant == RFC_4122: return int((self.int >> 76) & 0xf) -def _popen(command, *args): - import os, shutil, subprocess - executable = shutil.which(command) - if executable is None: - path = os.pathsep.join(('/sbin', '/usr/sbin')) - executable = shutil.which(command, path=path) + +def _get_command_stdout(command, *args): + import io, os, shutil, subprocess + + try: + path_dirs = os.environ.get('PATH', os.defpath).split(os.pathsep) + path_dirs.extend(['/sbin', '/usr/sbin']) + executable = shutil.which(command, path=os.pathsep.join(path_dirs)) if executable is None: return None - # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output - # on stderr (Note: we don't have an example where the words we search - # for are actually localized, but in theory some system could do so.) - env = dict(os.environ) - env['LC_ALL'] = 'C' - proc = subprocess.Popen((executable,) + args, - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, - env=env) - return proc - -def _find_mac(command, args, hw_identifiers, get_index): - try: - proc = _popen(command, *args.split()) + # LC_ALL=C to ensure English output, stderr=DEVNULL to prevent output + # on stderr (Note: we don't have an example where the words we search + # for are actually localized, but in theory some system could do so.) + env = dict(os.environ) + env['LC_ALL'] = 'C' + proc = subprocess.Popen((executable,) + args, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + env=env) if not proc: - return - with proc: - for line in proc.stdout: - words = line.lower().rstrip().split() - for i in range(len(words)): - if words[i] in hw_identifiers: - try: - word = words[get_index(i)] - mac = int(word.replace(b':', b''), 16) - if mac: - return mac - except (ValueError, IndexError): - # Virtual interfaces, such as those provided by - # VPNs, do not have a colon-delimited MAC address - # as expected, but a 16-byte HWAddr separated by - # dashes. These should be ignored in favor of a - # real MAC address - pass - except OSError: - pass + return None + stdout, stderr = proc.communicate() + return io.BytesIO(stdout) + except (OSError, subprocess.SubprocessError): + return None + +# For MAC (a.k.a. IEEE 802, or EUI-48) addresses, the second least significant +# bit of the first octet signifies whether the MAC address is universally (0) +# or locally (1) administered. Network cards from hardware manufacturers will +# always be universally administered to guarantee global uniqueness of the MAC +# address, but any particular machine may have other interfaces which are +# locally administered. An example of the latter is the bridge interface to +# the Touch Bar on MacBook Pros. +# +# This bit works out to be the 42nd bit counting from 1 being the least +# significant, or 1<<41. We'll prefer universally administered MAC addresses +# over locally administered ones since the former are globally unique, but +# we'll return the first of the latter found if that's all the machine has. +# +# See https://en.wikipedia.org/wiki/MAC_address#Universal_vs._local + +def _is_universal(mac): + return not (mac & (1 << 41)) + + +def _find_mac_near_keyword(command, args, keywords, get_word_index): + """Searches a command's output for a MAC address near a keyword. + + Each line of words in the output is case-insensitively searched for + any of the given keywords. Upon a match, get_word_index is invoked + to pick a word from the line, given the index of the match. For + example, lambda i: 0 would get the first word on the line, while + lambda i: i - 1 would get the word preceding the keyword. + """ + stdout = _get_command_stdout(command, args) + if stdout is None: + return None + + first_local_mac = None + for line in stdout: + words = line.lower().rstrip().split() + for i in range(len(words)): + if words[i] in keywords: + try: + word = words[get_word_index(i)] + mac = int(word.replace(_MAC_DELIM, b''), 16) + except (ValueError, IndexError): + # Virtual interfaces, such as those provided by + # VPNs, do not have a colon-delimited MAC address + # as expected, but a 16-byte HWAddr separated by + # dashes. These should be ignored in favor of a + # real MAC address + pass + else: + if _is_universal(mac): + return mac + first_local_mac = first_local_mac or mac + return first_local_mac or None + + +def _parse_mac(word): + # Accept 'HH:HH:HH:HH:HH:HH' MAC address (ex: '52:54:00:9d:0e:67'), + # but reject IPv6 address (ex: 'fe80::5054:ff:fe9' or '123:2:3:4:5:6:7:8'). + # + # Virtual interfaces, such as those provided by VPNs, do not have a + # colon-delimited MAC address as expected, but a 16-byte HWAddr separated + # by dashes. These should be ignored in favor of a real MAC address + parts = word.split(_MAC_DELIM) + if len(parts) != 6: + return + if _MAC_OMITS_LEADING_ZEROES: + # (Only) on AIX the macaddr value given is not prefixed by 0, e.g. + # en0 1500 link#2 fa.bc.de.f7.62.4 110854824 0 160133733 0 0 + # not + # en0 1500 link#2 fa.bc.de.f7.62.04 110854824 0 160133733 0 0 + if not all(1 <= len(part) <= 2 for part in parts): + return + hexstr = b''.join(part.rjust(2, b'0') for part in parts) + else: + if not all(len(part) == 2 for part in parts): + return + hexstr = b''.join(parts) + try: + return int(hexstr, 16) + except ValueError: + return + + +def _find_mac_under_heading(command, args, heading): + """Looks for a MAC address under a heading in a command's output. + + The first line of words in the output is searched for the given + heading. Words at the same word index as the heading in subsequent + lines are then examined to see if they look like MAC addresses. + """ + stdout = _get_command_stdout(command, args) + if stdout is None: + return None + + keywords = stdout.readline().rstrip().split() + try: + column_index = keywords.index(heading) + except ValueError: + return None + + first_local_mac = None + for line in stdout: + words = line.rstrip().split() + try: + word = words[column_index] + except IndexError: + continue + + mac = _parse_mac(word) + if mac is None: + continue + if _is_universal(mac): + return mac + if first_local_mac is None: + first_local_mac = mac + + return first_local_mac + + +# The following functions call external programs to 'get' a macaddr value to +# be used as basis for an uuid def _ifconfig_getnode(): """Get the hardware address on Unix by running ifconfig.""" # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes. + keywords = (b'hwaddr', b'ether', b'address:', b'lladdr') for args in ('', '-a', '-av'): - mac = _find_mac('ifconfig', args, [b'hwaddr', b'ether'], lambda i: i+1) + mac = _find_mac_near_keyword('ifconfig', args, keywords, lambda i: i+1) if mac: return mac + return None def _ip_getnode(): """Get the hardware address on Unix by running ip.""" # This works on Linux with iproute2. - mac = _find_mac('ip', 'link list', [b'link/ether'], lambda i: i+1) + mac = _find_mac_near_keyword('ip', 'link', [b'link/ether'], lambda i: i+1) if mac: return mac + return None def _arp_getnode(): """Get the hardware address on Unix by running arp.""" @@ -370,159 +529,113 @@ def _arp_getnode(): return None # Try getting the MAC addr from arp based on our IP address (Solaris). - return _find_mac('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1) + mac = _find_mac_near_keyword('arp', '-an', [os.fsencode(ip_addr)], lambda i: -1) + if mac: + return mac + + # This works on OpenBSD + mac = _find_mac_near_keyword('arp', '-an', [os.fsencode(ip_addr)], lambda i: i+1) + if mac: + return mac + + # This works on Linux, FreeBSD and NetBSD + mac = _find_mac_near_keyword('arp', '-an', [os.fsencode('(%s)' % ip_addr)], + lambda i: i+2) + # Return None instead of 0. + if mac: + return mac + return None def _lanscan_getnode(): """Get the hardware address on Unix by running lanscan.""" # This might work on HP-UX. - return _find_mac('lanscan', '-ai', [b'lan0'], lambda i: 0) + return _find_mac_near_keyword('lanscan', '-ai', [b'lan0'], lambda i: 0) def _netstat_getnode(): """Get the hardware address on Unix by running netstat.""" - # This might work on AIX, Tru64 UNIX and presumably on IRIX. - try: - proc = _popen('netstat', '-ia') - if not proc: - return - with proc: - words = proc.stdout.readline().rstrip().split() - try: - i = words.index(b'Address') - except ValueError: - return - for line in proc.stdout: - try: - words = line.rstrip().split() - word = words[i] - if len(word) == 17 and word.count(b':') == 5: - mac = int(word.replace(b':', b''), 16) - if mac: - return mac - except (ValueError, IndexError): - pass - except OSError: - pass + # This works on AIX and might work on Tru64 UNIX. + return _find_mac_under_heading('netstat', '-ian', b'Address') def _ipconfig_getnode(): - """Get the hardware address on Windows by running ipconfig.exe.""" - import os, re - dirs = ['', r'c:\windows\system32', r'c:\winnt\system32'] - try: - import ctypes - buffer = ctypes.create_string_buffer(300) - ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300) - dirs.insert(0, buffer.value.decode('mbcs')) - except: - pass - for dir in dirs: - try: - pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all') - except OSError: - continue - with pipe: - for line in pipe: - value = line.split(':')[-1].strip().lower() - if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value): - return int(value.replace('-', ''), 16) + """[DEPRECATED] Get the hardware address on Windows.""" + # bpo-40501: UuidCreateSequential() is now the only supported approach + return _windll_getnode() def _netbios_getnode(): - """Get the hardware address on Windows using NetBIOS calls. - See http://support.microsoft.com/kb/118623 for details.""" - import win32wnet, netbios - ncb = netbios.NCB() - ncb.Command = netbios.NCBENUM - ncb.Buffer = adapters = netbios.LANA_ENUM() - adapters._pack() - if win32wnet.Netbios(ncb) != 0: - return - adapters._unpack() - for i in range(adapters.length): - ncb.Reset() - ncb.Command = netbios.NCBRESET - ncb.Lana_num = ord(adapters.lana[i]) - if win32wnet.Netbios(ncb) != 0: - continue - ncb.Reset() - ncb.Command = netbios.NCBASTAT - ncb.Lana_num = ord(adapters.lana[i]) - ncb.Callname = '*'.ljust(16) - ncb.Buffer = status = netbios.ADAPTER_STATUS() - if win32wnet.Netbios(ncb) != 0: - continue - status._unpack() - bytes = status.adapter_address[:6] - if len(bytes) != 6: - continue - return int.from_bytes(bytes, 'big') + """[DEPRECATED] Get the hardware address on Windows.""" + # bpo-40501: UuidCreateSequential() is now the only supported approach + return _windll_getnode() -# Thanks to Thomas Heller for ctypes and for his help with its use here. -# If ctypes is available, use it to find system routines for UUID generation. -# XXX This makes the module non-thread-safe! -_uuid_generate_time = _UuidCreate = None +# Import optional C extension at toplevel, to help disabling it when testing try: - import ctypes, ctypes.util - import sys + import _uuid + _generate_time_safe = getattr(_uuid, "generate_time_safe", None) + _UuidCreate = getattr(_uuid, "UuidCreate", None) + _has_uuid_generate_time_safe = _uuid.has_uuid_generate_time_safe +except ImportError: + _uuid = None + _generate_time_safe = None + _UuidCreate = None + _has_uuid_generate_time_safe = None - # The uuid_generate_* routines are provided by libuuid on at least - # Linux and FreeBSD, and provided by libc on Mac OS X. - _libnames = ['uuid'] - if not sys.platform.startswith('win'): - _libnames.append('c') - for libname in _libnames: - try: - lib = ctypes.CDLL(ctypes.util.find_library(libname)) - except Exception: - continue - if hasattr(lib, 'uuid_generate_time'): - _uuid_generate_time = lib.uuid_generate_time - break - del _libnames - # The uuid_generate_* functions are broken on MacOS X 10.5, as noted - # in issue #8621 the function generates the same sequence of values - # in the parent process and all children created using fork (unless - # those children use exec as well). - # - # Assume that the uuid_generate functions are broken from 10.5 onward, - # the test can be adjusted when a later version is fixed. - if sys.platform == 'darwin': - if int(os.uname().release.split('.')[0]) >= 9: - _uuid_generate_time = None +def _load_system_functions(): + """[DEPRECATED] Platform-specific functions loaded at import time""" - # On Windows prior to 2000, UuidCreate gives a UUID containing the - # hardware address. On Windows 2000 and later, UuidCreate makes a - # random UUID and UuidCreateSequential gives a UUID containing the - # hardware address. These routines are provided by the RPC runtime. - # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last - # 6 bytes returned by UuidCreateSequential are fixed, they don't appear - # to bear any relationship to the MAC address of any network device - # on the box. - try: - lib = ctypes.windll.rpcrt4 - except: - lib = None - _UuidCreate = getattr(lib, 'UuidCreateSequential', - getattr(lib, 'UuidCreate', None)) -except: - pass -def _unixdll_getnode(): - """Get the hardware address on Unix using ctypes.""" - _buffer = ctypes.create_string_buffer(16) - _uuid_generate_time(_buffer) - return UUID(bytes=bytes_(_buffer.raw)).node +def _unix_getnode(): + """Get the hardware address on Unix using the _uuid extension module.""" + if _generate_time_safe: + uuid_time, _ = _generate_time_safe() + return UUID(bytes=uuid_time).node def _windll_getnode(): - """Get the hardware address on Windows using ctypes.""" - _buffer = ctypes.create_string_buffer(16) - if _UuidCreate(_buffer) == 0: - return UUID(bytes=bytes_(_buffer.raw)).node + """Get the hardware address on Windows using the _uuid extension module.""" + if _UuidCreate: + uuid_bytes = _UuidCreate() + return UUID(bytes_le=uuid_bytes).node def _random_getnode(): - """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" + """Get a random node ID.""" + # RFC 4122, $4.1.6 says "For systems with no IEEE address, a randomly or + # pseudo-randomly generated value may be used; see Section 4.5. The + # multicast bit must be set in such addresses, in order that they will + # never conflict with addresses obtained from network cards." + # + # The "multicast bit" of a MAC address is defined to be "the least + # significant bit of the first octet". This works out to be the 41st bit + # counting from 1 being the least significant bit, or 1<<40. + # + # See https://en.wikipedia.org/wiki/MAC_address#Unicast_vs._multicast import random - return random.getrandbits(48) | 0x010000000000 + return random.getrandbits(48) | (1 << 40) + + +# _OS_GETTERS, when known, are targeted for a specific OS or platform. +# The order is by 'common practice' on the specified platform. +# Note: 'posix' and 'windows' _OS_GETTERS are prefixed by a dll/dlload() method +# which, when successful, means none of these "external" methods are called. +# _GETTERS is (also) used by test_uuid.py to SkipUnless(), e.g., +# @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, ...) +if _LINUX: + _OS_GETTERS = [_ip_getnode, _ifconfig_getnode] +elif sys.platform == 'darwin': + _OS_GETTERS = [_ifconfig_getnode, _arp_getnode, _netstat_getnode] +elif sys.platform == 'win32': + # bpo-40201: _windll_getnode will always succeed, so these are not needed + _OS_GETTERS = [] +elif _AIX: + _OS_GETTERS = [_netstat_getnode] +else: + _OS_GETTERS = [_ifconfig_getnode, _ip_getnode, _arp_getnode, + _netstat_getnode, _lanscan_getnode] +if os.name == 'posix': + _GETTERS = [_unix_getnode] + _OS_GETTERS +elif os.name == 'nt': + _GETTERS = [_windll_getnode] + _OS_GETTERS +else: + _GETTERS = _OS_GETTERS _node = None @@ -534,25 +647,19 @@ def getnode(): choose a random 48-bit number with its eighth bit set to 1 as recommended in RFC 4122. """ - global _node if _node is not None: return _node - import sys - if sys.platform == 'win32': - getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] - else: - getters = [_unixdll_getnode, _ifconfig_getnode, _ip_getnode, - _arp_getnode, _lanscan_getnode, _netstat_getnode] - - for getter in getters + [_random_getnode]: + for getter in _GETTERS + [_random_getnode]: try: _node = getter() except: continue - if _node is not None: + if (_node is not None) and (0 <= _node < (1 << 48)): return _node + assert False, '_random_getnode() returned invalid value: {}'.format(_node) + _last_timestamp = None @@ -564,17 +671,20 @@ def uuid1(node=None, clock_seq=None): # When the system provides a version-1 UUID generator, use it (but don't # use UuidCreate here because its UUIDs don't conform to RFC 4122). - if _uuid_generate_time and node is clock_seq is None: - _buffer = ctypes.create_string_buffer(16) - _uuid_generate_time(_buffer) - return UUID(bytes=bytes_(_buffer.raw)) + if _generate_time_safe is not None and node is clock_seq is None: + uuid_time, safely_generated = _generate_time_safe() + try: + is_safe = SafeUUID(safely_generated) + except ValueError: + is_safe = SafeUUID.unknown + return UUID(bytes=uuid_time, is_safe=is_safe) global _last_timestamp import time - nanoseconds = int(time.time() * 1e9) + nanoseconds = time.time_ns() # 0x01b21dd213814000 is the number of 100-ns intervals between the # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - timestamp = int(nanoseconds/100) + 0x01b21dd213814000 + timestamp = nanoseconds // 100 + 0x01b21dd213814000 if _last_timestamp is not None and timestamp <= _last_timestamp: timestamp = _last_timestamp + 1 _last_timestamp = timestamp @@ -594,8 +704,11 @@ def uuid1(node=None, clock_seq=None): def uuid3(namespace, name): """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" from hashlib import md5 - hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() - return UUID(bytes=hash[:16], version=3) + digest = md5( + namespace.bytes + bytes(name, "utf-8"), + usedforsecurity=False + ).digest() + return UUID(bytes=digest[:16], version=3) def uuid4(): """Generate a random UUID.""" From bc1bbc06dd8ed980fb090d14dc84939565c0af7f Mon Sep 17 00:00:00 2001 From: Narawit Rakket Date: Wed, 1 Dec 2021 19:59:43 +0700 Subject: [PATCH 2/2] test(uuid): remove unnecessary expectedFailure from test_uuid --- Lib/test/test_uuid.py | 80 ++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 2f3561230..f82602030 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -320,8 +320,6 @@ class BaseTestUUID: node2 = self.uuid.getnode() self.assertEqual(node1, node2, '%012x != %012x' % (node1, node2)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_pickle_roundtrip(self): def check(actual, expected): self.assertEqual(actual, expected) @@ -337,8 +335,6 @@ class BaseTestUUID: with self.subTest(protocol=proto): check(pickle.loads(pickle.dumps(u, proto)), u) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_unpickle_previous_python_versions(self): def check(actual, expected): self.assertEqual(actual, expected) @@ -458,8 +454,6 @@ class BaseTestUUID: for pickled in pickled_uuids_unsafe: check(pickle.loads(pickled), u_unsafe) - # TODO: RUSTPYTHON - @unittest.expectedFailure # bpo-32502: UUID1 requires a 48-bit identifier, but hardware identifiers # need not necessarily be 48 bits (e.g., EUI-64). def test_uuid1_eui64(self): @@ -485,8 +479,6 @@ class BaseTestUUID: except ValueError: self.fail('uuid1 was given an invalid node ID') - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_uuid1(self): equal = self.assertEqual @@ -590,8 +582,6 @@ class BaseTestUUID: u = self.uuid.uuid1() self.assertEqual(u.is_safe, self.uuid.SafeUUID.unknown) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_uuid1_time(self): with mock.patch.object(self.uuid, '_has_uuid_generate_time_safe', False), \ mock.patch.object(self.uuid, '_generate_time_safe', None), \ @@ -746,18 +736,12 @@ class BaseTestInternals: with self.subTest(mac=mac): self.assertIsNone(self.uuid._parse_mac(mac)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_parse_mac(self): self.check_parse_mac(False) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_parse_mac_aix(self): self.check_parse_mac(True) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_find_under_heading(self): data = '''\ Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Coll @@ -783,8 +767,6 @@ en0 1500 192.168.90 x071 1714807956 0 711348489 0 0 self.assertEqual(mac, 0xfead0c012304) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_find_under_heading_ipv6(self): # bpo-39991: IPv6 address "fe80::5054:ff:fe9" looks like a MAC address # (same string length) but must be skipped @@ -822,8 +804,6 @@ lo0 - 127.0.0.0/8 127.0.0.1 259955 - - 259955 - self.assertEqual(mac, 0x5254009d0e67) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_find_mac_near_keyword(self): # key and value are on the same line data = ''' @@ -855,45 +835,35 @@ eth0 Link encap:Ethernet HWaddr 12:34:56:78:90:ab self.assertTrue(0 < node < (1 << 48), "%s is not an RFC 4122 node ID" % hex) - # TODO: RUSTPYTHON - # - # @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, - # "ifconfig is not used for introspection on this platform") - # def test_ifconfig_getnode(self): - # node = self.uuid._ifconfig_getnode() - # self.check_node(node, 'ifconfig') + @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, + "ifconfig is not used for introspection on this platform") + def test_ifconfig_getnode(self): + node = self.uuid._ifconfig_getnode() + self.check_node(node, 'ifconfig') - # TODO: RUSTPYTHON - # - # @unittest.skipUnless(_uuid._ip_getnode in _uuid._GETTERS, - # "ip is not used for introspection on this platform") - # def test_ip_getnode(self): - # node = self.uuid._ip_getnode() - # self.check_node(node, 'ip') + @unittest.skipUnless(_uuid._ip_getnode in _uuid._GETTERS, + "ip is not used for introspection on this platform") + def test_ip_getnode(self): + node = self.uuid._ip_getnode() + self.check_node(node, 'ip') - # TODO: RUSTPYTHON - # - # @unittest.skipUnless(_uuid._arp_getnode in _uuid._GETTERS, - # "arp is not used for introspection on this platform") - # def test_arp_getnode(self): - # node = self.uuid._arp_getnode() - # self.check_node(node, 'arp') + @unittest.skipUnless(_uuid._arp_getnode in _uuid._GETTERS, + "arp is not used for introspection on this platform") + def test_arp_getnode(self): + node = self.uuid._arp_getnode() + self.check_node(node, 'arp') - # TODO: RUSTPYTHON - # - # @unittest.skipUnless(_uuid._lanscan_getnode in _uuid._GETTERS, - # "lanscan is not used for introspection on this platform") - # def test_lanscan_getnode(self): - # node = self.uuid._lanscan_getnode() - # self.check_node(node, 'lanscan') + @unittest.skipUnless(_uuid._lanscan_getnode in _uuid._GETTERS, + "lanscan is not used for introspection on this platform") + def test_lanscan_getnode(self): + node = self.uuid._lanscan_getnode() + self.check_node(node, 'lanscan') - # TODO: RUSTPYTHON - # - # @unittest.skipUnless(_uuid._netstat_getnode in _uuid._GETTERS, - # "netstat is not used for introspection on this platform") - # def test_netstat_getnode(self): - # node = self.uuid._netstat_getnode() - # self.check_node(node, 'netstat') + @unittest.skipUnless(_uuid._netstat_getnode in _uuid._GETTERS, + "netstat is not used for introspection on this platform") + def test_netstat_getnode(self): + node = self.uuid._netstat_getnode() + self.check_node(node, 'netstat') def test_random_getnode(self): node = self.uuid._random_getnode()