Skip to content

Commit a8250cb

Browse files
Fix: pytest >=8.1.0 displays no diff for AssertionError with --import-mode=importlib (#12659)
1 parent b08b41c commit a8250cb

File tree

5 files changed

+52
-1
lines changed

5 files changed

+52
-1
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ Ted Xiao
412412
Terje Runde
413413
Thomas Grainger
414414
Thomas Hisch
415+
Tianyu Dongfang
415416
Tim Hoffmann
416417
Tim Strazny
417418
TJ Bruno

changelog/12659.bugfix.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed the issue of not displaying assertion failure differences when using the parameter '--import-mode=importlib' in pytest>=8.1 (#12659). The purpose of this import mode is to avoid modifications to `sys.path`, allowing test cases to have the same module names.

src/_pytest/assertion/rewrite.py

+10
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ def find_spec(
101101

102102
# Type ignored because mypy is confused about the `self` binding here.
103103
spec = self._find_spec(name, path) # type: ignore
104+
105+
if spec is None and path is not None:
106+
# With --import-mode=importlib, PathFinder cannot find spec without modifying `sys. path`,
107+
# causing inability to assert rewriting (#12659).
108+
# At this point, try using the file path to find the module spec.
109+
for _path_str in path:
110+
spec = importlib.util.spec_from_file_location(name, _path_str)
111+
if spec is not None:
112+
break
113+
104114
if (
105115
# the import machinery could not find a file to import
106116
spec is None

src/_pytest/pathlib.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,9 @@ def _import_module_using_spec(
621621
# Checking with sys.meta_path first in case one of its hooks can import this module,
622622
# such as our own assertion-rewrite hook.
623623
for meta_importer in sys.meta_path:
624-
spec = meta_importer.find_spec(module_name, [str(module_location)])
624+
spec = meta_importer.find_spec(
625+
module_name, [str(module_location), str(module_path)]
626+
)
625627
if spec_matches_module_path(spec, module_path):
626628
break
627629
else:

testing/test_pathlib.py

+37
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,43 @@ def test_resolve_pkg_root_and_module_name_ns_multiple_levels(
13721372
)
13731373
assert mod is mod2
13741374

1375+
def test_ns_multiple_levels_import_rewrite_assertions(
1376+
self,
1377+
tmp_path: Path,
1378+
monkeypatch: MonkeyPatch,
1379+
pytester: Pytester,
1380+
) -> None:
1381+
models_py, algorithms_py = self.setup_directories(
1382+
tmp_path, monkeypatch, pytester
1383+
)
1384+
code = dedent("""
1385+
def test():
1386+
assert "four lights" == "five lights"
1387+
""")
1388+
1389+
# A case is in a subdirectory with an `__init__.py` file.
1390+
test_py = tmp_path / tmp_path / "src/dist2/com/company/calc/algo/test_demo.py"
1391+
test_py.write_text(code, encoding="UTF-8")
1392+
1393+
pkg_root, module_name = resolve_pkg_root_and_module_name(
1394+
test_py, consider_namespace_packages=True
1395+
)
1396+
assert (pkg_root, module_name) == (
1397+
tmp_path / "src/dist2",
1398+
"com.company.calc.algo.test_demo",
1399+
)
1400+
1401+
result = pytester.runpytest("--import-mode=importlib", test_py)
1402+
1403+
result.stdout.fnmatch_lines(
1404+
[
1405+
"E AssertionError: assert 'four lights' == 'five lights'",
1406+
"E *",
1407+
"E - five lights*",
1408+
"E + four lights",
1409+
]
1410+
)
1411+
13751412
@pytest.mark.parametrize("import_mode", ["prepend", "append", "importlib"])
13761413
def test_incorrect_namespace_package(
13771414
self,

0 commit comments

Comments
 (0)