summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2022-05-30 12:04:20 -0400
committerGitHub <noreply@github.com>2022-05-30 18:04:20 +0200
commitc4cc193921651eedd70d6e6a5dedaa81db2f6a67 (patch)
tree3b27543c912b6064edc53dbbf402de2a5cf0101a
parent152083468dffb8ede7465f7f0250d081b8da3523 (diff)
downloadastroid-git-c4cc193921651eedd70d6e6a5dedaa81db2f6a67.tar.gz
Provide first component of dotted path to namespace searches (#1575)
* Use first component of dotted path only in namespace searches * Add test and catch KeyError instead of altering search strategy
-rw-r--r--astroid/interpreter/_import/util.py15
-rw-r--r--tests/testdata/python3/data/parent_of_homonym/__init__.py0
-rw-r--r--tests/testdata/python3/data/parent_of_homonym/doc/README.md2
-rw-r--r--tests/testdata/python3/data/parent_of_homonym/doc/__init__.py0
-rw-r--r--tests/unittest_manager.py5
5 files changed, 15 insertions, 7 deletions
diff --git a/astroid/interpreter/_import/util.py b/astroid/interpreter/_import/util.py
index 53c6922c..47623c94 100644
--- a/astroid/interpreter/_import/util.py
+++ b/astroid/interpreter/_import/util.py
@@ -18,17 +18,18 @@ def is_namespace(modname: str) -> bool:
# That's unacceptable here, so we fallback to _find_spec_from_path(), which does
# not, but requires instead that each single parent ('astroid', 'nodes', etc.)
# be specced from left to right.
- processed_components = []
- last_parent = None
- for component in modname.split("."):
- processed_components.append(component)
- working_modname = ".".join(processed_components)
+ components = modname.split(".")
+ for i in range(1, len(components) + 1):
+ working_modname = ".".join(components[:i])
try:
- found_spec = _find_spec_from_path(working_modname, last_parent)
+ # Search under the highest package name
+ # Only relevant if package not already on sys.path
+ # See https://github.com/python/cpython/issues/89754 for reasoning
+ # Otherwise can raise bare KeyError: https://github.com/python/cpython/issues/93334
+ found_spec = _find_spec_from_path(working_modname, components[0])
except ValueError:
# executed .pth files may not have __spec__
return True
- last_parent = working_modname
if found_spec is None:
return False
diff --git a/tests/testdata/python3/data/parent_of_homonym/__init__.py b/tests/testdata/python3/data/parent_of_homonym/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/testdata/python3/data/parent_of_homonym/__init__.py
diff --git a/tests/testdata/python3/data/parent_of_homonym/doc/README.md b/tests/testdata/python3/data/parent_of_homonym/doc/README.md
new file mode 100644
index 00000000..d24e8943
--- /dev/null
+++ b/tests/testdata/python3/data/parent_of_homonym/doc/README.md
@@ -0,0 +1,2 @@
+This submodule should have the same name as a directory in the root of the project that
+is _NOT_ a python module. For this reason, it's currently called "doc".
diff --git a/tests/testdata/python3/data/parent_of_homonym/doc/__init__.py b/tests/testdata/python3/data/parent_of_homonym/doc/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/testdata/python3/data/parent_of_homonym/doc/__init__.py
diff --git a/tests/unittest_manager.py b/tests/unittest_manager.py
index 0bce3487..d098ca13 100644
--- a/tests/unittest_manager.py
+++ b/tests/unittest_manager.py
@@ -120,6 +120,11 @@ class AstroidManagerTest(
util.is_namespace("tests.testdata.python3.data.path_pkg_resources_1")
)
+ def test_submodule_homonym_with_non_module(self) -> None:
+ self.assertFalse(
+ util.is_namespace("tests.testdata.python3.data.parent_of_homonym.doc")
+ )
+
def test_implicit_namespace_package(self) -> None:
data_dir = os.path.dirname(resources.find("data/namespace_pep_420"))
contribute = os.path.join(data_dir, "contribute_to_namespace")