Repository navigation
Conversation
`install` appended a `MetadataPathFinder` to `sys.meta_path` while the module body was still executing, 36 lines before `PathDistribution` is bound, and `PathDistribution` is the only global the installed finder has yet to see (`Prepared`, `FastPath` and `DistributionFinder` all precede it). Anything walking `sys.meta_path` in that window resolves it against incomplete globals and raises `NameError: name 'PathDistribution' is not defined`. Two conditions reach the window. Another thread calling `entry_points()` takes no module lock, as it imports nothing and only iterates `sys.meta_path`. And an import aborted in the window, as an async exception such as a signal handler or a soft time limit can do, leaves the half-built finder installed for the life of the process: the module is dropped from `sys.modules`, `install` has already deleted `PathFinder.find_distributions` so the orphan is the only provider, and even a later successful import does not displace it. Installing at the end of the module, rather than just after `PathDistribution`, states the invariant the finder depends on and so survives any later reordering. The stdlib copy is unaffected, where `install` is stripped and `PathFinder.find_distributions` imports `MetadataPathFinder` lazily. Closes #525. Co-Authored-By: Claude Opus 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
installappended aMetadataPathFindertosys.meta_pathwhile the module body was still executing, 36 lines beforePathDistributionis bound.PathDistributionis the only global the installed finder has yet to see —Prepared,FastPathandDistributionFinderall precede it — which is why it is specifically this name that fails.Anything walking
sys.meta_pathin that window resolves the finder against incomplete globals:Two conditions reach it:
entry_points(). No module lock applies, because that thread imports nothing — it only iteratessys.meta_path.KeyboardInterrupt) can do. The module is dropped fromsys.modulesbut the half-built finder stays installed for the life of the process,installhas already deletedPathFinder.find_distributionsso the orphan is the only provider, and even a later successful import does not displace it.The second explains why #525 wasn't reproducible: the import that fails is not the import that reports, and consumers of a backport conventionally swallow its
ImportError.Installing at the end of the module, rather than just after
PathDistribution, states the invariant the finder actually depends on, so a later reordering can't silently reopen the window.The stdlib copy is unaffected —
installis stripped there andPathFinder.find_distributionsimportsMetadataPathFinderlazily — so this needs no CPython-side change and stays clear of python/cpython#160387.Test
FinderInstallTestssnapshots the module globals at the moment the finder is published and assertsPathDistributionis already bound. Without the fix:Closes #525.
🤖 Generated with Claude Code