Expose `MsgType` and extend `MsgCodec` API a bit
Make a new `MsgType: TypeAlias` for the union of all msg types such that it can be used in annots throughout the code base; just make `.msg.__msg_spec__` delegate to it. Add some new codec methods: - `pld_spec_str`: for the `str`-casted value of the payload spec, generally useful in logging content. - `msg_spec_items()`: to render a `dict` of msg types to their `str()`-casted values with support for singling out a specific `MsgType`, type by input `msg` instance. - `pformat_msg_spec()`: for rendering the (partial) `.msg_spec` as a formatted `str` useful in logging. Oh right, add a `Error._msg_dict: dict` in support of the previous commit (for `MsgTypeError` packing as RAEs) such that our error msg type can house a non-type-spec decoded wire-bytes for error reporting/analysis purposes.runtime_to_msgspec
parent
cf48fdecfe
commit
15549f7c26
|
@ -19,7 +19,6 @@ Built-in messaging patterns, types, APIs and helpers.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
from typing import (
|
from typing import (
|
||||||
Union,
|
|
||||||
TypeAlias,
|
TypeAlias,
|
||||||
)
|
)
|
||||||
from .ptr import (
|
from .ptr import (
|
||||||
|
@ -56,8 +55,9 @@ from .types import (
|
||||||
|
|
||||||
# full msg class set from above as list
|
# full msg class set from above as list
|
||||||
__msg_types__ as __msg_types__,
|
__msg_types__ as __msg_types__,
|
||||||
|
|
||||||
|
# type-alias for union of all msgs
|
||||||
|
MsgType as MsgType,
|
||||||
)
|
)
|
||||||
# TODO: use new type declaration syntax for msg-type-spec
|
|
||||||
# https://docs.python.org/3/library/typing.html#type-aliases
|
__msg_spec__: TypeAlias = MsgType
|
||||||
# https://docs.python.org/3/reference/simple_stmts.html#type
|
|
||||||
__msg_spec__: TypeAlias = Union[*__msg_types__]
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ from trio.lowlevel import (
|
||||||
from tractor.msg.pretty_struct import Struct
|
from tractor.msg.pretty_struct import Struct
|
||||||
from tractor.msg.types import (
|
from tractor.msg.types import (
|
||||||
mk_msg_spec,
|
mk_msg_spec,
|
||||||
Msg,
|
MsgType,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,12 +87,50 @@ class MsgCodec(Struct):
|
||||||
|
|
||||||
pld_spec: Union[Type[Struct]]|None
|
pld_spec: Union[Type[Struct]]|None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pld_spec_str(self) -> str:
|
||||||
|
spec: Union[Type]|Type = self.pld_spec
|
||||||
|
|
||||||
|
# TODO: could also use match: instead?
|
||||||
|
if getattr(spec, '__args__', False):
|
||||||
|
# `typing.Union` case
|
||||||
|
return str(spec)
|
||||||
|
else:
|
||||||
|
return spec.__name__
|
||||||
|
|
||||||
# struct type unions
|
# struct type unions
|
||||||
# https://jcristharif.com/msgspec/structs.html#tagged-unions
|
# https://jcristharif.com/msgspec/structs.html#tagged-unions
|
||||||
@property
|
@property
|
||||||
def msg_spec(self) -> Union[Type[Struct]]:
|
def msg_spec(self) -> Union[Type[Struct]]:
|
||||||
return self._dec.type
|
return self._dec.type
|
||||||
|
|
||||||
|
def msg_spec_items(
|
||||||
|
self,
|
||||||
|
msg: MsgType|None = None,
|
||||||
|
|
||||||
|
) -> dict[str, MsgType]|str:
|
||||||
|
|
||||||
|
msgt_table: dict[str, MsgType] = {
|
||||||
|
msgt: str(msgt)
|
||||||
|
for msgt in self.msg_spec.__args__
|
||||||
|
}
|
||||||
|
if msg:
|
||||||
|
msgt: MsgType = type(msg)
|
||||||
|
str_repr: str = msgt_table[msgt]
|
||||||
|
return {msgt: str_repr}
|
||||||
|
|
||||||
|
return msgt_table
|
||||||
|
|
||||||
|
# TODO: some way to make `pretty_struct.Struct` use this
|
||||||
|
# wrapped field over the `.msg_spec` one?
|
||||||
|
def pformat_msg_spec(
|
||||||
|
self,
|
||||||
|
msg: MsgType|None = None,
|
||||||
|
) -> str:
|
||||||
|
return '\n'.join(
|
||||||
|
self.msg_spec_items(msg=msg).values()
|
||||||
|
)
|
||||||
|
|
||||||
lib: ModuleType = msgspec
|
lib: ModuleType = msgspec
|
||||||
|
|
||||||
# TODO: a sub-decoder system as well?
|
# TODO: a sub-decoder system as well?
|
||||||
|
@ -108,7 +146,7 @@ class MsgCodec(Struct):
|
||||||
# OR
|
# OR
|
||||||
# ) = {
|
# ) = {
|
||||||
# # pre-seed decoders for std-py-type-set for use when
|
# # pre-seed decoders for std-py-type-set for use when
|
||||||
# # `Msg.pld == None|Any`.
|
# # `MsgType.pld == None|Any`.
|
||||||
# None: msgpack.Decoder(Any),
|
# None: msgpack.Decoder(Any),
|
||||||
# Any: msgpack.Decoder(Any),
|
# Any: msgpack.Decoder(Any),
|
||||||
# }
|
# }
|
||||||
|
@ -303,7 +341,7 @@ def mk_codec(
|
||||||
# by `tag_field: str` value key?
|
# by `tag_field: str` value key?
|
||||||
# payload_msg_specs: dict[
|
# payload_msg_specs: dict[
|
||||||
# str, # tag_field value as sub-decoder key
|
# str, # tag_field value as sub-decoder key
|
||||||
# Union[Type[Struct]] # `Msg.pld` type spec
|
# Union[Type[Struct]] # `MsgType.pld` type spec
|
||||||
# ]|None = None,
|
# ]|None = None,
|
||||||
|
|
||||||
libname: str = 'msgspec',
|
libname: str = 'msgspec',
|
||||||
|
@ -336,7 +374,7 @@ def mk_codec(
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f'If a payload spec is provided,\n'
|
f'If a payload spec is provided,\n'
|
||||||
"the builtin SC-shuttle-protocol's msg set\n"
|
"the builtin SC-shuttle-protocol's msg set\n"
|
||||||
f'(i.e. `{Msg}`) MUST be used!\n\n'
|
f'(i.e. a `{MsgType}`) MUST be used!\n\n'
|
||||||
f'However both values were passed as => mk_codec(\n'
|
f'However both values were passed as => mk_codec(\n'
|
||||||
f' ipc_msg_spec={ipc_msg_spec}`\n'
|
f' ipc_msg_spec={ipc_msg_spec}`\n'
|
||||||
f' ipc_pld_spec={ipc_pld_spec}`\n)\n'
|
f' ipc_pld_spec={ipc_pld_spec}`\n)\n'
|
||||||
|
|
|
@ -31,6 +31,7 @@ from typing import (
|
||||||
Literal,
|
Literal,
|
||||||
Type,
|
Type,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
|
TypeAlias,
|
||||||
Union,
|
Union,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -400,16 +401,29 @@ class CancelAck(
|
||||||
pld: bool
|
pld: bool
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: unify this with `._exceptions.RemoteActorError`
|
||||||
|
# such that we can have a msg which is both raisable and
|
||||||
|
# IPC-wire ready?
|
||||||
|
# B~o
|
||||||
class Error(
|
class Error(
|
||||||
Struct,
|
Struct,
|
||||||
tag=True,
|
tag=True,
|
||||||
tag_field='msg_type',
|
tag_field='msg_type',
|
||||||
|
|
||||||
|
# TODO may omit defaults?
|
||||||
|
# https://jcristharif.com/msgspec/structs.html#omitting-default-values
|
||||||
|
# omit_defaults=True,
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
A pkt that wraps `RemoteActorError`s for relay and raising.
|
A pkt that wraps `RemoteActorError`s for relay and raising.
|
||||||
|
|
||||||
Fields are 1-to-1 meta-data as needed originally by
|
Fields are 1-to-1 meta-data as needed originally by
|
||||||
`RemoteActorError.msgdata: dict`.
|
`RemoteActorError.msgdata: dict` but now are defined here.
|
||||||
|
|
||||||
|
Note: this msg shuttles `ContextCancelled` and `StreamOverrun`
|
||||||
|
as well is used to rewrap any `MsgTypeError` for relay-reponse
|
||||||
|
to bad `Yield.pld` senders during an IPC ctx's streaming dialog
|
||||||
|
phase.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
src_uid: tuple[str, str]
|
src_uid: tuple[str, str]
|
||||||
|
@ -428,6 +442,10 @@ class Error(
|
||||||
# `StreamOverrun`
|
# `StreamOverrun`
|
||||||
sender: tuple[str, str]|None = None
|
sender: tuple[str, str]|None = None
|
||||||
|
|
||||||
|
# for the `MsgTypeError` case where the receiver side
|
||||||
|
# decodes the underlying original `Msg`-subtype
|
||||||
|
_msg_dict: dict|None = None
|
||||||
|
|
||||||
|
|
||||||
# TODO: should be make a msg version of `ContextCancelled?`
|
# TODO: should be make a msg version of `ContextCancelled?`
|
||||||
# and/or with a scope field or a full `ActorCancelled`?
|
# and/or with a scope field or a full `ActorCancelled`?
|
||||||
|
@ -486,6 +504,11 @@ __msg_types__: list[Msg] = (
|
||||||
_payload_msgs
|
_payload_msgs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: use new type declaration syntax for msg-type-spec
|
||||||
|
# https://docs.python.org/3/library/typing.html#type-aliases
|
||||||
|
# https://docs.python.org/3/reference/simple_stmts.html#type
|
||||||
|
MsgType: TypeAlias = Union[*__msg_types__]
|
||||||
|
|
||||||
|
|
||||||
def mk_msg_spec(
|
def mk_msg_spec(
|
||||||
payload_type_union: Union[Type] = Any,
|
payload_type_union: Union[Type] = Any,
|
||||||
|
|
Loading…
Reference in New Issue