Skip to content

Commit c6774cc

Browse files
committed
No longer override existing warning filters during warnings capture
Fix pytest-dev#2430
1 parent 6117930 commit c6774cc

File tree

6 files changed

+73
-35
lines changed

6 files changed

+73
-35
lines changed

CHANGELOG.rst

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
3.1.1 (unreleased)
22
==================
33

4+
* pytest warning capture no longer override existing warning filters. The previous
5+
behaviour would override all filters and caused regressions in test suites which configure warning
6+
filters to match their needs. Note as a side-effect of this is that ``DeprecationWarning``
7+
and ``PendingDeprecationWarning`` are no longer shown by default. (towncrier: 2430.bugfix)
8+
49
* Fix encoding errors for unicode warnings in Python 2. (towncrier: 2436.bugfix)
510

611
* Fix issue with non-ascii contents in doctest text files. (towncrier: 2434.bugfix)

_pytest/warnings.py

-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ def catch_warnings_for_item(item):
5353
args = item.config.getoption('pythonwarnings') or []
5454
inifilters = item.config.getini("filterwarnings")
5555
with warnings.catch_warnings(record=True) as log:
56-
warnings.simplefilter('once')
5756
for arg in args:
5857
warnings._setoption(arg)
5958

doc/en/warnings.rst

+32-20
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,18 @@ Warnings Capture
55

66
.. versionadded:: 3.1
77

8-
.. warning::
9-
pytest captures all warnings between tests, which prevents custom warning
10-
filters in existing test suites from working. If this causes problems to your test suite,
11-
this plugin can be disabled in your ``pytest.ini`` file with:
12-
13-
.. code-block:: ini
14-
15-
[pytest]
16-
addopts = -p no:warnings
17-
18-
There's an ongoing discussion about this on `#2430
19-
<https://github.com/pytest-dev/pytest/issues/2430>`_.
20-
21-
228
Starting from version ``3.1``, pytest now automatically catches all warnings during test execution
239
and displays them at the end of the session::
2410

2511
# content of test_show_warnings.py
2612
import warnings
2713

28-
def deprecated_function():
29-
warnings.warn("this function is deprecated, use another_function()", DeprecationWarning)
14+
def api_v1():
15+
warnings.warn(UserWarning("api v1, should use functions from v2"))
3016
return 1
3117

3218
def test_one():
33-
assert deprecated_function() == 1
19+
assert api_v1() == 1
3420

3521
Running pytest now produces this output::
3622

@@ -53,7 +39,7 @@ Running pytest now produces this output::
5339
The ``-W`` flag can be passed to control which warnings will be displayed or even turn
5440
them into errors::
5541

56-
$ pytest -q test_show_warnings.py -W error::DeprecationWarning
42+
$ pytest -q test_show_warnings.py -W error::UserWarning
5743
F
5844
======= FAILURES ========
5945
_______ test_one ________
@@ -72,15 +58,15 @@ them into errors::
7258
1 failed in 0.12 seconds
7359

7460
The same option can be set in the ``pytest.ini`` file using the ``filterwarnings`` ini option.
75-
For example, the configuration below will ignore all deprecation warnings, but will transform
61+
For example, the configuration below will ignore all user warnings, but will transform
7662
all other warnings into errors.
7763

