Tweak some `pformat_boxed_tb()` indent inputs

- add some `tb_str: str` indent-prefix args for diff indent levels for the
body vs. the surrounding "ascii box".
- ^-use it-^ from `RemoteActorError.__repr()__` obvi.
- use new `msg.types.from_dict_msg()` in impl of
  `MsgTypeError.payload_msg`, handy for showing what the message "would
  have looked like in `Struct` form" had it not failed it's type
  constraints.
runtime_to_msgspec
Tyler Goodlet 2024-04-11 21:24:02 -04:00
parent 322e015d32
commit eec240a70a
1 changed files with 45 additions and 28 deletions

View File

@ -40,7 +40,7 @@ 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,
Msg, MsgType,
Stop, Stop,
Yield, Yield,
pretty_struct, pretty_struct,
@ -130,7 +130,10 @@ def pformat_boxed_tb(
tb_str: str, tb_str: str,
fields_str: str|None = None, fields_str: str|None = None,
field_prefix: str = ' |_', field_prefix: str = ' |_',
indent: str = ' '*2
tb_box_indent: int|None = None,
tb_body_indent: int = 1,
) -> str: ) -> str:
if ( if (
fields_str fields_str
@ -139,15 +142,19 @@ def pformat_boxed_tb(
): ):
fields: str = textwrap.indent( fields: str = textwrap.indent(
fields_str, fields_str,
# prefix=' '*2,
# prefix=' |_',
prefix=field_prefix, prefix=field_prefix,
) )
else: else:
fields = fields_str or '' fields = fields_str or ''
# body_indent: str = len(field_prefix) * ' ' tb_body = tb_str
body: str = ( if tb_body_indent:
tb_body: str = textwrap.indent(
tb_str,
prefix=tb_body_indent * ' ',
)
tb_box: str = (
# orig # orig
# f' |\n' # f' |\n'
@ -158,21 +165,29 @@ def pformat_boxed_tb(
f'|\n' f'|\n'
f' ------ - ------\n\n' f' ------ - ------\n\n'
f'{tb_str}\n' # f'{tb_str}\n'
f'{tb_body}'
f' ------ - ------\n' f' ------ - ------\n'
f'_|\n' f'_|\n'
) )
if len(indent): tb_box_indent: str = (
body: str = textwrap.indent( tb_box_indent
body, or
# prefix=body_indent, 1
prefix=indent,
# (len(field_prefix))
# ? ^-TODO-^ ? if you wanted another indent level
)
if tb_box_indent > 0:
tb_box: str = textwrap.indent(
tb_box,
prefix=tb_box_indent * ' ',
) )
return ( return (
fields fields
+ +
body tb_box
) )
@ -316,7 +331,7 @@ class RemoteActorError(Exception):
if self._ipc_msg is None: if self._ipc_msg is None:
return None return None
msg_type: Msg = type(self._ipc_msg) msg_type: MsgType = type(self._ipc_msg)
fields: dict[str, Any] = { fields: dict[str, Any] = {
k: v for _, k, v in k: v for _, k, v in
pretty_struct.iter_fields(self._ipc_msg) pretty_struct.iter_fields(self._ipc_msg)
@ -493,7 +508,10 @@ class RemoteActorError(Exception):
tb_str=self.tb_str, tb_str=self.tb_str,
fields_str=fields, fields_str=fields,
field_prefix=' |_', field_prefix=' |_',
indent=' ', # no indent? # ^- is so that it's placed like so,
# just after <Type(
# |___ ..
tb_body_indent=1,
) )
return ( return (
f'<{type(self).__name__}(\n' f'<{type(self).__name__}(\n'
@ -623,7 +641,7 @@ class MsgTypeError(
''' '''
reprol_fields: list[str] = [ reprol_fields: list[str] = [
'ipc_msg', 'payload_msg',
] ]
extra_body_fields: list[str] = [ extra_body_fields: list[str] = [
'cid', 'cid',
@ -633,7 +651,7 @@ class MsgTypeError(
@property @property
def msg_dict(self) -> dict[str, Any]: def msg_dict(self) -> dict[str, Any]:
''' '''
If the underlying IPC `Msg` was received from a remote If the underlying IPC `MsgType` was received from a remote
actor but was unable to be decoded to a native actor but was unable to be decoded to a native
`Yield`|`Started`|`Return` struct, the interchange backend `Yield`|`Started`|`Return` struct, the interchange backend
native format decoder can be used to stash a `dict` native format decoder can be used to stash a `dict`
@ -643,22 +661,21 @@ class MsgTypeError(
return self.msgdata.get('_msg_dict') return self.msgdata.get('_msg_dict')
@property @property
def payload_msg(self) -> Msg|None: def payload_msg(
self,
) -> MsgType|None:
''' '''
Attempt to construct what would have been the original Attempt to construct what would have been the original
`Msg`-with-payload subtype (i.e. an instance from the set `MsgType`-with-payload subtype (i.e. an instance from the set
of msgs in `.msg.types._payload_msgs`) which failed of msgs in `.msg.types._payload_msgs`) which failed
validation. validation.
''' '''
msg_dict: dict = self.msg_dict.copy() if msg_dict := self.msg_dict.copy():
name: str = msg_dict.pop('msg_type') return msgtypes.from_dict_msg(
msg_type: Msg = getattr( dict_msg=msg_dict,
msgtypes, )
name, return None
Msg,
)
return msg_type(**msg_dict)
@property @property
def cid(self) -> str: def cid(self) -> str:
@ -908,7 +925,7 @@ def is_multi_cancelled(exc: BaseException) -> bool:
def _raise_from_no_key_in_msg( def _raise_from_no_key_in_msg(
ctx: Context, ctx: Context,
msg: Msg, msg: MsgType,
src_err: KeyError, src_err: KeyError,
log: StackLevelAdapter, # caller specific `log` obj log: StackLevelAdapter, # caller specific `log` obj