Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions Lib/test/test_uuid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import unittest
from test import support
from test.support import import_helper
from test.support.script_helper import assert_python_ok
import builtins
import contextlib
import copy
Expand Down Expand Up @@ -32,8 +33,7 @@ def get_command_stdout(command, args):
class BaseTestUUID:
uuid = None

# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_safe_uuid_enum(self):
class CheckedSafeUUID(enum.Enum):
safe = 0
Expand Down Expand Up @@ -775,10 +775,37 @@ def test_cli_uuid5_ouputted_with_valid_namespace_and_name(self):
class TestUUIDWithoutExtModule(BaseTestUUID, unittest.TestCase):
uuid = py_uuid


@unittest.skipUnless(c_uuid, 'requires the C _uuid module')
class TestUUIDWithExtModule(BaseTestUUID, unittest.TestCase):
uuid = c_uuid

def check_has_stable_libuuid_extractable_node(self):
if not self.uuid._has_stable_extractable_node:
self.skipTest("libuuid cannot deduce MAC address")

@unittest.skipUnless(os.name == 'posix', 'POSIX only')
def test_unix_getnode_from_libuuid(self):
self.check_has_stable_libuuid_extractable_node()
script = 'import uuid; print(uuid._unix_getnode())'
_, n_a, _ = assert_python_ok('-c', script)
_, n_b, _ = assert_python_ok('-c', script)
n_a, n_b = n_a.decode().strip(), n_b.decode().strip()
self.assertTrue(n_a.isdigit())
self.assertTrue(n_b.isdigit())
self.assertEqual(n_a, n_b)

@unittest.skipUnless(os.name == 'nt', 'Windows only')
def test_windows_getnode_from_libuuid(self):
self.check_has_stable_libuuid_extractable_node()
script = 'import uuid; print(uuid._windll_getnode())'
_, n_a, _ = assert_python_ok('-c', script)
_, n_b, _ = assert_python_ok('-c', script)
n_a, n_b = n_a.decode().strip(), n_b.decode().strip()
self.assertTrue(n_a.isdigit())
self.assertTrue(n_b.isdigit())
self.assertEqual(n_a, n_b)


class BaseTestInternals:
_uuid = py_uuid
Expand Down
20 changes: 12 additions & 8 deletions Lib/uuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,39 +572,43 @@ def _netstat_getnode():
try:
import _uuid
_generate_time_safe = getattr(_uuid, "generate_time_safe", None)
_has_stable_extractable_node = getattr(_uuid, "has_stable_extractable_node", False)
_UuidCreate = getattr(_uuid, "UuidCreate", None)
except ImportError:
_uuid = None
_generate_time_safe = None
_has_stable_extractable_node = False
_UuidCreate = None


def _unix_getnode():
"""Get the hardware address on Unix using the _uuid extension module."""
if _generate_time_safe:
if _generate_time_safe and _has_stable_extractable_node:
uuid_time, _ = _generate_time_safe()
return UUID(bytes=uuid_time).node

def _windll_getnode():
"""Get the hardware address on Windows using the _uuid extension module."""
if _UuidCreate:
if _UuidCreate and _has_stable_extractable_node:
uuid_bytes = _UuidCreate()
return UUID(bytes_le=uuid_bytes).node

def _random_getnode():
"""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."
# RFC 9562, §6.10-3 says that
#
# Implementations MAY elect to obtain a 48-bit cryptographic-quality
# random number as per Section 6.9 to use as the Node ID. [...] [and]
# implementations MUST set the least significant bit of the first octet
# of the Node ID to 1. This bit is the unicast or multicast bit, which
# will never be set in IEEE 802 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/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit)
import random
return random.getrandbits(48) | (1 << 40)
return int.from_bytes(os.urandom(6)) | (1 << 40)


# _OS_GETTERS, when known, are targeted for a specific OS or platform.
Expand Down
3 changes: 3 additions & 0 deletions stdlib/src/uuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ mod _uuid {
fn has_uuid_generate_time_safe(_vm: &VirtualMachine) -> u32 {
0
}

#[pyattr(name = "has_stable_extractable_node")]
const HAS_STABLE_EXTRACTABLE_NODE: bool = false;
}
Loading