forked from goodboy/tractor
Even smarter `RemoteActorError.pformat()`-ing
Related to the prior patch, re the new `with_type_header: bool`: - in the `with_type_header == True` use case make sure we keep the first `._message: str` line non-indented since it'll show just after the header-line's type path with ':'. - when `False` drop the `)>` `repr()`-instance style as well so that we just get the ascii boxed traceback as though it's the error message-`str` not the `repr()` of the error obj. Other, - hide `pack_from_raise()` call frame since it'll show in debug mode crash handling.. - mk `MsgTypeError.from_decode()` explicitly accept and proxy an optional `ipc_msg` and change `msgdict` to also be optional, only reading out the `**extra_msgdata` when provided. - expose a `_mk_msg_type_err(src_err_msg: Error|None = None,)` for callers who which to inject a `._ipc_msg: Msgtype` to the MTE. |_ add a note how we can't use it due to a causality-dilemma when pld validating `Started` on the send side..runtime_to_msgspec
parent
9ce958cb4a
commit
e4ec6b7b0c
|
@ -35,7 +35,6 @@ import trio
|
||||||
from msgspec import (
|
from msgspec import (
|
||||||
defstruct,
|
defstruct,
|
||||||
msgpack,
|
msgpack,
|
||||||
Raw,
|
|
||||||
structs,
|
structs,
|
||||||
ValidationError,
|
ValidationError,
|
||||||
)
|
)
|
||||||
|
@ -44,11 +43,12 @@ from tractor._state import current_actor
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
from tractor.msg import (
|
from tractor.msg import (
|
||||||
Error,
|
Error,
|
||||||
|
PayloadMsg,
|
||||||
MsgType,
|
MsgType,
|
||||||
Stop,
|
|
||||||
types as msgtypes,
|
|
||||||
MsgCodec,
|
MsgCodec,
|
||||||
MsgDec,
|
MsgDec,
|
||||||
|
Stop,
|
||||||
|
types as msgtypes,
|
||||||
)
|
)
|
||||||
from tractor.msg.pretty_struct import (
|
from tractor.msg.pretty_struct import (
|
||||||
iter_fields,
|
iter_fields,
|
||||||
|
@ -156,6 +156,7 @@ def pack_from_raise(
|
||||||
`Error`-msg using `pack_error()` to extract the tb info.
|
`Error`-msg using `pack_error()` to extract the tb info.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
__tracebackhide__: bool = True
|
||||||
try:
|
try:
|
||||||
raise local_err
|
raise local_err
|
||||||
except type(local_err) as local_err:
|
except type(local_err) as local_err:
|
||||||
|
@ -525,10 +526,26 @@ class RemoteActorError(Exception):
|
||||||
if not with_type_header:
|
if not with_type_header:
|
||||||
body = '\n' + body
|
body = '\n' + body
|
||||||
else:
|
else:
|
||||||
body: str = textwrap.indent(
|
first: str = ''
|
||||||
self._message,
|
message: str = self._message
|
||||||
|
|
||||||
|
# split off the first line so it isn't indented
|
||||||
|
# the same like the "boxed content".
|
||||||
|
if not with_type_header:
|
||||||
|
lines: list[str] = message.splitlines()
|
||||||
|
first = lines[0]
|
||||||
|
message = ''.join(lines[1:])
|
||||||
|
|
||||||
|
body: str = (
|
||||||
|
first
|
||||||
|
+
|
||||||
|
textwrap.indent(
|
||||||
|
message,
|
||||||
prefix=' ',
|
prefix=' ',
|
||||||
) + '\n'
|
)
|
||||||
|
+
|
||||||
|
'\n'
|
||||||
|
)
|
||||||
|
|
||||||
if with_type_header:
|
if with_type_header:
|
||||||
tail: str = ')>'
|
tail: str = ')>'
|
||||||
|
@ -734,25 +751,38 @@ class MsgTypeError(
|
||||||
def from_decode(
|
def from_decode(
|
||||||
cls,
|
cls,
|
||||||
message: str,
|
message: str,
|
||||||
msgdict: dict,
|
|
||||||
|
ipc_msg: PayloadMsg|None = None,
|
||||||
|
msgdict: dict|None = None,
|
||||||
|
|
||||||
) -> MsgTypeError:
|
) -> MsgTypeError:
|
||||||
return cls(
|
'''
|
||||||
message=message,
|
Constuctor for easy creation from (presumably) catching
|
||||||
boxed_type=cls,
|
the backend interchange lib's underlying validation error
|
||||||
|
and passing context-specific meta-data to `_mk_msg_type_err()`
|
||||||
|
(which is normally the caller of this).
|
||||||
|
|
||||||
# NOTE: original "vanilla decode" of the msg-bytes
|
'''
|
||||||
# is placed inside a value readable from
|
# if provided, expand and pack all RAE compat fields into the
|
||||||
# `.msgdata['_msg_dict']`
|
# `._extra_msgdata` auxillary data `dict` internal to
|
||||||
_msg_dict=msgdict,
|
# `RemoteActorError`.
|
||||||
|
extra_msgdata: dict = {}
|
||||||
# expand and pack all RAE compat fields
|
if msgdict:
|
||||||
# into the `._extra_msgdata` aux `dict`.
|
extra_msgdata: dict = {
|
||||||
**{
|
|
||||||
k: v
|
k: v
|
||||||
for k, v in msgdict.items()
|
for k, v in msgdict.items()
|
||||||
if k in _ipcmsg_keys
|
if k in _ipcmsg_keys
|
||||||
},
|
}
|
||||||
|
# NOTE: original "vanilla decode" of the msg-bytes
|
||||||
|
# is placed inside a value readable from
|
||||||
|
# `.msgdata['_msg_dict']`
|
||||||
|
extra_msgdata['_msg_dict'] = msgdict
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
message=message,
|
||||||
|
boxed_type=cls,
|
||||||
|
ipc_msg=ipc_msg,
|
||||||
|
**extra_msgdata,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1076,7 +1106,7 @@ _raise_from_no_key_in_msg = _raise_from_unexpected_msg
|
||||||
|
|
||||||
|
|
||||||
def _mk_msg_type_err(
|
def _mk_msg_type_err(
|
||||||
msg: Any|bytes|Raw,
|
msg: Any|bytes|MsgType,
|
||||||
codec: MsgCodec|MsgDec,
|
codec: MsgCodec|MsgDec,
|
||||||
|
|
||||||
message: str|None = None,
|
message: str|None = None,
|
||||||
|
@ -1085,6 +1115,7 @@ def _mk_msg_type_err(
|
||||||
src_validation_error: ValidationError|None = None,
|
src_validation_error: ValidationError|None = None,
|
||||||
src_type_error: TypeError|None = None,
|
src_type_error: TypeError|None = None,
|
||||||
is_invalid_payload: bool = False,
|
is_invalid_payload: bool = False,
|
||||||
|
src_err_msg: Error|None = None,
|
||||||
|
|
||||||
**mte_kwargs,
|
**mte_kwargs,
|
||||||
|
|
||||||
|
@ -1159,9 +1190,10 @@ def _mk_msg_type_err(
|
||||||
# only the payload being wrong?
|
# only the payload being wrong?
|
||||||
# -[ ] maybe the better design is to break this construct
|
# -[ ] maybe the better design is to break this construct
|
||||||
# logic into a separate explicit helper raiser-func?
|
# logic into a separate explicit helper raiser-func?
|
||||||
msg_dict: dict = {}
|
msg_dict = None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
msg: bytes
|
||||||
# decode the msg-bytes using the std msgpack
|
# decode the msg-bytes using the std msgpack
|
||||||
# interchange-prot (i.e. without any
|
# interchange-prot (i.e. without any
|
||||||
# `msgspec.Struct` handling) so that we can
|
# `msgspec.Struct` handling) so that we can
|
||||||
|
@ -1206,6 +1238,14 @@ def _mk_msg_type_err(
|
||||||
msgtyperr = MsgTypeError.from_decode(
|
msgtyperr = MsgTypeError.from_decode(
|
||||||
message=message,
|
message=message,
|
||||||
msgdict=msg_dict,
|
msgdict=msg_dict,
|
||||||
|
|
||||||
|
# NOTE: for the send-side `.started()` pld-validate
|
||||||
|
# case we actually set the `._ipc_msg` AFTER we return
|
||||||
|
# from here inside `Context.started()` since we actually
|
||||||
|
# want to emulate the `Error` from the mte we build here
|
||||||
|
# Bo
|
||||||
|
# so by default in that case this is set to `None`
|
||||||
|
ipc_msg=src_err_msg,
|
||||||
)
|
)
|
||||||
msgtyperr.__cause__ = src_validation_error
|
msgtyperr.__cause__ = src_validation_error
|
||||||
return msgtyperr
|
return msgtyperr
|
||||||
|
|
Loading…
Reference in New Issue