Skip to content

Commit 4a8827d

Browse files
authored
Adjust is_namespace() to check ModuleSpec.loader (#2410)
This fixes inference when six.moves is imported. Closes #2409
1 parent 4ba531b commit 4a8827d

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

ChangeLog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ Release date: TBA
1919

2020
Refs pylint-dev/pylint#9442
2121

22+
* Make ``astroid.interpreter._import.util.is_namespace`` only consider modules
23+
using a loader set to ``NamespaceLoader`` or ``None`` as namespaces.
24+
This fixes a problem that ``six.moves`` brain was not effective if ``six.moves``
25+
was already imported.
26+
27+
Closes #1107
28+
2229

2330
What's New in astroid 3.1.1?
2431
============================

astroid/interpreter/_import/util.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
from astroid.const import IS_PYPY
1414

15+
if sys.version_info >= (3, 11):
16+
from importlib.machinery import NamespaceLoader
17+
else:
18+
from importlib._bootstrap_external import _NamespaceLoader as NamespaceLoader
19+
1520

1621
@lru_cache(maxsize=4096)
1722
def is_namespace(modname: str) -> bool:
@@ -101,4 +106,7 @@ def is_namespace(modname: str) -> bool:
101106
found_spec is not None
102107
and found_spec.submodule_search_locations is not None
103108
and found_spec.origin is None
109+
and (
110+
found_spec.loader is None or isinstance(found_spec.loader, NamespaceLoader)
111+
)
104112
)

tests/brain/test_six.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def test_attribute_access(self) -> None:
2929
six.moves.urllib_parse #@
3030
six.moves.urllib_error #@
3131
six.moves.urllib.request #@
32+
from six.moves import StringIO
33+
StringIO #@
3234
"""
3335
)
3436
assert isinstance(ast_nodes, list)
@@ -64,6 +66,18 @@ def test_attribute_access(self) -> None:
6466
self.assertIsInstance(urlretrieve, nodes.FunctionDef)
6567
self.assertEqual(urlretrieve.qname(), "urllib.request.urlretrieve")
6668

69+
StringIO = next(ast_nodes[4].infer())
70+
self.assertIsInstance(StringIO, nodes.ClassDef)
71+
self.assertEqual(StringIO.qname(), "_io.StringIO")
72+
self.assertTrue(StringIO.callable())
73+
74+
def test_attribute_access_with_six_moves_imported(self) -> None:
75+
astroid.MANAGER.clear_cache()
76+
astroid.MANAGER._mod_file_cache.clear()
77+
import six.moves # type: ignore[import] # pylint: disable=import-outside-toplevel,unused-import,redefined-outer-name
78+
79+
self.test_attribute_access()
80+
6781
def test_from_imports(self) -> None:
6882
ast_node = builder.extract_node(
6983
"""

0 commit comments

Comments
 (0)