Match uuid.getnode() native node detection to CPython - #8612
Conversation
Cache native MAC address detection and advertise an extractable node only when a hardware address is available. This lets uuid.getnode() use the native UUID path while preserving its existing fallbacks. Assisted-by: Codex:gpt-5.6-sol
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughChangesMAC-based UUID node identification
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to The change makes native UUID node selection use a cached host MAC when available while preserving existing fallbacks; no actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
uuid.getnode() native node detection to CPython
Match uuid.getnode()'s documented interface-selection rule by scanning available addresses before falling back to a locally administered one. Ignore zero addresses and cover the selection behavior with Rust unit tests. Assisted-by: Codex:gpt-5.6-sol
Summary
Cache the hardware node used by the native
_uuidgenerator and exposehas_stable_extractable_nodeas an integer capability flag when a MAC address is available.This allows
uuid.getnode()to prefer_unix_getnode()when RustPython's native UUID implementation has a stable extractable node. If hardware lookup fails, RustPython still advertises no stable node anduuid.getnode()keeps its existing platform-command and random fallbacks.When several MAC addresses are available, the native lookup now prefers a universally administered address and falls back to the first locally administered address, matching the documented
uuid.getnode()selection rule.Python documentation contract
The Python 3.14 documentation for
uuid.getnode()defines these observable requirements:It also notes that the first call may launch a separate program and therefore may be slow. CPython's current implementation caches the first valid result, but the documentation does not separately promise cache identity as part of the public contract.
CPython implementation
RustPython's current
Lib/uuid.pywas updated from CPython revision06f9c8ca1cb9abe92507108a299a65ee868d07e3.CPython gates the native Unix getter on the extension's stable-node capability (
Lib/uuid.pypermalink):getnode()tries that native getter first on POSIX, validates the 48-bit result, caches it, and eventually falls back to a random node (Lib/uuid.pypermalink):Its command-based MAC discovery records the first locally administered address but immediately returns a universally administered address when one is found (
Lib/uuid.pypermalink):CPython exposes
has_stable_extractable_nodeas an integer and enables it only when the native implementation can provide a stable node (Modules/_uuidmodule.cpermalink):The capability value is platform- and build-dependent. CPython's configure probe enables it only when two independent native UUID probes return the same node (
configure.acpermalink), and its test repeats_unix_getnode()in two subprocesses and requires equal results (Lib/test/test_uuid.pypermalink).RustPython does not wrap the platform
libuuid; its native generator usesrustpython_host_env::socket::mac_address()and falls back to random bytes. This PR caches the MAC lookup and reports the capability as1exactly when that lookup succeeds. A missing MAC reports0, leaving CPython's existing fallback chain active.Behavior changes
Both CPython's native UUID backend and RustPython's
generate_time_safe()may internally use a random node when they cannot obtain a MAC address. In both implementations, a falsehas_stable_extractable_nodecapability preventsuuid._unix_getnode()from accepting that native random node, so the publicuuid.getnode()continues through the OS-command getters before using_random_getnode(). This PR preserves that fallback behavior; it changes the positive case where RustPython can obtain a stable MAC directly.The importable
_uuid.has_stable_extractable_nodeattribute is externally observable, although_uuidis an internal, undocumented extension module rather than a public Python API. Its value is platform- and build-dependent, so CPython and RustPython need not report the same number on the same host. The relevant behavior is that it is an integer capability matching whether the native getter can return a stable node. Before this PR RustPython always exposedbool(False)and disabled_unix_getnode(); afterward it exposesint(1)when its MAC lookup succeeds andint(0)otherwise.The comparison uses one script to format
uuid.getnode()as a conventional MAC address, verify caching, and force the documented random fallback:The real MAC is redacted below to avoid publishing a machine identifier. The three redacted runtime values were equal when run on the same host. Each
fresh-processcheck also launches three independent interpreter processes: normalgetnode()remains equal across all three and matches the parent process, while a forced random fallback changes across processes.The unmodified CPython tests conditionally skip native-node coverage when the extension cannot advertise or return a stable node:
test_unix_getnode_from_libuuidcallsskipTest()when_has_stable_extractable_nodeis false;test_unix_getnodepasses_unix_getnode()through CPython'scheck_node(), which skips when the getter returnsNone.Before this PR, RustPython reported the capability as
False(abool), so those paths were skipped. After this PR, a supported POSIX host with an available MAC reports1(anint), and both original CPython tests execute and pass. This is askip→passtransition, not anexpectedFailure→unexpected successtransition. No Python source or test marker underLib/is changed.CPython 3.14.7
RustPython before
RustPython after
Summary by CodeRabbit