pytest: Treating warnings as errors may interrupt teardown
Description
Treating warnings as errors (e.g. with option -W error
) may interrupt teardown. When warning is reported (with warnings.warn
) during teardown, teardown is stopped. Teardown interruption is serious problem which leads to leak of resources (e.g. processes are not closed or temporary files are not deleted).
Expected behavior is teardown completion and then displaying warning message as error.
Minimal example
import warnings
import pytest
@pytest.fixture
def example_fixture():
yield
print('Teardown started')
warnings.warn('Some warning')
print('Teardown finished')
def test_teardown_bug(example_fixture):
pass
Without -W error
, teardown is fully executed correctly. (Note “Teardown finished” in output below).
$ pytest -s
======================================== test session starts ========================================
platform linux -- Python 3.8.12, pytest-7.0.0, pluggy-1.0.0
rootdir: /home/dev/Desktop/pytest-bug-reproduction
collected 1 item
test_teardown_bug.py .Teardown started
Teardown finished
========================================= warnings summary ==========================================
test_teardown_bug.py::test_teardown_bug
/home/dev/Desktop/pytest-bug-reproduction/test_teardown_bug.py:10: UserWarning: Some warning
warnings.warn('Some warning')
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=================================== 1 passed, 1 warning in 0.00s ====================================
When warnings are treated as errors, then teardown is interrupted. (Note that now “Teardown finished” is missing in output below).
$ pytest -s -W error
======================================== test session starts ========================================
platform linux -- Python 3.8.12, pytest-7.0.0, pluggy-1.0.0
rootdir: /home/dev/Desktop/pytest-bug-reproduction
collected 1 item
test_teardown_bug.py .Teardown started
E
============================================== ERRORS ===============================================
______________________________ ERROR at teardown of test_teardown_bug _______________________________
@pytest.fixture
def example_fixture():
yield
print('Teardown started')
> warnings.warn('Some warning')
E UserWarning: Some warning
test_teardown_bug.py:10: UserWarning
====================================== short test summary info ======================================
ERROR test_teardown_bug.py::test_teardown_bug - UserWarning: Some warning
==================================== 1 passed, 1 error in 0.01s =====================================
Environment
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic
$ python --version
Python 3.8.12
$ pytest --version
pytest 7.0.0
$ pip list
Package Version
---------- -------
attrs 21.4.0
iniconfig 1.1.1
packaging 21.3
pip 22.0.3
pluggy 1.0.0
py 1.11.0
pyparsing 3.0.7
pytest 7.0.0
setuptools 56.0.0
tomli 2.0.1
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 18 (16 by maintainers)
Commits related to this issue
- Workaround problem with node not closed correctly Pytest has a bug, which interrupts test teardown, when warning is emitted. This bug is visible only, when warnings are treated as errors. So I turned... — committed to openhive-network/test-tools by PiotrBatko-BlockchainWares 2 years ago
- Workaround problem with node not closed correctly Pytest has a bug, which interrupts test teardown, when warning is emitted. This bug is visible only, when warnings are treated as errors. So I turned... — committed to openhive-network/hive by PiotrBatko-BlockchainWares 2 years ago
- Workaround problem with node not closed correctly Pytest has a bug, which interrupts test teardown, when warning is emitted. This bug is visible only, when warnings are treated as errors. So I turned... — committed to openhive-network/hive by PiotrBatko-BlockchainWares 2 years ago
I found in
warnings
documentation thatwarnings.warn
may raise exception (source). I didn’t know about it during writing code usingwarnings.warn
, so my code is non-exception-safe as @asottile wrote. Pytest behavior is now completely understandable, but… 😃I used
-W error
, because my intention was to never miss emitted warnings. By default pytest reports at the end of tests, that tests are finished successfully with some warnings and returns 0. In real use cases – on CI or in PyCharm – such warnings are very hard to notice.I know, that pytest records warnings, because prints information about them in tests summary. For described use case would be enough, if pytest will be able to return non-zero and report about errors instead of warnings. Then CI will be red and IDEs will be able to show that tests failed. It is completely different behavior than
-W error
, so should be handled by another flag, let’s say--treat-warnings-as-errors
, and should be recommended instead of-W error
in documentation, because this behavior is what users expects. Complete code execution followed by report about warnings (as errors) instead of interruption in the middle. If user wants interruption, writesraise
instead ofwarn
.ok I don’t think we’re going to agree on that then. anyway my 2c is that pytest should not deviate from how python works here lest we have to explain a complex and difficult-to-understand (and surprisingly different) warning system that deviates from python. I think our recommendation should be that you be careful to write context-safe cleanup (use
with
/finally
) when exceptions could be raised (which isn’t really different from the status quo imo) – and especially when converting warnings to errors@RonnyPfannschmidt that’s kinda a strawman too – an api change which raises an exception would have the same problem
I don’t think we should deviate from what python does here, and with proper context management (
finally
/with
) this isn’t really an issue@nicoddemus bascially test runners should be able to error out on warnings without making the code that triggers warnings fall off the world all over the place
we already can go yellow on warnings, we should have a opt in to go into the reds
it needs a little design to make sense in integration
im under the impression that pytest should gain a own extra mode to report warnins as errors after a testrun
imho
-W error
is actually a test antipattern as it breaks test cleanup and code under test just to record the error lateri beleive we had a short discussion on that on twitter a few days back