7864
.. code-block:: ini
7965
8066
[pytest]
8167
filterwarnings =
8268
error
83-
ignore::DeprecationWarning
69+
ignore::UserWarning
8470
8571
8672
When a warning matches more than one option in the list, the action for the last matching option
@@ -90,13 +76,39 @@ Both ``-W`` command-line option and ``filterwarnings`` ini option are based on P
9076
`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
9177
documentation for other examples and advanced usage.
9278

79+
.. note::
80+
81+
``DeprecationWarning`` and ``PendingDeprecationWarning`` are hidden by the standard library
82+
by default so you have to explicitly configure them to be displayed in your ``pytest.ini``:
83+
84+
.. code-block:: ini
85+
86+
[pytest]
87+
filterwarnings =
88+
once::DeprecationWarning
89+
once::PendingDeprecationWarning
90+
91+
9392
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
9493
*plugin.*
9594

9695
.. _`-W option`: https://docs.python.org/3/using/cmdline.html?highlight=#cmdoption-W
9796
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
9897
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
9998

99+
100+
Disabling warning capture
101+
-------------------------
102+
103+
This feature is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
104+
105+
.. code-block:: ini
106+
107+
[pytest]
108+
addopts = -p no:warnings
109+
110+
Or passing ``-p no:warnings`` in the command-line.
111+
100112
.. _`asserting warnings`:
101113

102114
.. _assertwarnings:

testing/test_recwarn.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def test_two():
148148
result = testdir.runpytest()
149149
# the 2 tests must pass, but the call to test_one() will generate a warning
150150
# in pytest's summary
151-
result.stdout.fnmatch_lines('*=== 2 passed, 1 warnings in *===')
151+
result.stdout.fnmatch_lines('*=== 2 passed in *===')
152152

153153

154154
class TestWarns(object):

testing/test_warnings.py

+34-12
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def pyfile_with_warnings(testdir, request):
2020
module_name: '''
2121
import warnings
2222
def foo():
23-
warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))
24-
warnings.warn(DeprecationWarning("functionality is deprecated"))
23+
warnings.warn(UserWarning("user warning"))
24+
warnings.warn(RuntimeWarning("runtime warning"))
2525
return 1
2626
''',
2727
test_name: '''
@@ -43,11 +43,11 @@ def test_normal_flow(testdir, pyfile_with_warnings):
4343

4444
'*test_normal_flow.py::test_func',
4545

46-
'*normal_flow_module.py:3: PendingDeprecationWarning: functionality is pending deprecation',
47-
'* warnings.warn(PendingDeprecationWarning("functionality is pending deprecation"))',
46+
'*normal_flow_module.py:3: UserWarning: user warning',
47+
'* warnings.warn(UserWarning("user warning"))',
4848

49-
'*normal_flow_module.py:4: DeprecationWarning: functionality is deprecated',
50-
'* warnings.warn(DeprecationWarning("functionality is deprecated"))',
49+
'*normal_flow_module.py:4: RuntimeWarning: runtime warning',
50+
'* warnings.warn(RuntimeWarning("runtime warning"))',
5151
'* 1 passed, 2 warnings*',
5252
])
5353
assert result.stdout.str().count('test_normal_flow.py::test_func') == 1
@@ -90,8 +90,8 @@ def test_as_errors(testdir, pyfile_with_warnings, method):
9090
''')
9191
result = testdir.runpytest(*args)
9292
result.stdout.fnmatch_lines([
93-
'E PendingDeprecationWarning: functionality is pending deprecation',
94-
'as_errors_module.py:3: PendingDeprecationWarning',
93+
'E UserWarning: user warning',
94+
'as_errors_module.py:3: UserWarning',
9595
'* 1 failed in *',
9696
])
9797

@@ -133,9 +133,7 @@ def test_func(fix):
133133
result = testdir.runpytest()
134134
result.stdout.fnmatch_lines([
135135
'*== %s ==*' % WARNINGS_SUMMARY_HEADER,
136-
137-
'*test_unicode.py:8: UserWarning: \u6d4b\u8bd5',
138-
'*warnings.warn(u"\u6d4b\u8bd5")',
136+
'*test_unicode.py:8: UserWarning: \u6d4b\u8bd5*',
139137
'* 1 passed, 1 warnings*',
140138
])
141139

@@ -163,6 +161,30 @@ def test_func(fix):
163161

164162
'*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5',
165163
'*warnings.warn(u"\u6d4b\u8bd5")',
166-
'*warnings.py:82: UnicodeWarning: This warning*\u6d4b\u8bd5',
164+
'*warnings.py:*: UnicodeWarning: This warning*\u6d4b\u8bd5',
167165
'* 1 passed, 2 warnings*',
168166
])
167+
168+
169+
def test_works_with_filterwarnings(testdir):
170+
"""Ensure our warnings capture does not mess with pre-installed filters (#2430)."""
171+
testdir.makepyfile('''
172+
import warnings
173+
174+
class MyWarning(Warning):
175+
pass
176+
177+
warnings.filterwarnings("error", category=MyWarning)
178+
179+
class TestWarnings(object):
180+
def test_my_warning(self):
181+
try:
182+
warnings.warn(MyWarning("warn!"))
183+
assert False
184+
except MyWarning:
185+
assert True
186+
''')
187+
result = testdir.runpytest()
188+
result.stdout.fnmatch_lines([
189+
'*== 1 passed in *',
190+
])

tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ python_files=test_*.py *_test.py testing/*/*.py
184184
python_classes=Test Acceptance
185185
python_functions=test
186186
norecursedirs = .tox ja .hg cx_freeze_source
187-
filterwarnings= error
187+
filterwarnings=
188188
# produced by path.local
189189
ignore:bad escape.*:DeprecationWarning:re
190190
# produced by path.readlines

0 commit comments

Comments
 (0)