Skip to content

Commit f0e5c01

Browse files
bpo-28009: Fix uuid SkipUnless logic to be based on platform programs capable of introspection (GH-12777)
uuid could try fallback methods that had no chance of working on a particular platform, and this could cause spurious test failures, as well as degraded performance as fallback options were tried and failed. This fixes both the uuid module and its test's SkipUnless logic to use a prefiltered list of techniques that may at least potentially work on that platform. Patch by Michael Felt (aixtools). (cherry picked from commit 3a1d50e) Co-authored-by: Michael Felt <aixtools@users.noreply.github.com>
1 parent 2980236 commit f0e5c01

File tree

3 files changed

+47
-19
lines changed

3 files changed

+47
-19
lines changed

Lib/test/test_uuid.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,7 @@ def test_uuid1_eui64(self):
462462
with unittest.mock.patch.multiple(
463463
self.uuid,
464464
_node=None, # Ignore any cached node value.
465-
_NODE_GETTERS_WIN32=[too_large_getter],
466-
_NODE_GETTERS_UNIX=[too_large_getter],
465+
_GETTERS=[too_large_getter],
467466
):
468467
node = self.uuid.getnode()
469468
self.assertTrue(0 < node < (1 << 48), '%012x' % node)
@@ -673,7 +672,7 @@ class TestUUIDWithExtModule(BaseTestUUID, unittest.TestCase):
673672

674673

675674
class BaseTestInternals:
676-
uuid = None
675+
_uuid = py_uuid
677676

678677
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
679678
def test_find_mac(self):
@@ -708,27 +707,32 @@ def check_node(self, node, requires=None):
708707
self.assertTrue(0 < node < (1 << 48),
709708
"%s is not an RFC 4122 node ID" % hex)
710709

711-
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
710+
@unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS,
711+
"ifconfig is not used for introspection on this platform")
712712
def test_ifconfig_getnode(self):
713713
node = self.uuid._ifconfig_getnode()
714714
self.check_node(node, 'ifconfig')
715715

716-
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
716+
@unittest.skipUnless(_uuid._ip_getnode in _uuid._GETTERS,
717+
"ip is not used for introspection on this platform")
717718
def test_ip_getnode(self):
718719
node = self.uuid._ip_getnode()
719720
self.check_node(node, 'ip')
720721

721-
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
722+
@unittest.skipUnless(_uuid._arp_getnode in _uuid._GETTERS,
723+
"arp is not used for introspection on this platform")
722724
def test_arp_getnode(self):
723725
node = self.uuid._arp_getnode()
724726
self.check_node(node, 'arp')
725727

726-
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
728+
@unittest.skipUnless(_uuid._lanscan_getnode in _uuid._GETTERS,
729+
"lanscan is not used for introspection on this platform")
727730
def test_lanscan_getnode(self):
728731
node = self.uuid._lanscan_getnode()
729732
self.check_node(node, 'lanscan')
730733

731-
@unittest.skipUnless(os.name == 'posix', 'requires Posix')
734+
@unittest.skipUnless(_uuid._netstat_getnode in _uuid._GETTERS,
735+
"netstat is not used for introspection on this platform")
732736
def test_netstat_getnode(self):
733737
node = self.uuid._netstat_getnode()
734738
self.check_node(node, 'netstat')

Lib/uuid.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,20 @@
4545
"""
4646

4747
import os
48+
import platform
4849
import sys
4950

5051
from enum import Enum
5152

5253

5354
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
5455

56+
# The recognized platforms - known behaviors
57+
_AIX = platform.system() == 'AIX'
58+
_DARWIN = platform.system() == 'Darwin'
59+
_LINUX = platform.system() == 'Linux'
60+
_WINDOWS = platform.system() == 'Windows'
61+
5562
RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
5663
'reserved for NCS compatibility', 'specified in RFC 4122',
5764
'reserved for Microsoft compatibility', 'reserved for future definition']
@@ -673,12 +680,31 @@ def _random_getnode():
673680
return random.getrandbits(48) | (1 << 40)
674681

675682

676-
_node = None
677-
678-
_NODE_GETTERS_WIN32 = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
683+
# _OS_GETTERS, when known, are targetted for a specific OS or platform.
684+
# The order is by 'common practice' on the specified platform.
685+
# Note: 'posix' and 'windows' _OS_GETTERS are prefixed by a dll/dlload() method
686+
# which, when successful, means none of these "external" methods are called.
687+
# _GETTERS is (also) used by test_uuid.py to SkipUnless(), e.g.,
688+
# @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, ...)
689+
if _LINUX:
690+
_OS_GETTERS = [_ip_getnode, _ifconfig_getnode]
691+
elif _DARWIN:
692+
_OS_GETTERS = [_ifconfig_getnode, _arp_getnode, _netstat_getnode]
693+
elif _WINDOWS:
694+
_OS_GETTERS = [_netbios_getnode, _ipconfig_getnode]
695+
elif _AIX:
696+
_OS_GETTERS = [_netstat_getnode]
697+
else:
698+
_OS_GETTERS = [_ifconfig_getnode, _ip_getnode, _arp_getnode,
699+
_netstat_getnode, _lanscan_getnode]
700+
if os.name == 'posix':
701+
_GETTERS = [_unix_getnode] + _OS_GETTERS
702+
elif os.name == 'nt':
703+
_GETTERS = [_windll_getnode] + _OS_GETTERS
704+
else:
705+
_GETTERS = _OS_GETTERS
679706

680-
_NODE_GETTERS_UNIX = [_unix_getnode, _ifconfig_getnode, _ip_getnode,
681-
_arp_getnode, _lanscan_getnode, _netstat_getnode]
707+
_node = None
682708

683709
def getnode(*, getters=None):
684710
"""Get the hardware address as a 48-bit positive integer.
@@ -692,12 +718,7 @@ def getnode(*, getters=None):
692718
if _node is not None:
693719
return _node
694720

695-
if sys.platform == 'win32':
696-
getters = _NODE_GETTERS_WIN32
697-
else:
698-
getters = _NODE_GETTERS_UNIX
699-
700-
for getter in getters + [_random_getnode]:
721+
for getter in _GETTERS + [_random_getnode]:
701722
try:
702723
_node = getter()
703724
except:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Modify the test_uuid logic to test when a program is available
2+
AND can be used to obtain a MACADDR as basis for an UUID.
3+
Patch by M. Felt

0 commit comments

Comments
 (0)