Skip to content

Commit

Permalink
Fix assertion rewriting with importlib mode (#12716)
Browse files Browse the repository at this point in the history
Fixes #12659
  • Loading branch information
dongfangtianyu committed Aug 30, 2024
1 parent 419bc7a commit 9a444d1
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 1 deletion.
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.
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
36 changes: 36 additions & 0 deletions testing/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,42 @@ 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:
"""Check assert rewriting with `--import-mode=importlib` (#12659)."""
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 / "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 9a444d1

Please sign in to comment.