Skip to content

Commit d18d2c1

Browse files
authored
Merge pull request #9686 from pytest-dev/backport-9681-to-7.0.x
2 parents 18d35b8 + 68db4e3 commit d18d2c1

File tree

4 files changed

+56
-12
lines changed

4 files changed

+56
-12
lines changed

changelog/9645.bugfix.rst

Lines changed: 1 addition & 0 deletions
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

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

testing/test_collection.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,35 @@ def test_modules_not_importable_as_side_effect(self, pytester: Pytester) -> None
14771477
]
14781478
)
14791479

1480+
def test_using_python_path(self, pytester: Pytester) -> None:
1481+
"""
1482+
Dummy modules created by insert_missing_modules should not get in
1483+
the way of modules that could be imported via python path (#9645).
1484+
"""
1485+
pytester.makeini(
1486+
"""
1487+
[pytest]
1488+
pythonpath = .
1489+
addopts = --import-mode importlib
1490+
"""
1491+
)
1492+
pytester.makepyfile(
1493+
**{
1494+
"tests/__init__.py": "",
1495+
"tests/conftest.py": "",
1496+
"tests/subpath/__init__.py": "",
1497+
"tests/subpath/helper.py": "",
1498+
"tests/subpath/test_something.py": """
1499+
import tests.subpath.helper
1500+
1501+
def test_something():
1502+
assert True
1503+
""",
1504+
}
1505+
)
1506+
result = pytester.runpytest()
1507+
result.stdout.fnmatch_lines("*1 passed in*")
1508+
14801509

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

testing/test_pathlib.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -559,15 +559,20 @@ def test_module_name_from_path(self, tmp_path: Path) -> None:
559559
result = module_name_from_path(Path("/home/foo/test_foo.py"), Path("/bar"))
560560
assert result == "home.foo.test_foo"
561561

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

567572
mod = ModuleType("mod", doc="My Module")
568-
modules = {"src": mod}
569-
insert_missing_modules(modules, "src")
570-
assert modules == {"src": mod}
573+
modules = {"xxy": mod}
574+
insert_missing_modules(modules, "xxy")
575+
assert modules == {"xxy": mod}
571576

572577
modules = {}
573578
insert_missing_modules(modules, "")

0 commit comments

Comments
 (0)