-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
gh-84530: fix namespace package support in modulefinder #29196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -752,17 +752,18 @@ def _init_module_attrs(spec, module, *, override=False): | |
loader = NamespaceLoader.__new__(NamespaceLoader) | ||
loader._path = spec.submodule_search_locations | ||
spec.loader = loader | ||
# While the docs say that module.__file__ is not set for | ||
# built-in modules, and the code below will avoid setting it if | ||
# spec.has_location is false, this is incorrect for namespace | ||
# packages. Namespace packages have no location, but their | ||
# __spec__.origin is None, and thus their module.__file__ | ||
# should also be None for consistency. While a bit of a hack, | ||
# this is the best place to ensure this consistency. | ||
# | ||
# See # https://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module | ||
# and bpo-32305 | ||
module.__file__ = None | ||
if _bootstrap_external and isinstance(loader, _bootstrap_external.NamespaceLoader): | ||
# While the docs say that module.__file__ is not set for | ||
# built-in modules, and the code below will avoid setting it if | ||
# spec.has_location is false, this is incorrect for namespace | ||
# packages. Namespace packages have no location, but their | ||
# __spec__.origin is None, and thus their module.__file__ | ||
# should also be None for consistency. While a bit of a hack, | ||
# this is the best place to ensure this consistency. | ||
# | ||
# See # https://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module | ||
# and bpo-32305 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably this comment should now also mention bpo-40350. |
||
module.__file__ = None | ||
try: | ||
module.__loader__ = loader | ||
except AttributeError: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
_PKG_DIRECTORY = 5 | ||
_C_BUILTIN = 6 | ||
_PY_FROZEN = 7 | ||
_NAMESPACE = 8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change feels wrong based on the comment above ("Old imp constants"), because it introduces a "new old constant". Perhaps the comment just needs to be replaced with something more accurate. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I share the same concern, but these constants are being used here to identify the module type, so maybe we can change the comment to "constants initially imported from imp module" or something similar. |
||
|
||
# Modulefinder does a good job at simulating Python's, but it can not | ||
# handle __path__ modifications packages make at runtime. Therefore there | ||
|
@@ -66,7 +67,10 @@ def _find_module(name, path=None): | |
|
||
file_path = spec.origin | ||
|
||
if spec.loader.is_package(name): | ||
if isinstance(spec.loader, importlib.machinery.NamespaceLoader): | ||
return None, spec.submodule_search_locations, ("", "", _NAMESPACE) | ||
|
||
if spec.loader.is_package(name): # non-namespace package | ||
return None, os.path.dirname(file_path), ("", "", _PKG_DIRECTORY) | ||
|
||
if isinstance(spec.loader, importlib.machinery.SourceFileLoader): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fix support for namespace packages in :mod:`modulefinder`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rescoping this change means it no longer falls under "A backward compatibility hack." Is that intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the
if loader is None
block above still needed now thatspec.loader
is set in_bootstrap_external
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did do a deep dive into this and was meaning to write a more in-depth explanation. If I understand correctly, the backwards compatibility hack is instantiating the loader, not setting
__file__
. This function is meant to fill these missing attributes, but up until now it always expected to be the one instantiating the loader on namespace packages, which now changed with this PR. This should also trip up on 3rd party finders that set the loader for namespace packages, but so far no one has reported it yet.