Description
The current behavior on the released pytest version is:
- if
match
fails,pytest.raises
raises anAssertionError
- if the type differs, the exception propagates through.
- if no exception was raised,
pytest.raises
raisespytest.Failed
#13192 complicated this for several reasons, and having RaisesGroup
adhere to point 2 was untenable. It became non-trivial to figure out why the "type" of an exceptiongroup with several nested exceptions and groups couldn't get matched against another group. It also became very weird when the "type" started to include matches itself, and it would've necessitated extra logic to figure out if RaisesGroup(RaisesExc(ValueError, match="foo"))
failed because of the type or the match in RaisesExc
. Or in even weirder cases where it fails for both reasons:
with RaisesGroup(RaisesExc(ValueError), RaisesExc(match="foo")):
raise ExceptionGroup(TypeError("bar"), TypeError("bar"))
So RaisesGroup
will raise an exception in all cases.
We're then faced with how this should affect pytest.raises
. #13192 made it raise an AssertionError
upon type difference (and if check
fails), but this would likely be considered a breaking change. I personally think it's very different if a test fails because I got a completely unexpected exception, versus a different exception than the one I specifically expected in a raises
block; but I don't think that's a huge win.
The other downside of keeping current behavior is it becoming an arbitrary-but-for-historic-reasons difference between raises
and RaisesGroup
.
In either case, the original exception is accessible in the __cause__
attribute and adapting code should be straightforward.
I do also find the distinction between raising pytest.Fail
versus AssertionError
quite arbitrary, and think they should be unified. My instinct would be for all failures to be pytest.Fail
, as AssertionError
usually signals to users that an explicit assert
has failed. We could make this change backward-compatible by having the exception raised inherit from both AssertionError
and pytest.Fail
if we really want to.
This also matters for ExceptionInfo.match
, which ideally should share logic with raises
for string matching - but currently doesn't. It currently raises an AssertionError
on failure.
tl;dr
- Should
raises
propagate the exception, or raiseAssertionError
, orFail
? - Is the distinction between raising different exception types useful, or confusing?
- Should
RaisesGroup
raisepytest.Fail
orAssertionError
when failing a match, regardless of reason?