Skip to content

Commit

Permalink
add matching the error message to pytest.raises
Browse files Browse the repository at this point in the history
  • Loading branch information
Kriechi committed Feb 1, 2017
1 parent 0931fe2 commit 06fae84
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 3 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
3.0.7 (unreleased)
=======================

*
* ``pytest.raises`` can now assert that the error message contains a certain text.
Thanks `@Kriechi`_ for the PR.

*

Expand All @@ -10,6 +11,9 @@
*


.. _@Kriechi: https://github.com/Kriechi


3.0.6 (2017-01-22)
==================

Expand Down
17 changes: 15 additions & 2 deletions _pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,12 @@ def raises(expected_exception, *args, **kwargs):
...
>>> assert str(exc_info.value) == "value must be <= 10"
Or you can use the keyword argument ``match_info`` to assert that the
exception contains a certain text::
>>> with raises(ValueError, match_info='must be 0'):
.... if value != 0:
.... raise ValueError("value must be 0 or None")
Or you can specify a callable by passing a to-be-called lambda::
Expand Down Expand Up @@ -1191,11 +1197,15 @@ def raises(expected_exception, *args, **kwargs):
raise TypeError(msg % type(expected_exception))

message = "DID NOT RAISE {0}".format(expected_exception)
match_info = None

if not args:
if "message" in kwargs:
message = kwargs.pop("message")
return RaisesContext(expected_exception, message)
if "match_info" in kwargs:
match_info = kwargs.pop("match_info")
message += " with text '{0}'".format(match_info)
return RaisesContext(expected_exception, message, match_info)
elif isinstance(args[0], str):
code, = args
assert isinstance(code, str)
Expand All @@ -1219,9 +1229,10 @@ def raises(expected_exception, *args, **kwargs):
pytest.fail(message)

class RaisesContext(object):
def __init__(self, expected_exception, message):
def __init__(self, expected_exception, message, match_info):
self.expected_exception = expected_exception
self.message = message
self.match_info = match_info
self.excinfo = None

def __enter__(self):
Expand All @@ -1240,6 +1251,8 @@ def __exit__(self, *tp):
exc_type, value, traceback = tp
tp = exc_type, exc_type(value), traceback
self.excinfo.__init__(tp)
if self.match_info and not self.match_info.lower() in str(self.excinfo).lower():
pytest.fail(self.message)
suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
if sys.version_info[0] == 2 and suppress_exception:
sys.exc_clear()
Expand Down
13 changes: 13 additions & 0 deletions testing/python/raises.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,16 @@ def __call__(self):
for o in gc.get_objects():
assert type(o) is not T


def test_raises_match_info(self):
msg = "with base 10"
with pytest.raises(ValueError, match_info=msg):
int('asdf')

try:
with pytest.raises(ValueError, match_info=msg):
int('asdf', base=16)
except pytest.raises.Exception as e:
assert e.msg == "DID NOT RAISE {0} with text '{1}'".format(repr(ValueError), msg)
else:
assert False, "Expected pytest.raises.Exception"

0 comments on commit 06fae84

Please sign in to comment.