Skip to content

Commit 098e5a6

Browse files
Fix: Using --import-mode=importlib, a directory with the same name in the namespace package causes a KeyError.(#12592
1 parent 419bc7a commit 098e5a6

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

changelog/12592.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed the issue of causes ``KeyError`` when using the parameter ``--import-mode=importlib`` in pytest>=8.2 .

src/_pytest/pathlib.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,15 @@ def _import_module_using_spec(
629629

630630
if spec_matches_module_path(spec, module_path):
631631
assert spec is not None
632+
633+
# Find spec and import this module.
634+
mod = importlib.util.module_from_spec(spec)
635+
sys.modules[module_name] = mod
636+
spec.loader.exec_module(mod) # type: ignore[union-attr]
637+
638+
if insert_modules:
639+
insert_missing_modules(sys.modules, module_name)
640+
632641
# Attempt to import the parent module, seems is our responsibility:
633642
# https://github.com/python/cpython/blob/73906d5c908c1e0b73c5436faeff7d93698fc074/Lib/importlib/_bootstrap.py#L1308-L1311
634643
parent_module_name, _, name = module_name.rpartition(".")
@@ -655,17 +664,9 @@ def _import_module_using_spec(
655664
insert_modules=insert_modules,
656665
)
657666

658-
# Find spec and import this module.
659-
mod = importlib.util.module_from_spec(spec)
660-
sys.modules[module_name] = mod
661-
spec.loader.exec_module(mod) # type: ignore[union-attr]
662-
663667
# Set this module as an attribute of the parent module (#12194).
664668
if parent_module is not None:
665669
setattr(parent_module, name, mod)
666-
667-
if insert_modules:
668-
insert_missing_modules(sys.modules, module_name)
669670
return mod
670671

671672
return None

testing/test_pathlib.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,44 @@ def test_full_ns_packages_without_init_files(
15051505
tmp_path / "src/dist2/ns/a/core/foo/m.py", consider_namespace_packages=True
15061506
) == (tmp_path / "src/dist2", "ns.a.core.foo.m")
15071507

1508+
def test_ns_multiple_levels_import_same_name_directory(
1509+
self,
1510+
tmp_path: Path,
1511+
monkeypatch: MonkeyPatch,
1512+
pytester: Pytester,
1513+
) -> None:
1514+
"""Check KeyError with `--import-mode=importlib` (#12592)."""
1515+
self.setup_directories(tmp_path, monkeypatch, pytester)
1516+
code = dedent("""
1517+
def test():
1518+
assert "four lights" == "five lights"
1519+
""")
1520+
1521+
# a subdirectories with the same name in the namespace package,
1522+
# along with a tests file
1523+
test_base_path = tmp_path / "src/dist2/com/company"
1524+
test_py = test_base_path / "a/b/c/test_demo.py"
1525+
test_dir = test_base_path / "a/b/c/c"
1526+
1527+
test_dir.mkdir(parents=True)
1528+
test_py.write_text(code, encoding="UTF-8")
1529+
1530+
pkg_root, module_name = resolve_pkg_root_and_module_name(
1531+
test_py, consider_namespace_packages=True
1532+
)
1533+
assert (pkg_root, module_name) == (
1534+
tmp_path / "src/dist2",
1535+
"com.company.a.b.c.test_demo",
1536+
)
1537+
1538+
result = pytester.runpytest("--import-mode=importlib", test_py)
1539+
1540+
result.stdout.no_fnmatch_line(
1541+
"E KeyError: 'test_ns_multiple_levels_import1.src.dist2.com.company.a.b'"
1542+
)
1543+
1544+
assert "KeyError" not in result.stdout.str()
1545+
15081546

15091547
def test_is_importable(pytester: Pytester) -> None:
15101548
pytester.syspathinsert()

0 commit comments

Comments
 (0)