Skip to content

Commit

Permalink
Fix: pytest >=8.1.0 displays no diff for AssertionError with `--impor…
Browse files Browse the repository at this point in the history
…t-mode=importlib` (#12659)
  • Loading branch information
dongfangtianyu committed Aug 15, 2024
1 parent b08b41c commit 7a195c1
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 2 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ Ted Xiao
Terje Runde
Thomas Grainger
Thomas Hisch
Tianyu Dongfang
Tim Hoffmann
Tim Strazny
TJ Bruno
Expand Down
1 change: 1 addition & 0 deletions changelog/12659.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +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.
10 changes: 10 additions & 0 deletions src/_pytest/assertion/rewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ def find_spec(

# Type ignored because mypy is confused about the `self` binding here.
spec = self._find_spec(name, path) # type: ignore

if spec is None and path is not None:
# With --import-mode=importlib, PathFinder cannot find spec without modifying `sys. path`,
# causing inability to assert rewriting (#12659).
# At this point, try using the file path to find the module spec.
for _path_str in path:
spec = importlib.util.spec_from_file_location(name, _path_str)
if spec is not None:
break

if (
# the import machinery could not find a file to import
spec is None
Expand Down
4 changes: 3 additions & 1 deletion src/_pytest/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,9 @@ def _import_module_using_spec(
# Checking with sys.meta_path first in case one of its hooks can import this module,
# such as our own assertion-rewrite hook.
for meta_importer in sys.meta_path:
spec = meta_importer.find_spec(module_name, [str(module_location)])
spec = meta_importer.find_spec(
module_name, [str(module_location), str(module_path)]
)
if spec_matches_module_path(spec, module_path):
break
else:
Expand Down
39 changes: 38 additions & 1 deletion testing/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class TestImportPath:
"""

@pytest.fixture(scope="session")
def path1(self, tmp_path_factory: TempPathFactory) -> Generator[Path]:
def path1(self, tmp_path_factory: TempPathFactory) -> Generator[Path, None, None]:
path = tmp_path_factory.mktemp("path")
self.setuptestfs(path)
yield path
Expand Down Expand Up @@ -1372,6 +1372,43 @@ def test_resolve_pkg_root_and_module_name_ns_multiple_levels(
)
assert mod is mod2

def test_ns_multiple_levels_import_rewrite_assertions(
self,
tmp_path: Path,
monkeypatch: MonkeyPatch,
pytester: Pytester,
) -> None:
models_py, algorithms_py = self.setup_directories(
tmp_path, monkeypatch, pytester
)
code = dedent("""
def test():
assert "four lights" == "five lights"
""")

# A case is in a subdirectory with an `__init__.py` file.
test_py = tmp_path / tmp_path / "src/dist2/com/company/calc/algo/test_demo.py"
test_py.write_text(code, encoding="UTF-8")

pkg_root, module_name = resolve_pkg_root_and_module_name(
test_py, consider_namespace_packages=True
)
assert (pkg_root, module_name) == (
tmp_path / "src/dist2",
"com.company.calc.algo.test_demo",
)

result = pytester.runpytest("--import-mode=importlib", test_py)

result.stdout.fnmatch_lines(
[
"E AssertionError: assert 'four lights' == 'five lights'",
"E *",
"E - five lights*",
"E + four lights",
]
)

@pytest.mark.parametrize("import_mode", ["prepend", "append", "importlib"])
def test_incorrect_namespace_package(
self,
Expand Down

0 comments on commit 7a195c1

Please sign in to comment.