Add "ignore-case-handling" to exc unmasker
Since it turns out there's even case(s) in `trio` core that are guilty (of implementing things like checkpoints in exc handlers), this adds facility for ignoring explicit cases via `inspect.FrameInfo` field matching from the unmasked `exc_ctx` within `maybe_raise_from_masking_exc()`. Impl deats, - use `inspect.getinnerframes()/getmodule()` to extract the equivalent "guilty place in code" which raised the masked error which we'd like to ignore and **not unmask**. - start a `_mask_cases: dict` which describes the entries to ignore by matching against a specific `FrameInfo`'s fields from indexed from `getinnerframes()`. - describe in that table the case i hit with `trio.WouldBlock` being always masked by a `Cancelled` due to way `trio.Lock.acquire()` implements the blocking case in the would-block handler.. - always call into a new `is_expected_masking_case()` predicate (from `maybe_raise_from_masking_exc()`) on matching `exc_ctx` types.log_sys_testing
parent
93aa39db07
commit
e9f3689191
|
@ -22,6 +22,10 @@ from __future__ import annotations
|
||||||
from contextlib import (
|
from contextlib import (
|
||||||
asynccontextmanager as acm,
|
asynccontextmanager as acm,
|
||||||
)
|
)
|
||||||
|
import inspect
|
||||||
|
from types import (
|
||||||
|
TracebackType,
|
||||||
|
)
|
||||||
from typing import (
|
from typing import (
|
||||||
Type,
|
Type,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
|
@ -63,6 +67,66 @@ def find_masked_excs(
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
_mask_cases: dict[
|
||||||
|
Type[Exception], # masked exc type
|
||||||
|
dict[
|
||||||
|
int, # inner-frame index into `inspect.getinnerframes()`
|
||||||
|
# `FrameInfo.function/filename: str`s to match
|
||||||
|
tuple[str, str],
|
||||||
|
],
|
||||||
|
] = {
|
||||||
|
trio.WouldBlock: {
|
||||||
|
# `trio.Lock.acquire()` has a checkpoint inside the
|
||||||
|
# `WouldBlock`-no_wait path's handler..
|
||||||
|
-5: { # "5th frame up" from checkpoint
|
||||||
|
'filename': 'trio/_sync.py',
|
||||||
|
'function': 'acquire',
|
||||||
|
# 'lineno': 605, # matters?
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def is_expected_masking_case(
|
||||||
|
cases: dict,
|
||||||
|
exc_ctx: Exception,
|
||||||
|
exc_match: BaseException,
|
||||||
|
|
||||||
|
) -> bool|inspect.FrameInfo:
|
||||||
|
'''
|
||||||
|
Determine whether the provided masked exception is from a known
|
||||||
|
bug/special/unintentional-`trio`-impl case which we do not wish
|
||||||
|
to unmask.
|
||||||
|
|
||||||
|
Return any guilty `inspect.FrameInfo` ow `False`.
|
||||||
|
|
||||||
|
'''
|
||||||
|
exc_tb: TracebackType = exc_match.__traceback__
|
||||||
|
if cases := _mask_cases.get(type(exc_ctx)):
|
||||||
|
inner: list[inspect.FrameInfo] = inspect.getinnerframes(exc_tb)
|
||||||
|
|
||||||
|
# from tractor.devx.debug import mk_pdb
|
||||||
|
# mk_pdb().set_trace()
|
||||||
|
for iframe, matchon in cases.items():
|
||||||
|
try:
|
||||||
|
masker_frame: inspect.FrameInfo = inner[iframe]
|
||||||
|
except IndexError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for field, in_field in matchon.items():
|
||||||
|
val = getattr(
|
||||||
|
masker_frame,
|
||||||
|
field,
|
||||||
|
)
|
||||||
|
if in_field not in val:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return masker_frame
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# XXX, relevant discussion @ `trio`-core,
|
# XXX, relevant discussion @ `trio`-core,
|
||||||
# https://github.com/python-trio/trio/issues/455
|
# https://github.com/python-trio/trio/issues/455
|
||||||
#
|
#
|
||||||
|
@ -197,6 +261,24 @@ async def maybe_raise_from_masking_exc(
|
||||||
raise_unmasked
|
raise_unmasked
|
||||||
):
|
):
|
||||||
if len(masked) < 2:
|
if len(masked) < 2:
|
||||||
|
# don't unmask already known "special" cases..
|
||||||
|
if (
|
||||||
|
(cases := _mask_cases.get(type(exc_ctx)))
|
||||||
|
and
|
||||||
|
(masker_frame := is_expected_masking_case(
|
||||||
|
cases,
|
||||||
|
exc_ctx,
|
||||||
|
exc_match,
|
||||||
|
))
|
||||||
|
):
|
||||||
|
log.warning(
|
||||||
|
f'Ignoring already-known/non-ideally-valid masker code @\n'
|
||||||
|
f'{masker_frame}\n'
|
||||||
|
f'\n'
|
||||||
|
f'NOT raising {exc_ctx} from masker {exc_match!r}\n'
|
||||||
|
)
|
||||||
|
raise exc_match
|
||||||
|
|
||||||
raise exc_ctx from exc_match
|
raise exc_ctx from exc_match
|
||||||
|
|
||||||
# ??TODO, see above but, possibly unmasking sub-exc
|
# ??TODO, see above but, possibly unmasking sub-exc
|
||||||
|
|
Loading…
Reference in New Issue