pytest
pytest copied to clipboard
Another way to disable rewrites?
I am trying to add a pytest plugin to coverage.py. Because the plugin is in the coverage package, coverage/init.py will be imported when the plugin is imported. Because I'm using coverage to run pytest in the first place, coverage/__init__.py has already been imported. This leads to a warning:
PytestAssertRewriteWarning: Module already imported so cannot be rewritten: coverage
I can disable this warning by adding PYTEST_DONT_REWRITE to the coverage/__init__.py docstring, but then that word is visible in the docstring for my package. Ugly.
Much of pytest is controlled by specially named attributes in modules. It would be great if I could control rewriting by adding an attribute to my module instead of amending the docstring.
If needed, I can provide a reproducer that shows the warning.
Here is a gist showing the warning happening: https://gist.github.com/nedbat/2ba6834eab6d008dbd1c494c39f61bad (the warning about __main__ is a confusion between coverage's file and pytest's, and only happens with a -e install of coverage, so I am not concerned about it.)
Yes, controlling this in another way sounds useful.
One solution for this might be to skip the warning during import of the (entrypoint) plugin (and also for -p coverage.pytest_plugin), only explicitly for __init__.py files seen during it (the import process).
It should/would still happen for coverage.pytest_plugin itself then.
Hi, we've run into a similar issue with Basilisp, where the basilisp package includes a pytest plugin as part of its source tree:
[tool.poetry.plugins.pytest11]:
basilisp_test_runner = "basilisp.contrib.pytest.testrunner"
The package also provides a CLI that invokes pytest.main():
From src/basilisp/cli.py:
from basilisp import main as basilisp
#...
def test(
parser: argparse.ArgumentParser,
args: argparse.Namespace,
extra: list[str],
) -> None: # pragma: no cover
#...
sys.exit(pytest.main(args=list(extra)))
However, since:
basilispdeclares a pytest plugin, enabling assertion rewriting, and- the
basilispmodule is already imported whenpytest.main()is called,
pytest raises the warning::
Module already imported so cannot be rewritten: basilisp
We'd like to suppress this warning for basilisp, as assertion rewriting isn't needed here. While pytest supports suppressing warnings using the -W option:
-W ignore:Module already imported so cannot be rewritten: basilisp:pytest.PytestAssertRewriteWarning:
attempting this like so:
from basilisp import main as basilisp
#...
def test(
parser: argparse.ArgumentParser,
args: argparse.Namespace,
extra: list[str],
) -> None: # pragma: no cover
#...
extra = [
"-W",
"ignore:Module already imported so cannot be rewritten:* basilisp:pytest.PytestAssertRewriteWarning",
] + extra
sys.exit(pytest.main(args=list(extra)))
fails with the error:
ERROR: while parsing the following warning configuration:
ignore:Module already imported so cannot be rewritten:* basilisp:pytest.PytestAssertRewriteWarning
This error occurred:
Traceback (most recent call last):
File "d:\src\basilisp\.venv\Lib\site-packages\_pytest\config\__init__.py", line 1918, in parse_warning_filter
category: type[Warning] = _resolve_warning_category(category_)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "d:\src\basilisp\.venv\Lib\site-packages\_pytest\config\__init__.py", line 1957, in _resolve_warning_category
cat = getattr(m, klass)
^^^^^^^^^^^^^^^^^
AttributeError: module 'builtins' has no attribute '* basilisp'
this doesn't work because the message contains a literal : (as in ...rewritten: basilisp), which is treated as field separator in -W, corrupting the filter definition.
Since wildcards aren't supported in -W filters one possible solution is to change the warning message in https://github.com/pytest-dev/pytest/blob/919ae9d7c12bec52ea0c18a14299223eadb2b890/src/_pytest/assertion/rewrite.py#L284
to replace : for example with something like ;:
f"Module already imported so cannot be rewritten; {name}"
So that the -W filter can now work (there is no extra : in the filter any more):
-W ignore:Module already imported so cannot be rewritten; basilisp:pytest.PytestAssertRewriteWarning.
Using : in warning messages makes it incompatible with some Python’s warning filter syntax, so replacing it would improve usability. I’m planning to raise a PR to suggest this change.
Alternatives considered
- Use Python's
warning.filterwarnings()prior to callingpytest.main:
import warnings
warnings.filterwarnings("ignore", message="Module already imported so cannot be rewritten: basilisp", category=pytest.PytestAssertRewriteWarning)
sys.exit(pytest.main(args=list(extra)))
This doesn't work doesn't work because pytest disables all filters internally when emitting this warning:
https://github.com/pytest-dev/pytest/blob/20c51f70c99ecaa4745d622a69bbe93fbf59ad16/src/_pytest/config/init.py#L1541-L1574
- Users adding explicit
filterwarningsin theirpyproject.toml:
[tool.pytest.ini_options]
filterwarnings = [
"ignore:Module already imported so cannot be rewritten. basilisp:pytest.PytestAssertRewriteWarning",
]
This works but requires the user to know and handle this technical limitation explicitly. Ideally, the warning wouldn’t be shown in the first place.
Thanks