Skip to content

Commit bc94a51

Browse files
committed
Add a warning option which does not escape its arguments.
This is useful when to use regular expressions, like for example ignore a bunch of dynamic messages --filterwarnigns 'ignore:Please use assert.* instead.:' Or ignore all the warnings in a sub-backage --filterwarnigns 'ignore:::package.submodule.*' This is also available in the ini file as the filterwarnigns options
1 parent bc5a8c7 commit bc94a51

File tree

5 files changed

+144
-1
lines changed

5 files changed

+144
-1
lines changed

README.rst

+21
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,27 @@ You can also turn warnings into actual errors::
2727
py.test -W error
2828

2929

30+
Advance usage
31+
=============
32+
33+
You can get more fine grained filtering of warnings by using the
34+
``filterwarnings`` configuration option.
35+
36+
``filterwarnings`` works like the python's ``-W`` flag except it will not
37+
escape special characters.
38+
39+
Example
40+
-------
41+
42+
.. code::
43+
44+
# pytest.ini
45+
[pytest]
46+
filterwarnings= default
47+
ignore:.*is deprecated.*:Warning
48+
error::DeprecationWarning:importlib.*
49+
50+
3051
Changes
3152
=======
3253

helper_test_a.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import warnings
2+
3+
4+
def deprecated_a():
5+
"""
6+
A warning triggered in __this__ module for testing.
7+
"""
8+
globals()['__warningregistry__'] = {}
9+
warnings.warn("This is deprecated message_a",
10+
DeprecationWarning, stacklevel=0)

helper_test_b.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import warnings
2+
3+
4+
def user_warning_b():
5+
"""
6+
A warning triggered in __this__ module for testing.
7+
"""
8+
# reset the "once" filters
9+
# globals()['__warningregistry__'] = {}
10+
warnings.warn("This is deprecated message_b different from a",
11+
UserWarning, stacklevel=1)

pytest_warnings.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,39 @@
55
import warnings
66

77

8+
def _setoption(wmod, arg):
9+
"""
10+
Copy of the warning._setoption function but does not escape arguments.
11+
"""
12+
parts = arg.split(':')
13+
if len(parts) > 5:
14+
raise wmod._OptionError("too many fields (max 5): %r" % (arg,))
15+
while len(parts) < 5:
16+
parts.append('')
17+
action, message, category, module, lineno = [s.strip()
18+
for s in parts]
19+
action = wmod._getaction(action)
20+
category = wmod._getcategory(category)
21+
if lineno:
22+
try:
23+
lineno = int(lineno)
24+
if lineno < 0:
25+
raise ValueError
26+
except (ValueError, OverflowError):
27+
raise wmod._OptionError("invalid lineno %r" % (lineno,))
28+
else:
29+
lineno = 0
30+
wmod.filterwarnings(action, message, category, module, lineno)
31+
32+
833
def pytest_addoption(parser):
934
group = parser.getgroup("pytest-warnings")
1035
group.addoption(
1136
'-W', '--pythonwarnings', action='append',
12-
help="set which warnings to report, see ...")
37+
help="set which warnings to report, see -W option of python itself.")
38+
parser.addini("filterwarnings", type="linelist",
39+
help="Each line specifies warning filter pattern which would be passed"
40+
"to warnings.filterwarnings. Process after -W and --pythonwarnings.")
1341

1442

1543
@pytest.hookimpl(hookwrapper=True)
@@ -28,12 +56,17 @@ def showwarning(message, category, filename, lineno, file=None, line=None):
2856
message, category, filename, lineno, file=file, line=line)
2957

3058
args = item.config.getoption('pythonwarnings') or []
59+
inifilters = item.config.getini("filterwarnings")
3160
with wrec:
3261
_showwarning = wrec._showwarning
3362
warnings.showwarning = showwarning
3463
wrec._module.simplefilter('once')
3564
for arg in args:
3665
wrec._module._setoption(arg)
66+
67+
for arg in inifilters:
68+
_setoption(wrec._module, arg)
69+
3770
yield
3871
wrec._showwarning = _showwarning
3972

test_warnings.py

+68
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import pytest
22
import warnings
33

4+
from pytest_warnings import _setoption
5+
from helper_test_a import deprecated_a
6+
from helper_test_b import user_warning_b
7+
48

59
def test_warnings():
610
warnings.warn("Foo", DeprecationWarning)
@@ -25,3 +29,67 @@ def test_warnings1():
2529
def test_warn():
2630
with pytest.warns(DeprecationWarning):
2731
warnings.warn("Bar", DeprecationWarning)
32+
33+
34+
# This section test the ability to filter selectively warnings using regular
35+
# expressions on messages.
36+
37+
def test_filters_setoption():
38+
"A alone works"
39+
40+
with pytest.warns(DeprecationWarning):
41+
deprecated_a()
42+
43+
44+
def test_filters_setoption_2():
45+
"B alone works"
46+
47+
with pytest.warns(UserWarning) as record:
48+
user_warning_b()
49+
50+
assert len(record) == 1
51+
52+
53+
def test_filters_setoption_3():
54+
"A and B works"
55+
56+
with pytest.warns(None) as record:
57+
user_warning_b()
58+
deprecated_a()
59+
assert len(record) == 2
60+
61+
62+
def test_filters_setoption_4():
63+
"A works, B is filtered"
64+
65+
with pytest.warns(None) as record:
66+
_setoption(warnings, 'ignore:.*message_a.*')
67+
deprecated_a()
68+
user_warning_b()
69+
70+
assert len(record) == 1, "Only `A` should be filtered out"
71+
72+
73+
def test_filters_setoption_4b():
74+
"A works, B is filtered"
75+
76+
with pytest.warns(None) as record:
77+
_setoption(warnings, 'ignore:.*message_b.*')
78+
_setoption(warnings, 'ignore:.*message_a.*')
79+
_setoption(warnings, 'always:::.*helper_test_a.*')
80+
deprecated_a()
81+
user_warning_b()
82+
83+
assert len(record) == 1, "`A` and `B` should be visible, second filter reenable A"
84+
85+
86+
def test_filters_setoption_5():
87+
"B works, A is filtered"
88+
89+
with pytest.warns(None) as records:
90+
_setoption(warnings, 'always:::.*helper_test_a.*')
91+
_setoption(warnings, 'ignore::UserWarning')
92+
deprecated_a()
93+
user_warning_b()
94+
95+
assert len(records) == 1, "Only `B` should be filtered out"

0 commit comments

Comments
 (0)