Accept err-type override in `is_multi_cancelled()`
Such that equivalents of `trio.Cancelled` from other runtimes such as `asyncio.CancelledError` and `subprocess.CalledProcessError` (with a `.returncode == -2`) can be gracefully ignored as needed by the caller. For example this is handy if you want to avoid debug-mode REPL entry on an exception-group full of only some subset of exception types since you expect certain tasks to raise such errors after having been cancelled by a request from some parent supervision sys (some "higher up" `trio.CancelScope`, a remote triggered `ContextCancelled` or just from and OS SIGINT). Impl deats, - offer a new `ignore_nested: set[BaseException]` param which by default we add `trio.Cancelled` to when no other types are provided. - use `ExceptionGroup.subgroup(tuple(ignore_nested)` to filter to egs of the "ignored sub-errors set" and return any such match (instead of `True`). - detail a comment on exclusion case.hilevel_serman
parent
0945631629
commit
350a94f39e
|
@ -1146,19 +1146,51 @@ def unpack_error(
|
|||
|
||||
|
||||
def is_multi_cancelled(
|
||||
exc: BaseException|BaseExceptionGroup
|
||||
) -> bool:
|
||||
exc: BaseException|BaseExceptionGroup,
|
||||
|
||||
ignore_nested: set[BaseException] = set(),
|
||||
|
||||
) -> bool|BaseExceptionGroup:
|
||||
'''
|
||||
Predicate to determine if a possible ``BaseExceptionGroup`` contains
|
||||
only ``trio.Cancelled`` sub-exceptions (and is likely the result of
|
||||
cancelling a collection of subtasks.
|
||||
Predicate to determine if an `BaseExceptionGroup` only contains
|
||||
some (maybe nested) set of sub-grouped exceptions (like only
|
||||
`trio.Cancelled`s which get swallowed silently by default) and is
|
||||
thus the result of "gracefully cancelling" a collection of
|
||||
sub-tasks (or other conc primitives) and receiving a "cancelled
|
||||
ACK" from each after termination.
|
||||
|
||||
Docs:
|
||||
----
|
||||
- https://docs.python.org/3/library/exceptions.html#exception-groups
|
||||
- https://docs.python.org/3/library/exceptions.html#BaseExceptionGroup.subgroup
|
||||
|
||||
'''
|
||||
|
||||
if (
|
||||
not ignore_nested
|
||||
or
|
||||
trio.Cancelled in ignore_nested
|
||||
# XXX always count-in `trio`'s native signal
|
||||
):
|
||||
ignore_nested |= {trio.Cancelled}
|
||||
|
||||
if isinstance(exc, BaseExceptionGroup):
|
||||
return exc.subgroup(
|
||||
lambda exc: isinstance(exc, trio.Cancelled)
|
||||
) is not None
|
||||
matched_exc: BaseExceptionGroup|None = exc.subgroup(
|
||||
tuple(ignore_nested),
|
||||
|
||||
# TODO, complain about why not allowed XD
|
||||
# condition=tuple(ignore_nested),
|
||||
)
|
||||
if matched_exc is not None:
|
||||
return matched_exc
|
||||
|
||||
# NOTE, IFF no excs types match (throughout the error-tree)
|
||||
# -> return `False`, OW return the matched sub-eg.
|
||||
#
|
||||
# IOW, for the inverse of ^ for the purpose of
|
||||
# maybe-enter-REPL--logic: "only debug when the err-tree contains
|
||||
# at least one exc-type NOT in `ignore_nested`" ; i.e. the case where
|
||||
# we fallthrough and return `False` here.
|
||||
return False
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue