Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix AttributeError crash when using --import-mode=importlib #13029

Merged
merged 2 commits into from
Dec 7, 2024
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 @@
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__")

Check warning on line 673 in src/_pytest/pathlib.py

View check run for this annotation

Codecov / codecov/patch

src/_pytest/pathlib.py#L673

Added line #L673 was not covered by tests
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
Loading