Skip to content

Commit ab6c9bd

Browse files
authored
Merge pull request #3145 from jakkdl/raisesgroup_fail_reason
Add reason for failed match to RaisesGroup
2 parents 235bc2e + 8cb294f commit ab6c9bd

File tree

7 files changed

+1304
-162
lines changed

7 files changed

+1304
-162
lines changed

docs/source/reference-testing.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,12 @@ ExceptionGroup helpers
231231
.. autoclass:: RaisesGroup
232232
:members:
233233

234+
.. autoattribute:: fail_reason
235+
234236
.. autoclass:: Matcher
235237
:members:
236238

239+
.. autoattribute:: fail_reason
240+
237241
.. autoclass:: trio.testing._raises_group._ExceptionInfo
238242
:members:

newsfragments/3145.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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.

src/trio/_core/_run.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
PosArgT = TypeVarTuple("PosArgT")
7777
StatusT = TypeVar("StatusT", default=None)
7878
StatusT_contra = TypeVar("StatusT_contra", contravariant=True, default=None)
79+
BaseExcT = TypeVar("BaseExcT", bound=BaseException)
7980
else:
8081
from typing import TypeVar
8182

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

127+
# monkeypatch repr_callable to make repr's way better
128+
# requires importing hypothesis (in the test file or in conftest.py)
129+
try:
130+
from hypothesis.internal.reflection import get_pretty_function_description
131+
132+
import trio.testing._raises_group
133+
134+
def repr_callable(fun: Callable[[BaseExcT], bool]) -> str:
135+
# add quotes around the signature
136+
return repr(get_pretty_function_description(fun))
137+
138+
trio.testing._raises_group.repr_callable = repr_callable
139+
except ImportError:
140+
pass
141+
126142

127143
def _count_context_run_tb_frames() -> int:
128144
"""Count implementation dependent traceback frames from Context.run()

src/trio/_tests/test_exports.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,11 @@ def lookup_symbol(symbol: str) -> dict[str, str]:
318318
if module_name == "trio.socket" and class_name in dir(stdlib_socket):
319319
continue
320320

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

325328
# dir() and inspect.getmembers doesn't display properties from the metaclass
@@ -460,11 +463,6 @@ def lookup_symbol(symbol: str) -> dict[str, str]:
460463
"send_all_hook",
461464
"wait_send_all_might_not_block_hook",
462465
},
463-
trio.testing.Matcher: {
464-
"exception_type",
465-
"match",
466-
"check",
467-
},
468466
}
469467
if tool == "mypy" and class_ in EXTRAS:
470468
before = len(extra)

0 commit comments

Comments
 (0)