Skip to content

Commit

Permalink
Adjust is_namespace() to check ModuleSpec.loader (#2410)
Browse files Browse the repository at this point in the history
This fixes inference when six.moves is imported.

Closes #2409
  • Loading branch information
perrinjerome authored Apr 30, 2024
1 parent 4ba531b commit 4a8827d
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 0 deletions.
7 changes: 7 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ Release date: TBA

Refs pylint-dev/pylint#9442

* Make ``astroid.interpreter._import.util.is_namespace`` only consider modules
using a loader set to ``NamespaceLoader`` or ``None`` as namespaces.
This fixes a problem that ``six.moves`` brain was not effective if ``six.moves``
was already imported.

Closes #1107


What's New in astroid 3.1.1?
============================
Expand Down
8 changes: 8 additions & 0 deletions astroid/interpreter/_import/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

from astroid.const import IS_PYPY

if sys.version_info >= (3, 11):
from importlib.machinery import NamespaceLoader
else:
from importlib._bootstrap_external import _NamespaceLoader as NamespaceLoader


@lru_cache(maxsize=4096)
def is_namespace(modname: str) -> bool:
Expand Down Expand Up @@ -101,4 +106,7 @@ def is_namespace(modname: str) -> bool:
found_spec is not None
and found_spec.submodule_search_locations is not None
and found_spec.origin is None
and (
found_spec.loader is None or isinstance(found_spec.loader, NamespaceLoader)
)
)
14 changes: 14 additions & 0 deletions tests/brain/test_six.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def test_attribute_access(self) -> None:
six.moves.urllib_parse #@
six.moves.urllib_error #@
six.moves.urllib.request #@
from six.moves import StringIO
StringIO #@
"""
)
assert isinstance(ast_nodes, list)
Expand Down Expand Up @@ -64,6 +66,18 @@ def test_attribute_access(self) -> None:
self.assertIsInstance(urlretrieve, nodes.FunctionDef)
self.assertEqual(urlretrieve.qname(), "urllib.request.urlretrieve")

StringIO = next(ast_nodes[4].infer())
self.assertIsInstance(StringIO, nodes.ClassDef)
self.assertEqual(StringIO.qname(), "_io.StringIO")
self.assertTrue(StringIO.callable())

def test_attribute_access_with_six_moves_imported(self) -> None:
astroid.MANAGER.clear_cache()
astroid.MANAGER._mod_file_cache.clear()
import six.moves # type: ignore[import] # pylint: disable=import-outside-toplevel,unused-import,redefined-outer-name

self.test_attribute_access()

def test_from_imports(self) -> None:
ast_node = builder.extract_node(
"""
Expand Down

0 comments on commit 4a8827d

Please sign in to comment.