Skip to content

Commit 909d72b

Browse files
committed
Merge pull request #1502 from omarkohl/excinfo_match
Implement ExceptionInfo.match() method
2 parents fed89ef + 0c38aac commit 909d72b

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Michael Birtwell
6969
Michael Droettboom
7070
Mike Lundy
7171
Nicolas Delaby
72+
Omar Kohl
7273
Pieter Mulder
7374
Piotr Banaszkiewicz
7475
Punyashloka Biswal

CHANGELOG.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
* New Add ability to add global properties in the final xunit output file.
1919
Thanks `@tareqalayan`_ for the complete PR `#1454`_).
2020

21+
* New ``ExceptionInfo.match()`` method to match a regular expression on the
22+
string representation of an exception. Closes proposal `#372`_.
23+
Thanks `@omarkohl`_ for the complete PR (`#1502`_) and `@nicoddemus`_ for the
24+
implementation tips.
2125

2226
*
2327

@@ -38,13 +42,16 @@
3842
.. _@kalekundert: https://github.com/kalekundert
3943
.. _@tareqalayan: https://github.com/tareqalayan
4044
.. _@palaviv: https://github.com/palaviv
45+
.. _@omarkohl: https://github.com/omarkohl
4146

4247
.. _#1428: https://github.com/pytest-dev/pytest/pull/1428
4348
.. _#1444: https://github.com/pytest-dev/pytest/pull/1444
4449
.. _#1441: https://github.com/pytest-dev/pytest/pull/1441
4550
.. _#1454: https://github.com/pytest-dev/pytest/pull/1454
4651
.. _#1468: https://github.com/pytest-dev/pytest/pull/1468
4752
.. _#1474: https://github.com/pytest-dev/pytest/pull/1474
53+
.. _#1502: https://github.com/pytest-dev/pytest/pull/1502
54+
.. _#372: https://github.com/pytest-dev/pytest/issues/372
4855

4956

5057
2.9.2.dev1

_pytest/_code/code.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
from inspect import CO_VARARGS, CO_VARKEYWORDS
3+
import re
34

45
import py
56

@@ -427,6 +428,19 @@ def __unicode__(self):
427428
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
428429
return unicode(loc)
429430

431+
def match(self, regexp):
432+
"""
433+
Match the regular expression 'regexp' on the string representation of
434+
the exception. If it matches then True is returned (so that it is
435+
possible to write 'assert excinfo.match()'). If it doesn't match an
436+
AssertionError is raised.
437+
"""
438+
__tracebackhide__ = True
439+
if not re.search(regexp, str(self.value)):
440+
assert 0, "Pattern '{0!s}' not found in '{1!s}'".format(
441+
regexp, self.value)
442+
return True
443+
430444

431445
class FormattedExcinfo(object):
432446
""" presenting information about failing Functions and Generators. """

doc/en/assert.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,24 @@ exceptions your own code is deliberately raising, whereas using
110110
like documenting unfixed bugs (where the test describes what "should" happen)
111111
or bugs in dependencies.
112112

113+
If you want to test that a regular expression matches on the string
114+
representation of an exception (like the ``TestCase.assertRaisesRegexp`` method
115+
from ``unittest``) you can use the ``ExceptionInfo.match`` method::
116+
117+
import pytest
118+
119+
def myfunc():
120+
raise ValueError("Exception 123 raised")
121+
122+
def test_match():
123+
with pytest.raises(ValueError) as excinfo:
124+
myfunc()
125+
excinfo.match(r'.* 123 .*')
126+
127+
The regexp parameter of the ``match`` method is matched with the ``re.search``
128+
function. So in the above example ``excinfo.match('123')`` would have worked as
129+
well.
130+
113131

114132
.. _`assertwarns`:
115133

testing/code/test_excinfo.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,25 @@ def test_codepath_Queue_example():
323323
assert path.basename.lower() == "queue.py"
324324
assert path.check()
325325

326+
def test_match_succeeds():
327+
with pytest.raises(ZeroDivisionError) as excinfo:
328+
0 / 0
329+
excinfo.match(r'.*zero.*')
330+
331+
def test_match_raises_error(testdir):
332+
testdir.makepyfile("""
333+
import pytest
334+
def test_division_zero():
335+
with pytest.raises(ZeroDivisionError) as excinfo:
336+
0 / 0
337+
excinfo.match(r'[123]+')
338+
""")
339+
result = testdir.runpytest()
340+
assert result.ret != 0
341+
result.stdout.fnmatch_lines([
342+
"*AssertionError*Pattern*[123]*not found*",
343+
])
344+
326345
class TestFormattedExcinfo:
327346
def pytest_funcarg__importasmod(self, request):
328347
def importasmod(source):

0 commit comments

Comments
 (0)