Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/13026.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed :class:`AttributeError` crash when using ``--import-mode=importlib`` when top-level directory same name as another module of the standard library.
5 changes: 4 additions & 1 deletion src/_pytest/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,10 @@ def _import_module_using_spec(
parent_module: ModuleType | None = None
if parent_module_name:
parent_module = sys.modules.get(parent_module_name)
if parent_module is None:
# If the parent_module lacks the `__path__` attribute, AttributeError when finding a submodule's spec,
# requiring re-import according to the path.
need_reimport = not hasattr(parent_module, "__path__")
if parent_module is None or need_reimport:
# Get parent_location based on location, get parent_path based on path.
if module_path.name == "__init__.py":
# If the current module is in a package,
Expand Down
31 changes: 31 additions & 0 deletions testing/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,37 @@ def test_my_test():
result = pytester.runpytest("--import-mode=importlib")
result.stdout.fnmatch_lines("* 1 passed *")

@pytest.mark.parametrize("name", ["code", "time", "math"])
def test_importlib_same_name_as_stl(
self, pytester, ns_param: bool, tmp_path: Path, name: str
):
"""Import a namespace package with the same name as the standard library (#13026)."""
file_path = pytester.path / f"{name}/foo/test_demo.py"
file_path.parent.mkdir(parents=True)
file_path.write_text(
dedent(
"""
def test_demo():
pass
"""
),
encoding="utf-8",
)

# unit test
__import__(name) # import standard library

import_path( # import user files
file_path,
mode=ImportMode.importlib,
root=pytester.path,
consider_namespace_packages=ns_param,
)

# E2E test
result = pytester.runpytest("--import-mode=importlib")
result.stdout.fnmatch_lines("* 1 passed *")

def create_installed_doctests_and_tests_dir(
self, path: Path, monkeypatch: MonkeyPatch
) -> tuple[Path, Path, Path]:
Expand Down