Skip to content

Commit f224517

Browse files
authored
Merge pull request #9681 from nicoddemus/fix-9645-import-lib
2 parents 04cf8db + 747b837 commit f224517

File tree

4 files changed

+56
-12
lines changed

4 files changed

+56
-12
lines changed

changelog/9645.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed regression where ``--import-mode=importlib`` used together with :envvar:`PYTHONPATH` or :confval:`pythonpath` would cause import errors in test suites.

src/_pytest/pathlib.py

+14-5
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,20 @@ def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) ->
603603
module_parts = module_name.split(".")
604604
while module_name:
605605
if module_name not in modules:
606-
module = ModuleType(
607-
module_name,
608-
doc="Empty module created by pytest's importmode=importlib.",
609-
)
610-
modules[module_name] = module
606+
try:
607+
# If sys.meta_path is empty, calling import_module will issue
608+
# a warning and raise ModuleNotFoundError. To avoid the
609+
# warning, we check sys.meta_path explicitly and raise the error
610+
# ourselves to fall back to creating a dummy module.
611+
if not sys.meta_path:
612+
raise ModuleNotFoundError
613+
importlib.import_module(module_name)
614+
except ModuleNotFoundError:
615+
module = ModuleType(
616+
module_name,
617+
doc="Empty module created by pytest's importmode=importlib.",
618+
)
619+
modules[module_name] = module
611620
module_parts.pop(-1)
612621
module_name = ".".join(module_parts)
613622

testing/test_collection.py

+29
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,35 @@ def test_modules_not_importable_as_side_effect(self, pytester: Pytester) -> None
15071507
]
15081508
)
15091509

1510+
def test_using_python_path(self, pytester: Pytester) -> None:
1511+
"""
1512+
Dummy modules created by insert_missing_modules should not get in
1513+
the way of modules that could be imported via python path (#9645).
1514+
"""
1515+
pytester.makeini(
1516+
"""
1517+
[pytest]
1518+
pythonpath = .
1519+
addopts = --import-mode importlib
1520+
"""
1521+
)
1522+
pytester.makepyfile(
1523+
**{
1524+
"tests/__init__.py": "",
1525+
"tests/conftest.py": "",
1526+
"tests/subpath/__init__.py": "",
1527+
"tests/subpath/helper.py": "",
1528+
"tests/subpath/test_something.py": """
1529+
import tests.subpath.helper
1530+
1531+
def test_something():
1532+
assert True
1533+
""",
1534+
}
1535+
)
1536+
result = pytester.runpytest()
1537+
result.stdout.fnmatch_lines("*1 passed in*")
1538+
15101539

15111540
def test_does_not_crash_on_error_from_decorated_function(pytester: Pytester) -> None:
15121541
"""Regression test for an issue around bad exception formatting due to

testing/test_pathlib.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -562,15 +562,20 @@ def test_module_name_from_path(self, tmp_path: Path) -> None:
562562
result = module_name_from_path(Path("/home/foo/test_foo.py"), Path("/bar"))
563563
assert result == "home.foo.test_foo"
564564

565-
def test_insert_missing_modules(self) -> None:
566-
modules = {"src.tests.foo": ModuleType("src.tests.foo")}
567-
insert_missing_modules(modules, "src.tests.foo")
568-
assert sorted(modules) == ["src", "src.tests", "src.tests.foo"]
565+
def test_insert_missing_modules(
566+
self, monkeypatch: MonkeyPatch, tmp_path: Path
567+
) -> None:
568+
monkeypatch.chdir(tmp_path)
569+
# Use 'xxx' and 'xxy' as parent names as they are unlikely to exist and
570+
# don't end up being imported.
571+
modules = {"xxx.tests.foo": ModuleType("xxx.tests.foo")}
572+
insert_missing_modules(modules, "xxx.tests.foo")
573+
assert sorted(modules) == ["xxx", "xxx.tests", "xxx.tests.foo"]
569574

570575
mod = ModuleType("mod", doc="My Module")
571-
modules = {"src": mod}
572-
insert_missing_modules(modules, "src")
573-
assert modules == {"src": mod}
576+
modules = {"xxy": mod}
577+
insert_missing_modules(modules, "xxy")
578+
assert modules == {"xxy": mod}
574579

575580
modules = {}
576581
insert_missing_modules(modules, "")

0 commit comments

Comments
 (0)