Add match_regex functionality to warns

This commit is contained in:
Joan Massich 2017-09-06 01:13:08 +02:00
parent d8ecca5ebd
commit aa6a67044f
2 changed files with 32 additions and 13 deletions

View File

@ -8,6 +8,8 @@ import py
import sys import sys
import warnings import warnings
import re
from _pytest.fixtures import yield_fixture from _pytest.fixtures import yield_fixture
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -99,9 +101,11 @@ def warns(expected_warning, *args, **kwargs):
>>> with warns(RuntimeWarning): >>> with warns(RuntimeWarning):
... warnings.warn("my warning", RuntimeWarning) ... warnings.warn("my warning", RuntimeWarning)
""" """
wcheck = WarningsChecker(expected_warning) match_expr = None
if not args: if not args:
return wcheck if "match" in kwargs:
match_expr = kwargs.pop("match")
return WarningsChecker(expected_warning, match_expr=match_expr)
elif isinstance(args[0], str): elif isinstance(args[0], str):
code, = args code, = args
assert isinstance(code, str) assert isinstance(code, str)
@ -109,12 +113,12 @@ def warns(expected_warning, *args, **kwargs):
loc = frame.f_locals.copy() loc = frame.f_locals.copy()
loc.update(kwargs) loc.update(kwargs)
with wcheck: with WarningsChecker(expected_warning, match_expr=match_expr):
code = _pytest._code.Source(code).compile() code = _pytest._code.Source(code).compile()
py.builtin.exec_(code, frame.f_globals, loc) py.builtin.exec_(code, frame.f_globals, loc)
else: else:
func = args[0] func = args[0]
with wcheck: with WarningsChecker(expected_warning, match_expr=match_expr):
return func(*args[1:], **kwargs) return func(*args[1:], **kwargs)
@ -174,7 +178,7 @@ class WarningsRecorder(warnings.catch_warnings):
class WarningsChecker(WarningsRecorder): class WarningsChecker(WarningsRecorder):
def __init__(self, expected_warning=None): def __init__(self, expected_warning=None, match_expr=None):
super(WarningsChecker, self).__init__() super(WarningsChecker, self).__init__()
msg = ("exceptions must be old-style classes or " msg = ("exceptions must be old-style classes or "
@ -189,6 +193,7 @@ class WarningsChecker(WarningsRecorder):
raise TypeError(msg % type(expected_warning)) raise TypeError(msg % type(expected_warning))
self.expected_warning = expected_warning self.expected_warning = expected_warning
self.match_expr = match_expr
def __exit__(self, *exc_info): def __exit__(self, *exc_info):
super(WarningsChecker, self).__exit__(*exc_info) super(WarningsChecker, self).__exit__(*exc_info)
@ -203,3 +208,15 @@ class WarningsChecker(WarningsRecorder):
"The list of emitted warnings is: {1}.".format( "The list of emitted warnings is: {1}.".format(
self.expected_warning, self.expected_warning,
[each.message for each in self])) [each.message for each in self]))
elif self.match_expr is not None:
for r in self:
if issubclass(r.category, self.expected_warning):
if re.compile(self.match_expr).search(str(r.message)):
break
else:
fail("DID NOT WARN. No warnings of type {0} matching"
" ('{1}') was emitted. The list of emitted warnings"
" is: {2}.".format(
self.expected_warning,
self.match_expr,
[each.message for each in self]))

View File

@ -289,20 +289,22 @@ class TestWarns(object):
with pytest.warns(UserWarning, match=r'must be \d+$'): with pytest.warns(UserWarning, match=r'must be \d+$'):
warnings.warn("value must be 42", UserWarning) warnings.warn("value must be 42", UserWarning)
with pytest.raises(AssertionError, match='pattern not found'): with pytest.raises(pytest.fail.Exception):
with pytest.warns(UserWarning, match=r'must be \d+$'): with pytest.warns(UserWarning, match=r'must be \d+$'):
warnings.warn("this is not here", UserWarning) warnings.warn("this is not here", UserWarning)
def test_one_from_multiple_warns(): with pytest.raises(pytest.fail.Exception):
with warns(UserWarning, match=r'aaa'): with pytest.warns(FutureWarning, match=r'must be \d+$'):
warnings.warn("value must be 42", UserWarning)
def test_one_from_multiple_warns(self):
with pytest.warns(UserWarning, match=r'aaa'):
warnings.warn("cccccccccc", UserWarning) warnings.warn("cccccccccc", UserWarning)
warnings.warn("bbbbbbbbbb", UserWarning) warnings.warn("bbbbbbbbbb", UserWarning)
warnings.warn("aaaaaaaaaa", UserWarning) warnings.warn("aaaaaaaaaa", UserWarning)
def test_none_of_multiple_warns(): def test_none_of_multiple_warns(self):
a, b, c = ('aaa', 'bbbbbbbbbb', 'cccccccccc') with pytest.raises(pytest.fail.Exception):
expected_msg = "'{}' pattern not found in \['{}', '{}'\]".format(a, b, c) with pytest.warns(UserWarning, match=r'aaa'):
with raises(AssertionError, match=expected_msg):
with warns(UserWarning, match=r'aaa'):
warnings.warn("bbbbbbbbbb", UserWarning) warnings.warn("bbbbbbbbbb", UserWarning)
warnings.warn("cccccccccc", UserWarning) warnings.warn("cccccccccc", UserWarning)