Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/2353.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``pytest_plugins`` entries imported as a side effect of another plugin now also get assertion rewriting.
19 changes: 18 additions & 1 deletion src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,18 @@ def _import_plugin_specs(
self, spec: types.ModuleType | str | Sequence[str] | None
) -> None:
plugins = _get_plugin_specs_as_list(spec)
# Pre-mark plugins so side-effect imports are rewritten too (#2353).
# Skip blocked, registered or already imported ones. Their own import
# handles the warning.
self.rewrite_hook.mark_rewrite(
*(
_resolve_plugin_import_spec(plugin)
for plugin in plugins
if _resolve_plugin_import_spec(plugin) not in sys.modules
and not self.is_blocked(plugin)
and self.get_plugin(plugin) is None
)
)
for import_spec in plugins:
self.import_plugin(import_spec, consider_entry_points=True)

Expand All @@ -928,7 +940,7 @@ def import_plugin(self, modname: str, consider_entry_points: bool = False) -> No
if self.is_blocked(modname) or self.get_plugin(modname) is not None:
return

importspec = "_pytest." + modname if modname in builtin_plugins else modname
importspec = _resolve_plugin_import_spec(modname)
self.rewrite_hook.mark_rewrite(importspec)

if consider_entry_points:
Expand Down Expand Up @@ -1006,6 +1018,11 @@ def _get_plugin_specs_as_list(
)


def _resolve_plugin_import_spec(modname: str) -> str:
"""Resolve a plugin name to its import name (builtins live under ``_pytest``)."""
return "_pytest." + modname if modname in builtin_plugins else modname


def _iter_rewritable_modules(package_files: Iterable[str]) -> Iterator[str]:
"""Given an iterable of file names in a source distribution, return the "names" that should
be marked for assertion rewrite.
Expand Down
22 changes: 22 additions & 0 deletions testing/test_assertrewrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,28 @@ def test_rewrite_warning_using_pytest_plugins(self, pytester: Pytester) -> None:
result.stdout.fnmatch_lines(["*= 1 passed in *=*"])
result.stdout.no_fnmatch_line("*pytest-warning summary*")

def test_plugin_imported_as_side_effect_is_rewritten(
self, pytester: Pytester
) -> None:
"""A plugin imported as a side effect of another plugin must still
get assertion rewriting (#2353)."""
pytester.makepyfile(
**{
"conftest.py": "pytest_plugins = ['plugin_2353_a', 'plugin_2353_b']",
"plugin_2353_a.py": "import plugin_2353_b",
"plugin_2353_b.py": "def check():\n x = 1\n assert x == 2\n",
"test_2353_side_effect.py": (
"import plugin_2353_b\n\ndef test_rewritten():\n"
" plugin_2353_b.check()\n"
),
}
)
pytester.chdir()
result = pytester.runpytest_subprocess()
result.assert_outcomes(failed=1)
result.stdout.fnmatch_lines(["E *assert 1 == 2*"])
result.stdout.no_fnmatch_line("*already imported*")

def test_rewrite_warning_using_pytest_plugins_env_var(
self, pytester: Pytester, monkeypatch
) -> None:
Expand Down