-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
add matching the error message to pytest.raises #2227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This PR should go to the |
Sorry about that - I changed it as requested. |
No worries! You'll also need to change the changelog to add this to a Looking at https://travis-ci.org/pytest-dev/pytest/jobs/197286855#L214 I also think you should use LGTM otherwise from a quick look, but I'm a bit in a hurry currently. |
3bca688
to
cfb7bec
Compare
fixed & fixed 😄 |
Thanks for the PR! But I believe we already have similar functionality with excinfo.match (sorry I can't provide a link now because I'm on my phone) |
@nicoddemus would it make sense to make "with raises(..., match=...)" a shortcut for the turnaround? |
IMHO it does not add much... that would be two ways to accomplish the same thing with little gain. For now I'm -0 on the idea. |
But by all means if other people think this is a good idea we should move this forward, of course, |
We use these kind of assertions quite a lot - IMHO, a declarative "we expect this error with this message" style would be a bit nicer than the current with pytest.raises(ValueError) as excinfo:
myfunc()
excinfo.match(r'.* 123 .*') construct where our expectations about the error object are split before and after the statement. It might just be me, but I'm always slightly irritated by using |
im +1 on having match as kwarg and encouraging its usage over exceptioninfo |
@mhils thanks for the feedback, appreciate it! @RonnyPfannschmidt OK then, let's go ahead with it. 👍 I would just suggest to call the keyword argument with pytest.raises(ValueError, match=r'.* 123 .*'):
myfunc() |
At the moment this PR only does substring matching |
I think so, mostly to be consistent with |
@Kriechi also, it would be nice if you could review the relevant documentation and change the examples to use the new |
bc904f0
to
9377784
Compare
testing/python/raises.py
Outdated
int('asdf') | ||
|
||
msg = "with base 16" | ||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for mind-bending fun we could nest pytest.rasies here 🤣
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well done, good work :)
_pytest/python.py
Outdated
@@ -1246,6 +1260,11 @@ def __exit__(self, *tp): | |||
suppress_exception = issubclass(self.excinfo.type, self.expected_exception) | |||
if sys.version_info[0] == 2 and suppress_exception: | |||
sys.exc_clear() | |||
if self.match_expr: | |||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this bare try/except makes me a little uneasy... why is it needed? Wouldn't be enough to just call self.excinfo.match(self.match_expr)
?
if self.match_expr:
self.excinfo.match(self.match_expr)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure how to handle this properly, because ExceptionInfo.match
raises an AssertionError if no match is found, but we want to call pytest.fail
in that case...
Is there a better way of handling this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think just calling self.excinfo.match
should be enough, as this will produce the same behavior as:
with pytest.raises(...) as excinfo:
func()
excinfo.match(text)
Or am I missing something?
I guess one issue in that case is that the traceback will point to pytest's internals, but to prevent that we just need to declare a __tracebackhide__
variable:
__tracebackhide__ = True
if self.match_expr:
self.excinfo.match(self.match_expr)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. The __tracebackhide__
is already there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks! 👍
CHANGELOG.rst
Outdated
@@ -13,6 +13,9 @@ New Features | |||
* ``pytest.warns`` now checks for subclass relationship rather than | |||
class equality. Thanks `@lesteve`_ for the PR (`#2166`_) | |||
|
|||
* ``pytest.raises`` now asserts that the error message matches a text or regex | |||
with the `match` keyword argument. Thanks `@Kriechi`_ for the PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nitpick, but "match" should be surrounded by double back ticks to get a monospaced font, like you did with "pytest.raises"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks - fixed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Kriechi for the patience and following through with the PR! 👍
I will merge as soon as CI passes!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how this turned out, definitely also prefer this more declaritive/simple API! Just a simple fix for Python 2.6 left, LGTM otherwise.
testing/python/raises.py
Outdated
int('asdf') | ||
|
||
msg = "with base 16" | ||
expr = r"Pattern '{}' not found in 'invalid literal for int\(\) with base 10: 'asdf''".format(msg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be {0}
for Python 2.6 compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, pushed a quick fix. 👍
oh, right - I always forget about that "maintainers can push too" feature 😄 |
the py26 env broke due to a zero-length format spec |
whops, reload lag, sorry |
pytest.raises
can now assert that the error message contains a certain text.Example:
This is a more compact and IMHO cleaner way of doing it like this: