-
-
Notifications
You must be signed in to change notification settings - Fork 368
Description
At work we have an internal AssertRaises
class which I'd like to kill it off in favor of the newer trio.testing.RaisesGroup
(added in #2898). However, it has one neat feature which we use fairly regularly to test exceptions arising specifically when exiting some (potentially async) context manager, often one which wraps a nursery:
with RaisesGroup(..., must_reach_point=True) as assert_raises:
async with some_async_context_manager:
...
assert_raises.must_reach_this_point()
# passes iff we raise the error on exit
Obviously it's an error to call .must_reach_this_point()
without specifying must_reach_point=True
or vice-versa, or to call it twice. If must_reach_point=True
then the RaisesGroup
should not catch or otherwise handle any exceptions raised before .must_reach_this_point()
is called.
You can currently implement something similar inline, with:
reached_point = False
with RaisesGroup(...) as excinfo:
async with some_async_context_manager:
...
reached_point = True
if not reached_point:
raise AssertionError("Raised expected exception, but never executed CM body") from excinfo.value
but a mere three lines of code each time adds up pretty quickly. I think the main effect of this is to change from checking the exception was raised at all to checking it was raised during exit, which seems pretty valuable to me.
A small downside is it may encourage too-widely-scoped with RaisesGroup
; in principle we could check at runtime that the .must_reach_this_point()
is inside a with
block which is itself inside the RaisesGroup
, but I don't think it's worth the trouble.