Skip to content

Commit b05a51f

Browse files
skshetryPierre-Sassoulas
authored andcommitted
improve is_namespace check
See https://stackoverflow.com/a/42962529. Let's take the following contents as an example: ```python import celery.result ``` From #1777, astroid started to use `processed_components` for namespace check. In the above case, the `modname` is `celery.result`, it first checks for `celery` and then `celery.result`. Before that PR, it'd always check for `celery.result`. `celery` is recreating module to make it lazily load. See https://github.com/celery/celery/blob/34533ab44d2a6492004bc3df44dc04ad5c6611e7/celery/__init__.py#L150. This module does not have `__spec__` set. Reading through Python's docs, it seems that `__spec__` can be set to None, so it seems like it's not a thing that we can depend upon for namespace checks. See https://docs.python.org/3/reference/import.html#spec__. --- The `celery.result` gets imported for me when pylint-pytest plugin tries to load fixtures, but this could happen anytime if any plugin imports packages. In that case, `importlib.util._find_spec_from_path("celery")` will raise ValueError since it's already in `sys.modules` and does not have a spec. Fixes pylint-dev/pylint#7488.
1 parent eafc0ff commit b05a51f

File tree

3 files changed

+17
-1
lines changed

3 files changed

+17
-1
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ Release date: TBA
1111

1212
Refs PyCQA/pylint#3941
1313

14+
* Improve detection of namespace packages for the modules with ``__spec__`` set to None.
15+
16+
Closes PyCQA/pylint#7488.
17+
1418

1519
What's New in astroid 2.12.11?
1620
==============================

astroid/interpreter/_import/util.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ def is_namespace(modname: str) -> bool:
5252
# Check first fragment of modname, e.g. "astroid", not "astroid.interpreter"
5353
# because of cffi's behavior
5454
# See: https://github.com/PyCQA/astroid/issues/1776
55+
mod = sys.modules[processed_components[0]]
5556
return (
56-
sys.modules[processed_components[0]].__spec__ is None
57+
mod.__spec__ is None
58+
and getattr(mod, "__file__", None) is None
59+
and hasattr(mod, "__path__")
5760
and not IS_PYPY
5861
)
5962
except KeyError:

tests/unittest_manager.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,15 @@ def test_module_unexpectedly_missing_spec(self) -> None:
144144
finally:
145145
astroid_module.__spec__ = original_spec
146146

147+
def test_module_unexpectedly_spec_is_none(self) -> None:
148+
astroid_module = sys.modules["astroid"]
149+
original_spec = astroid_module.__spec__
150+
astroid_module.__spec__ = None
151+
try:
152+
self.assertFalse(util.is_namespace("astroid"))
153+
finally:
154+
astroid_module.__spec__ = original_spec
155+
147156
def test_implicit_namespace_package(self) -> None:
148157
data_dir = os.path.dirname(resources.find("data/namespace_pep_420"))
149158
contribute = os.path.join(data_dir, "contribute_to_namespace")

0 commit comments

Comments
 (0)