`._exceptions`: typing and error unpacking updates

Bump type annotations to 3.10+ style throughout module as well as fill
out doc strings a bit. Inside `unpack_error()` pop any `error_dict: dict`
and,
- return `None` early if not found,
- versus pass directly as `**error_dict` to the error constructor
  instead of a double field read.
multihomed
Tyler Goodlet 2023-10-16 16:23:30 -04:00
parent ab2664da70
commit e4a6223256
1 changed files with 35 additions and 18 deletions

View File

@ -113,18 +113,24 @@ class AsyncioCancelled(Exception):
def pack_error( def pack_error(
exc: BaseException, exc: BaseException,
tb=None, tb: str | None = None,
) -> dict[str, Any]: ) -> dict[str, dict]:
"""Create an "error message" for tranmission over '''
a channel (aka the wire). Create an "error message" encoded for wire transport via an IPC
""" `Channel`; expected to be unpacked on the receiver side using
`unpack_error()` below.
'''
if tb: if tb:
tb_str = ''.join(traceback.format_tb(tb)) tb_str = ''.join(traceback.format_tb(tb))
else: else:
tb_str = traceback.format_exc() tb_str = traceback.format_exc()
error_msg = { error_msg: dict[
str,
str | tuple[str, str]
] = {
'tb_str': tb_str, 'tb_str': tb_str,
'type_str': type(exc).__name__, 'type_str': type(exc).__name__,
'src_actor_uid': current_actor().uid, 'src_actor_uid': current_actor().uid,
@ -142,18 +148,28 @@ def unpack_error(
chan=None, chan=None,
err_type=RemoteActorError err_type=RemoteActorError
) -> Exception: ) -> None | Exception:
''' '''
Unpack an 'error' message from the wire Unpack an 'error' message from the wire
into a local ``RemoteActorError``. into a local `RemoteActorError` (subtype).
NOTE: this routine DOES not RAISE the embedded remote error,
which is the responsibilitiy of the caller.
''' '''
__tracebackhide__ = True __tracebackhide__: bool = True
error = msg['error']
tb_str = error.get('tb_str', '') error_dict: dict[str, dict] | None
message = f'{chan.uid}\n' + tb_str if (
type_name = error['type_str'] error_dict := msg.get('error')
) is None:
# no error field, nothing to unpack.
return None
# retrieve the remote error's msg encoded details
tb_str: str = error_dict.get('tb_str', '')
message: str = f'{chan.uid}\n' + tb_str
type_name: str = error_dict['type_str']
suberror_type: Type[BaseException] = Exception suberror_type: Type[BaseException] = Exception
if type_name == 'ContextCancelled': if type_name == 'ContextCancelled':
@ -167,18 +183,19 @@ def unpack_error(
eg, eg,
trio, trio,
]: ]:
try: if suberror_type := getattr(
suberror_type = getattr(ns, type_name) ns,
type_name,
False,
):
break break
except AttributeError:
continue
exc = err_type( exc = err_type(
message, message,
suberror_type=suberror_type, suberror_type=suberror_type,
# unpack other fields into error type init # unpack other fields into error type init
**msg['error'], **error_dict,
) )
return exc return exc