Skip to content

Commit

Permalink
Merge pull request #3145 from jakkdl/raisesgroup_fail_reason
Browse files Browse the repository at this point in the history
Add reason for failed match to RaisesGroup
  • Loading branch information
jakkdl authored Jan 29, 2025
2 parents 235bc2e + 8cb294f commit ab6c9bd
Show file tree
Hide file tree
Showing 7 changed files with 1,304 additions and 162 deletions.
4 changes: 4 additions & 0 deletions docs/source/reference-testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,12 @@ ExceptionGroup helpers
.. autoclass:: RaisesGroup
:members:

.. autoattribute:: fail_reason

.. autoclass:: Matcher
:members:

.. autoattribute:: fail_reason

.. autoclass:: trio.testing._raises_group._ExceptionInfo
:members:
1 change: 1 addition & 0 deletions newsfragments/3145.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
If `trio.testing.RaisesGroup` does not get the expected exceptions it now raises an `AssertionError` with a helpful message, instead of letting the raised exception/group fall through. The raised exception is available in the ``__context__`` of the `AssertionError` and can be seen in the traceback.
16 changes: 16 additions & 0 deletions src/trio/_core/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
PosArgT = TypeVarTuple("PosArgT")
StatusT = TypeVar("StatusT", default=None)
StatusT_contra = TypeVar("StatusT_contra", contravariant=True, default=None)
BaseExcT = TypeVar("BaseExcT", bound=BaseException)
else:
from typing import TypeVar

Expand Down Expand Up @@ -123,6 +124,21 @@ def _hypothesis_plugin_setup() -> None: # pragma: no cover
_ALLOW_DETERMINISTIC_SCHEDULING = True # type: ignore
register_random(_r)

# monkeypatch repr_callable to make repr's way better
# requires importing hypothesis (in the test file or in conftest.py)
try:
from hypothesis.internal.reflection import get_pretty_function_description

import trio.testing._raises_group

def repr_callable(fun: Callable[[BaseExcT], bool]) -> str:
# add quotes around the signature
return repr(get_pretty_function_description(fun))

trio.testing._raises_group.repr_callable = repr_callable
except ImportError:
pass


def _count_context_run_tb_frames() -> int:
"""Count implementation dependent traceback frames from Context.run()
Expand Down
12 changes: 5 additions & 7 deletions src/trio/_tests/test_exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,11 @@ def lookup_symbol(symbol: str) -> dict[str, str]:
if module_name == "trio.socket" and class_name in dir(stdlib_socket):
continue

# ignore class that does dirty tricks
if class_ is trio.testing.RaisesGroup:
# Ignore classes that don't use attrs, they only define their members once
# __init__ is called (and reason they don't use attrs is because they're going
# to be reimplemented in pytest).
# Not 100% that's the case, and it works locally, so whatever /shrug
if class_ is trio.testing.RaisesGroup or class_ is trio.testing.Matcher:
continue

# dir() and inspect.getmembers doesn't display properties from the metaclass
Expand Down Expand Up @@ -460,11 +463,6 @@ def lookup_symbol(symbol: str) -> dict[str, str]:
"send_all_hook",
"wait_send_all_might_not_block_hook",
},
trio.testing.Matcher: {
"exception_type",
"match",
"check",
},
}
if tool == "mypy" and class_ in EXTRAS:
before = len(extra)
Expand Down
Loading

0 comments on commit ab6c9bd

Please sign in to comment.