diff --git a/astroid/interpreter/_import/util.py b/astroid/interpreter/_import/util.py index 5db1702d5a..ab3aa652fb 100644 --- a/astroid/interpreter/_import/util.py +++ b/astroid/interpreter/_import/util.py @@ -34,8 +34,17 @@ def is_namespace(modname: str) -> bool: working_modname, path=last_submodule_search_locations ) except ValueError: - # Assume it's a .pth file, unless it's __main__ - return modname != "__main__" + if modname == "__main__": + return False + try: + # .pth files will be on sys.modules + return sys.modules[modname].__spec__ is None + except KeyError: + return False + except AttributeError: + # Workaround for "py" module + # https://github.com/pytest-dev/apipkg/issues/13 + return False except KeyError: # Intermediate steps might raise KeyErrors # https://github.com/python/cpython/issues/93334 diff --git a/tests/unittest_manager.py b/tests/unittest_manager.py index e9a1957e44..9cf02aff86 100644 --- a/tests/unittest_manager.py +++ b/tests/unittest_manager.py @@ -129,6 +129,15 @@ def test_module_is_not_namespace(self) -> None: self.assertFalse(util.is_namespace("tests.testdata.python3.data.all")) self.assertFalse(util.is_namespace("__main__")) + def test_module_unexpectedly_missing_spec(self) -> None: + astroid_module = sys.modules["astroid"] + original_spec = astroid_module.__spec__ + del astroid_module.__spec__ + try: + self.assertFalse(util.is_namespace("astroid")) + finally: + astroid_module.__spec__ = original_spec + 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")