Skip to content

What should raises and RaisesGroup raise? #13286

Open
@jakkdl

Description

@jakkdl

The current behavior on the released pytest version is:

  1. if match fails, pytest.raises raises an AssertionError
  2. if the type differs, the exception propagates through.
  3. if no exception was raised, pytest.raises raises pytest.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

  1. Should raises propagate the exception, or raise AssertionError, or Fail?
  2. Is the distinction between raising different exception types useful, or confusing?
  3. Should RaisesGroup raise pytest.Fail or AssertionError when failing a match, regardless of reason?

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: reportingrelated to terminal output and user-facing messages and errorstype: backward compatibilitymight present some backward compatibility issues which should be carefully noted in the changelog

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions