Compare commits
9 Commits
59f3e4f3ef
...
1c9056aced
Author | SHA1 | Date |
---|---|---|
|
1c9056aced | |
|
5fd92dce06 | |
|
d5ce51f4d9 | |
|
6a2ea0e875 | |
|
d67c025cd3 | |
|
a9cc293d00 | |
|
e67db03b7a | |
|
604a95f5bf | |
|
0fd43c3448 |
|
@ -47,7 +47,7 @@ dependencies = [
|
||||||
"tabcompleter>=1.4.0",
|
"tabcompleter>=1.4.0",
|
||||||
# typed IPC msging
|
# typed IPC msging
|
||||||
# TODO, get back on release once 3.13 support is out!
|
# TODO, get back on release once 3.13 support is out!
|
||||||
"msgspec",
|
"msgspec>=0.19.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
# ------ project ------
|
# ------ project ------
|
||||||
|
@ -138,8 +138,6 @@ python-preference = 'system'
|
||||||
# ------ tool.uv ------
|
# ------ tool.uv ------
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
msgspec = { git = "https://github.com/jcrist/msgspec.git" }
|
|
||||||
|
|
||||||
# XXX NOTE, only for @goodboy's hacking on `pprint(sort_dicts=False)`
|
# XXX NOTE, only for @goodboy's hacking on `pprint(sort_dicts=False)`
|
||||||
# for the `pp` alias..
|
# for the `pp` alias..
|
||||||
# pdbp = { path = "../pdbp", editable = true }
|
# pdbp = { path = "../pdbp", editable = true }
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -432,9 +432,13 @@ class RemoteActorError(Exception):
|
||||||
Error type boxed by last actor IPC hop.
|
Error type boxed by last actor IPC hop.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
if self._boxed_type is None:
|
if (
|
||||||
|
self._boxed_type is None
|
||||||
|
and
|
||||||
|
(ipc_msg := self._ipc_msg)
|
||||||
|
):
|
||||||
self._boxed_type = get_err_type(
|
self._boxed_type = get_err_type(
|
||||||
self._ipc_msg.boxed_type_str
|
ipc_msg.boxed_type_str
|
||||||
)
|
)
|
||||||
|
|
||||||
return self._boxed_type
|
return self._boxed_type
|
||||||
|
@ -1143,6 +1147,8 @@ def unpack_error(
|
||||||
which is the responsibilitiy of the caller.
|
which is the responsibilitiy of the caller.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
# XXX, apparently we pass all sorts of msgs here?
|
||||||
|
# kinda odd but seems like maybe they shouldn't be?
|
||||||
if not isinstance(msg, Error):
|
if not isinstance(msg, Error):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ from ._codec import (
|
||||||
|
|
||||||
apply_codec as apply_codec,
|
apply_codec as apply_codec,
|
||||||
mk_codec as mk_codec,
|
mk_codec as mk_codec,
|
||||||
|
mk_dec as mk_dec,
|
||||||
MsgCodec as MsgCodec,
|
MsgCodec as MsgCodec,
|
||||||
MsgDec as MsgDec,
|
MsgDec as MsgDec,
|
||||||
current_codec as current_codec,
|
current_codec as current_codec,
|
||||||
|
|
|
@ -61,6 +61,7 @@ from tractor.msg.pretty_struct import Struct
|
||||||
from tractor.msg.types import (
|
from tractor.msg.types import (
|
||||||
mk_msg_spec,
|
mk_msg_spec,
|
||||||
MsgType,
|
MsgType,
|
||||||
|
PayloadMsg,
|
||||||
)
|
)
|
||||||
from tractor.log import get_logger
|
from tractor.log import get_logger
|
||||||
|
|
||||||
|
@ -80,6 +81,7 @@ class MsgDec(Struct):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
_dec: msgpack.Decoder
|
_dec: msgpack.Decoder
|
||||||
|
# _ext_types_box: Struct|None = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dec(self) -> msgpack.Decoder:
|
def dec(self) -> msgpack.Decoder:
|
||||||
|
@ -179,23 +181,126 @@ class MsgDec(Struct):
|
||||||
|
|
||||||
|
|
||||||
def mk_dec(
|
def mk_dec(
|
||||||
spec: Union[Type[Struct]]|Any = Any,
|
spec: Union[Type[Struct]]|Type|None,
|
||||||
|
|
||||||
|
# NOTE, required for ad-hoc type extensions to the underlying
|
||||||
|
# serialization proto (which is default `msgpack`),
|
||||||
|
# https://jcristharif.com/msgspec/extending.html#mapping-to-from-native-types
|
||||||
dec_hook: Callable|None = None,
|
dec_hook: Callable|None = None,
|
||||||
|
ext_types: list[Type]|None = None,
|
||||||
|
|
||||||
) -> MsgDec:
|
) -> MsgDec:
|
||||||
'''
|
'''
|
||||||
Create an IPC msg decoder, normally used as the
|
Create an IPC msg decoder, a slightly higher level wrapper around
|
||||||
`PayloadMsg.pld: PayloadT` field decoder inside a `PldRx`.
|
a `msgspec.msgpack.Decoder` which provides,
|
||||||
|
|
||||||
|
- easier introspection of the underlying type spec via
|
||||||
|
the `.spec` and `.spec_str` attrs,
|
||||||
|
- `.hook` access to the `Decoder.dec_hook()`,
|
||||||
|
- automatic custom extension-types decode support when
|
||||||
|
`dec_hook()` is provided such that any `PayloadMsg.pld` tagged
|
||||||
|
as a type from from `ext_types` (presuming the `MsgCodec.encode()` also used
|
||||||
|
a `.enc_hook()`) is processed and constructed by a `PldRx` implicitily.
|
||||||
|
|
||||||
|
NOTE, as mentioned a `MsgDec` is normally used for `PayloadMsg.pld: PayloadT` field
|
||||||
|
decoding inside an IPC-ctx-oriented `PldRx`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
if (
|
||||||
|
spec is None
|
||||||
|
and
|
||||||
|
ext_types is None
|
||||||
|
):
|
||||||
|
raise TypeError(
|
||||||
|
f'MIssing type-`spec` for msg decoder!\n'
|
||||||
|
f'\n'
|
||||||
|
f'`spec=None` is **only** permitted is if custom extension types '
|
||||||
|
f'are provided via `ext_types`, meaning it must be non-`None`.\n'
|
||||||
|
f'\n'
|
||||||
|
f'In this case it is presumed that only the `ext_types`, '
|
||||||
|
f'which much be handled by a paired `dec_hook()`, '
|
||||||
|
f'will be permitted within the payload type-`spec`!\n'
|
||||||
|
f'\n'
|
||||||
|
f'spec = {spec!r}\n'
|
||||||
|
f'dec_hook = {dec_hook!r}\n'
|
||||||
|
f'ext_types = {ext_types!r}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
if dec_hook:
|
||||||
|
if ext_types is None:
|
||||||
|
raise TypeError(
|
||||||
|
f'If extending the serializable types with a custom decode hook (`dec_hook()`), '
|
||||||
|
f'you must also provide the expected type set that the hook will handle '
|
||||||
|
f'via a `ext_types: Union[Type]|None = None` argument!\n'
|
||||||
|
f'\n'
|
||||||
|
f'dec_hook = {dec_hook!r}\n'
|
||||||
|
f'ext_types = {ext_types!r}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
# XXX, i *thought* we would require a boxing struct as per docs,
|
||||||
|
# https://jcristharif.com/msgspec/extending.html#mapping-to-from-native-types
|
||||||
|
# |_ see comment,
|
||||||
|
# > Note that typed deserialization is required for
|
||||||
|
# > successful roundtripping here, so we pass `MyMessage` to
|
||||||
|
# > `Decoder`.
|
||||||
|
#
|
||||||
|
# BUT, turns out as long as you spec a union with `Raw` it
|
||||||
|
# will work? kk B)
|
||||||
|
#
|
||||||
|
# maybe_box_struct = mk_boxed_ext_struct(ext_types)
|
||||||
|
spec = Raw | Union[*ext_types]
|
||||||
|
|
||||||
return MsgDec(
|
return MsgDec(
|
||||||
_dec=msgpack.Decoder(
|
_dec=msgpack.Decoder(
|
||||||
type=spec, # like `MsgType[Any]`
|
type=spec, # like `MsgType[Any]`
|
||||||
dec_hook=dec_hook,
|
dec_hook=dec_hook,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO? remove since didn't end up needing this?
|
||||||
|
def mk_boxed_ext_struct(
|
||||||
|
ext_types: list[Type],
|
||||||
|
) -> Struct:
|
||||||
|
# NOTE, originally was to wrap non-msgpack-supported "extension
|
||||||
|
# types" in a field-typed boxing struct, see notes around the
|
||||||
|
# `dec_hook()` branch in `mk_dec()`.
|
||||||
|
ext_types_union = Union[*ext_types]
|
||||||
|
repr_ext_types_union: str = (
|
||||||
|
str(ext_types_union)
|
||||||
|
or
|
||||||
|
"|".join(ext_types)
|
||||||
|
)
|
||||||
|
BoxedExtType = msgspec.defstruct(
|
||||||
|
f'BoxedExts[{repr_ext_types_union}]',
|
||||||
|
fields=[
|
||||||
|
('boxed', ext_types_union),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return BoxedExtType
|
||||||
|
|
||||||
|
|
||||||
|
def unpack_spec_types(
|
||||||
|
spec: Union[Type]|Type,
|
||||||
|
) -> set[Type]:
|
||||||
|
'''
|
||||||
|
Given an input type-`spec`, either a lone type
|
||||||
|
or a `Union` of types (like `str|int|MyThing`),
|
||||||
|
return a set of individual types.
|
||||||
|
|
||||||
|
When `spec` is not a type-union returns `{spec,}`.
|
||||||
|
|
||||||
|
'''
|
||||||
|
spec_subtypes: set[Union[Type]] = set(
|
||||||
|
getattr(
|
||||||
|
spec,
|
||||||
|
'__args__',
|
||||||
|
{spec,},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return spec_subtypes
|
||||||
|
|
||||||
|
|
||||||
def mk_msgspec_table(
|
def mk_msgspec_table(
|
||||||
dec: msgpack.Decoder,
|
dec: msgpack.Decoder,
|
||||||
msg: MsgType|None = None,
|
msg: MsgType|None = None,
|
||||||
|
@ -273,6 +378,8 @@ class MsgCodec(Struct):
|
||||||
_dec: msgpack.Decoder
|
_dec: msgpack.Decoder
|
||||||
_pld_spec: Type[Struct]|Raw|Any
|
_pld_spec: Type[Struct]|Raw|Any
|
||||||
|
|
||||||
|
# _ext_types_box: Struct|None = None
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
speclines: str = textwrap.indent(
|
speclines: str = textwrap.indent(
|
||||||
pformat_msgspec(codec=self),
|
pformat_msgspec(codec=self),
|
||||||
|
@ -339,12 +446,15 @@ class MsgCodec(Struct):
|
||||||
|
|
||||||
def encode(
|
def encode(
|
||||||
self,
|
self,
|
||||||
py_obj: Any,
|
py_obj: Any|PayloadMsg,
|
||||||
|
|
||||||
use_buf: bool = False,
|
use_buf: bool = False,
|
||||||
# ^-XXX-^ uhh why am i getting this?
|
# ^-XXX-^ uhh why am i getting this?
|
||||||
# |_BufferError: Existing exports of data: object cannot be re-sized
|
# |_BufferError: Existing exports of data: object cannot be re-sized
|
||||||
|
|
||||||
|
as_ext_type: bool = False,
|
||||||
|
hide_tb: bool = True,
|
||||||
|
|
||||||
) -> bytes:
|
) -> bytes:
|
||||||
'''
|
'''
|
||||||
Encode input python objects to `msgpack` bytes for
|
Encode input python objects to `msgpack` bytes for
|
||||||
|
@ -354,11 +464,46 @@ class MsgCodec(Struct):
|
||||||
https://jcristharif.com/msgspec/perf-tips.html#reusing-an-output-buffer
|
https://jcristharif.com/msgspec/perf-tips.html#reusing-an-output-buffer
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
__tracebackhide__: bool = hide_tb
|
||||||
if use_buf:
|
if use_buf:
|
||||||
self._enc.encode_into(py_obj, self._buf)
|
self._enc.encode_into(py_obj, self._buf)
|
||||||
return self._buf
|
return self._buf
|
||||||
else:
|
|
||||||
return self._enc.encode(py_obj)
|
return self._enc.encode(py_obj)
|
||||||
|
# try:
|
||||||
|
# return self._enc.encode(py_obj)
|
||||||
|
# except TypeError as typerr:
|
||||||
|
# typerr.add_note(
|
||||||
|
# '|_src error from `msgspec`'
|
||||||
|
# # f'|_{self._enc.encode!r}'
|
||||||
|
# )
|
||||||
|
# raise typerr
|
||||||
|
|
||||||
|
# TODO! REMOVE once i'm confident we won't ever need it!
|
||||||
|
#
|
||||||
|
# box: Struct = self._ext_types_box
|
||||||
|
# if (
|
||||||
|
# as_ext_type
|
||||||
|
# or
|
||||||
|
# (
|
||||||
|
# # XXX NOTE, auto-detect if the input type
|
||||||
|
# box
|
||||||
|
# and
|
||||||
|
# (ext_types := unpack_spec_types(
|
||||||
|
# spec=box.__annotations__['boxed'])
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
# ):
|
||||||
|
# match py_obj:
|
||||||
|
# # case PayloadMsg(pld=pld) if (
|
||||||
|
# # type(pld) in ext_types
|
||||||
|
# # ):
|
||||||
|
# # py_obj.pld = box(boxed=py_obj)
|
||||||
|
# # breakpoint()
|
||||||
|
# case _ if (
|
||||||
|
# type(py_obj) in ext_types
|
||||||
|
# ):
|
||||||
|
# py_obj = box(boxed=py_obj)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dec(self) -> msgpack.Decoder:
|
def dec(self) -> msgpack.Decoder:
|
||||||
|
@ -378,21 +523,30 @@ class MsgCodec(Struct):
|
||||||
return self._dec.decode(msg)
|
return self._dec.decode(msg)
|
||||||
|
|
||||||
|
|
||||||
# [x] TODO: a sub-decoder system as well? => No!
|
# ?TODO? time to remove this finally?
|
||||||
|
#
|
||||||
|
# -[x] TODO: a sub-decoder system as well?
|
||||||
|
# => No! already re-architected to include a "payload-receiver"
|
||||||
|
# now found in `._ops`.
|
||||||
#
|
#
|
||||||
# -[x] do we still want to try and support the sub-decoder with
|
# -[x] do we still want to try and support the sub-decoder with
|
||||||
# `.Raw` technique in the case that the `Generic` approach gives
|
# `.Raw` technique in the case that the `Generic` approach gives
|
||||||
# future grief?
|
# future grief?
|
||||||
# => NO, since we went with the `PldRx` approach instead B)
|
# => well YES but NO, since we went with the `PldRx` approach
|
||||||
|
# instead!
|
||||||
#
|
#
|
||||||
# IF however you want to see the code that was staged for this
|
# IF however you want to see the code that was staged for this
|
||||||
# from wayyy back, see the pure removal commit.
|
# from wayyy back, see the pure removal commit.
|
||||||
|
|
||||||
|
|
||||||
def mk_codec(
|
def mk_codec(
|
||||||
# struct type unions set for `Decoder`
|
ipc_pld_spec: Union[Type[Struct]]|Any|Raw = Raw,
|
||||||
# https://jcristharif.com/msgspec/structs.html#tagged-unions
|
# tagged-struct-types-union set for `Decoder`ing of payloads, as
|
||||||
ipc_pld_spec: Union[Type[Struct]]|Any = Any,
|
# per https://jcristharif.com/msgspec/structs.html#tagged-unions.
|
||||||
|
# NOTE that the default `Raw` here **is very intentional** since
|
||||||
|
# the `PldRx._pld_dec: MsgDec` is responsible for per ipc-ctx-task
|
||||||
|
# decoding of msg-specs defined by the user as part of **their**
|
||||||
|
# `tractor` "app's" type-limited IPC msg-spec.
|
||||||
|
|
||||||
# TODO: offering a per-msg(-field) type-spec such that
|
# TODO: offering a per-msg(-field) type-spec such that
|
||||||
# the fields can be dynamically NOT decoded and left as `Raw`
|
# the fields can be dynamically NOT decoded and left as `Raw`
|
||||||
|
@ -405,13 +559,18 @@ def mk_codec(
|
||||||
|
|
||||||
libname: str = 'msgspec',
|
libname: str = 'msgspec',
|
||||||
|
|
||||||
# proxy as `Struct(**kwargs)` for ad-hoc type extensions
|
# settings for encoding-to-send extension-types,
|
||||||
# https://jcristharif.com/msgspec/extending.html#mapping-to-from-native-types
|
# https://jcristharif.com/msgspec/extending.html#mapping-to-from-native-types
|
||||||
# ------ - ------
|
# dec_hook: Callable|None = None,
|
||||||
dec_hook: Callable|None = None,
|
|
||||||
enc_hook: Callable|None = None,
|
enc_hook: Callable|None = None,
|
||||||
# ------ - ------
|
ext_types: list[Type]|None = None,
|
||||||
|
|
||||||
|
# optionally provided msg-decoder from which we pull its,
|
||||||
|
# |_.dec_hook()
|
||||||
|
# |_.type
|
||||||
|
ext_dec: MsgDec|None = None
|
||||||
#
|
#
|
||||||
|
# ?TODO? other params we might want to support
|
||||||
# Encoder:
|
# Encoder:
|
||||||
# write_buffer_size=write_buffer_size,
|
# write_buffer_size=write_buffer_size,
|
||||||
#
|
#
|
||||||
|
@ -425,26 +584,44 @@ def mk_codec(
|
||||||
`msgspec` ;).
|
`msgspec` ;).
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# (manually) generate a msg-payload-spec for all relevant
|
pld_spec = ipc_pld_spec
|
||||||
# god-boxing-msg subtypes, parameterizing the `PayloadMsg.pld: PayloadT`
|
if enc_hook:
|
||||||
# for the decoder such that all sub-type msgs in our SCIPP
|
if not ext_types:
|
||||||
# will automatically decode to a type-"limited" payload (`Struct`)
|
raise TypeError(
|
||||||
# object (set).
|
f'If extending the serializable types with a custom encode hook (`enc_hook()`), '
|
||||||
|
f'you must also provide the expected type set that the hook will handle '
|
||||||
|
f'via a `ext_types: Union[Type]|None = None` argument!\n'
|
||||||
|
f'\n'
|
||||||
|
f'enc_hook = {enc_hook!r}\n'
|
||||||
|
f'ext_types = {ext_types!r}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
dec_hook: Callable|None = None
|
||||||
|
if ext_dec:
|
||||||
|
dec: msgspec.Decoder = ext_dec.dec
|
||||||
|
dec_hook = dec.dec_hook
|
||||||
|
pld_spec |= dec.type
|
||||||
|
if ext_types:
|
||||||
|
pld_spec |= Union[*ext_types]
|
||||||
|
|
||||||
|
# (manually) generate a msg-spec (how appropes) for all relevant
|
||||||
|
# payload-boxing-struct-msg-types, parameterizing the
|
||||||
|
# `PayloadMsg.pld: PayloadT` for the decoder such that all msgs
|
||||||
|
# in our SC-RPC-protocol will automatically decode to
|
||||||
|
# a type-"limited" payload (`Struct`) object (set).
|
||||||
(
|
(
|
||||||
ipc_msg_spec,
|
ipc_msg_spec,
|
||||||
msg_types,
|
msg_types,
|
||||||
) = mk_msg_spec(
|
) = mk_msg_spec(
|
||||||
payload_type_union=ipc_pld_spec,
|
payload_type_union=pld_spec,
|
||||||
)
|
)
|
||||||
assert len(ipc_msg_spec.__args__) == len(msg_types)
|
|
||||||
assert ipc_msg_spec
|
|
||||||
|
|
||||||
# TODO: use this shim instead?
|
msg_spec_types: set[Type] = unpack_spec_types(ipc_msg_spec)
|
||||||
# bc.. unification, err somethin?
|
assert (
|
||||||
# dec: MsgDec = mk_dec(
|
len(ipc_msg_spec.__args__) == len(msg_types)
|
||||||
# spec=ipc_msg_spec,
|
and
|
||||||
# dec_hook=dec_hook,
|
len(msg_spec_types) == len(msg_types)
|
||||||
# )
|
)
|
||||||
|
|
||||||
dec = msgpack.Decoder(
|
dec = msgpack.Decoder(
|
||||||
type=ipc_msg_spec,
|
type=ipc_msg_spec,
|
||||||
|
@ -453,22 +630,29 @@ def mk_codec(
|
||||||
enc = msgpack.Encoder(
|
enc = msgpack.Encoder(
|
||||||
enc_hook=enc_hook,
|
enc_hook=enc_hook,
|
||||||
)
|
)
|
||||||
|
|
||||||
codec = MsgCodec(
|
codec = MsgCodec(
|
||||||
_enc=enc,
|
_enc=enc,
|
||||||
_dec=dec,
|
_dec=dec,
|
||||||
_pld_spec=ipc_pld_spec,
|
_pld_spec=pld_spec,
|
||||||
)
|
)
|
||||||
|
|
||||||
# sanity on expected backend support
|
# sanity on expected backend support
|
||||||
assert codec.lib.__name__ == libname
|
assert codec.lib.__name__ == libname
|
||||||
|
|
||||||
return codec
|
return codec
|
||||||
|
|
||||||
|
|
||||||
# instance of the default `msgspec.msgpack` codec settings, i.e.
|
# instance of the default `msgspec.msgpack` codec settings, i.e.
|
||||||
# no custom structs, hooks or other special types.
|
# no custom structs, hooks or other special types.
|
||||||
_def_msgspec_codec: MsgCodec = mk_codec(ipc_pld_spec=Any)
|
#
|
||||||
|
# XXX NOTE XXX, this will break our `Context.start()` call!
|
||||||
|
#
|
||||||
|
# * by default we roundtrip the started pld-`value` and if you apply
|
||||||
|
# this codec (globally anyway with `apply_codec()`) then the
|
||||||
|
# `roundtripped` value will include a non-`.pld: Raw` which will
|
||||||
|
# then type-error on the consequent `._ops.validte_payload_msg()`..
|
||||||
|
#
|
||||||
|
_def_msgspec_codec: MsgCodec = mk_codec(
|
||||||
|
ipc_pld_spec=Any,
|
||||||
|
)
|
||||||
|
|
||||||
# The built-in IPC `Msg` spec.
|
# The built-in IPC `Msg` spec.
|
||||||
# Our composing "shuttle" protocol which allows `tractor`-app code
|
# Our composing "shuttle" protocol which allows `tractor`-app code
|
||||||
|
@ -476,13 +660,13 @@ _def_msgspec_codec: MsgCodec = mk_codec(ipc_pld_spec=Any)
|
||||||
# https://jcristharif.com/msgspec/supported-types.html
|
# https://jcristharif.com/msgspec/supported-types.html
|
||||||
#
|
#
|
||||||
_def_tractor_codec: MsgCodec = mk_codec(
|
_def_tractor_codec: MsgCodec = mk_codec(
|
||||||
# TODO: use this for debug mode locking prot?
|
ipc_pld_spec=Raw, # XXX should be default righ!?
|
||||||
# ipc_pld_spec=Any,
|
|
||||||
ipc_pld_spec=Raw,
|
|
||||||
)
|
)
|
||||||
# TODO: IDEALLY provides for per-`trio.Task` specificity of the
|
|
||||||
|
# -[x] TODO, IDEALLY provides for per-`trio.Task` specificity of the
|
||||||
# IPC msging codec used by the transport layer when doing
|
# IPC msging codec used by the transport layer when doing
|
||||||
# `Channel.send()/.recv()` of wire data.
|
# `Channel.send()/.recv()` of wire data.
|
||||||
|
# => impled as our `PldRx` which is `Context` scoped B)
|
||||||
|
|
||||||
# ContextVar-TODO: DIDN'T WORK, kept resetting in every new task to default!?
|
# ContextVar-TODO: DIDN'T WORK, kept resetting in every new task to default!?
|
||||||
# _ctxvar_MsgCodec: ContextVar[MsgCodec] = ContextVar(
|
# _ctxvar_MsgCodec: ContextVar[MsgCodec] = ContextVar(
|
||||||
|
@ -559,17 +743,6 @@ def apply_codec(
|
||||||
)
|
)
|
||||||
token: Token = var.set(codec)
|
token: Token = var.set(codec)
|
||||||
|
|
||||||
# ?TODO? for TreeVar approach which copies from the
|
|
||||||
# cancel-scope of the prior value, NOT the prior task
|
|
||||||
# See the docs:
|
|
||||||
# - https://tricycle.readthedocs.io/en/latest/reference.html#tree-variables
|
|
||||||
# - https://github.com/oremanj/tricycle/blob/master/tricycle/_tests/test_tree_var.py
|
|
||||||
# ^- see docs for @cm `.being()` API
|
|
||||||
# with _ctxvar_MsgCodec.being(codec):
|
|
||||||
# new = _ctxvar_MsgCodec.get()
|
|
||||||
# assert new is codec
|
|
||||||
# yield codec
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield var.get()
|
yield var.get()
|
||||||
finally:
|
finally:
|
||||||
|
@ -580,6 +753,19 @@ def apply_codec(
|
||||||
)
|
)
|
||||||
assert var.get() is orig
|
assert var.get() is orig
|
||||||
|
|
||||||
|
# ?TODO? for TreeVar approach which copies from the
|
||||||
|
# cancel-scope of the prior value, NOT the prior task
|
||||||
|
#
|
||||||
|
# See the docs:
|
||||||
|
# - https://tricycle.readthedocs.io/en/latest/reference.html#tree-variables
|
||||||
|
# - https://github.com/oremanj/tricycle/blob/master/tricycle/_tests/test_tree_var.py
|
||||||
|
# ^- see docs for @cm `.being()` API
|
||||||
|
#
|
||||||
|
# with _ctxvar_MsgCodec.being(codec):
|
||||||
|
# new = _ctxvar_MsgCodec.get()
|
||||||
|
# assert new is codec
|
||||||
|
# yield codec
|
||||||
|
|
||||||
|
|
||||||
def current_codec() -> MsgCodec:
|
def current_codec() -> MsgCodec:
|
||||||
'''
|
'''
|
||||||
|
@ -599,6 +785,7 @@ def limit_msg_spec(
|
||||||
# -> related to the `MsgCodec._payload_decs` stuff above..
|
# -> related to the `MsgCodec._payload_decs` stuff above..
|
||||||
# tagged_structs: list[Struct]|None = None,
|
# tagged_structs: list[Struct]|None = None,
|
||||||
|
|
||||||
|
hide_tb: bool = True,
|
||||||
**codec_kwargs,
|
**codec_kwargs,
|
||||||
|
|
||||||
) -> MsgCodec:
|
) -> MsgCodec:
|
||||||
|
@ -609,7 +796,7 @@ def limit_msg_spec(
|
||||||
for all IPC contexts in use by the current `trio.Task`.
|
for all IPC contexts in use by the current `trio.Task`.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
__tracebackhide__: bool = True
|
__tracebackhide__: bool = hide_tb
|
||||||
curr_codec: MsgCodec = current_codec()
|
curr_codec: MsgCodec = current_codec()
|
||||||
msgspec_codec: MsgCodec = mk_codec(
|
msgspec_codec: MsgCodec = mk_codec(
|
||||||
ipc_pld_spec=payload_spec,
|
ipc_pld_spec=payload_spec,
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
# tractor: structured concurrent "actors".
|
||||||
|
# Copyright 2018-eternity Tyler Goodlet.
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
'''
|
||||||
|
Type-extension-utils for codec-ing (python) objects not
|
||||||
|
covered by the `msgspec.msgpack` protocol.
|
||||||
|
|
||||||
|
See the various API docs from `msgspec`.
|
||||||
|
|
||||||
|
extending from native types,
|
||||||
|
- https://jcristharif.com/msgspec/extending.html#mapping-to-from-native-types
|
||||||
|
|
||||||
|
converters,
|
||||||
|
- https://jcristharif.com/msgspec/converters.html
|
||||||
|
- https://jcristharif.com/msgspec/api.html#msgspec.convert
|
||||||
|
|
||||||
|
`Raw` fields,
|
||||||
|
- https://jcristharif.com/msgspec/api.html#raw
|
||||||
|
- support for `.convert()` and `Raw`,
|
||||||
|
|_ https://jcristharif.com/msgspec/changelog.html
|
||||||
|
|
||||||
|
'''
|
||||||
|
from types import (
|
||||||
|
ModuleType,
|
||||||
|
)
|
||||||
|
import typing
|
||||||
|
from typing import (
|
||||||
|
Type,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
|
def dec_type_union(
|
||||||
|
type_names: list[str],
|
||||||
|
mods: list[ModuleType] = []
|
||||||
|
) -> Type|Union[Type]:
|
||||||
|
'''
|
||||||
|
Look up types by name, compile into a list and then create and
|
||||||
|
return a `typing.Union` from the full set.
|
||||||
|
|
||||||
|
'''
|
||||||
|
# import importlib
|
||||||
|
types: list[Type] = []
|
||||||
|
for type_name in type_names:
|
||||||
|
for mod in [
|
||||||
|
typing,
|
||||||
|
# importlib.import_module(__name__),
|
||||||
|
] + mods:
|
||||||
|
if type_ref := getattr(
|
||||||
|
mod,
|
||||||
|
type_name,
|
||||||
|
False,
|
||||||
|
):
|
||||||
|
types.append(type_ref)
|
||||||
|
|
||||||
|
# special case handling only..
|
||||||
|
# ipc_pld_spec: Union[Type] = eval(
|
||||||
|
# pld_spec_str,
|
||||||
|
# {}, # globals
|
||||||
|
# {'typing': typing}, # locals
|
||||||
|
# )
|
||||||
|
|
||||||
|
return Union[*types]
|
||||||
|
|
||||||
|
|
||||||
|
def enc_type_union(
|
||||||
|
union_or_type: Union[Type]|Type,
|
||||||
|
) -> list[str]:
|
||||||
|
'''
|
||||||
|
Encode a type-union or single type to a list of type-name-strings
|
||||||
|
ready for IPC interchange.
|
||||||
|
|
||||||
|
'''
|
||||||
|
type_strs: list[str] = []
|
||||||
|
for typ in getattr(
|
||||||
|
union_or_type,
|
||||||
|
'__args__',
|
||||||
|
{union_or_type,},
|
||||||
|
):
|
||||||
|
type_strs.append(typ.__qualname__)
|
||||||
|
|
||||||
|
return type_strs
|
|
@ -50,7 +50,9 @@ from tractor._exceptions import (
|
||||||
_mk_recv_mte,
|
_mk_recv_mte,
|
||||||
pack_error,
|
pack_error,
|
||||||
)
|
)
|
||||||
from tractor._state import current_ipc_ctx
|
from tractor._state import (
|
||||||
|
current_ipc_ctx,
|
||||||
|
)
|
||||||
from ._codec import (
|
from ._codec import (
|
||||||
mk_dec,
|
mk_dec,
|
||||||
MsgDec,
|
MsgDec,
|
||||||
|
@ -78,7 +80,7 @@ if TYPE_CHECKING:
|
||||||
log = get_logger(__name__)
|
log = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
_def_any_pldec: MsgDec[Any] = mk_dec()
|
_def_any_pldec: MsgDec[Any] = mk_dec(spec=Any)
|
||||||
|
|
||||||
|
|
||||||
class PldRx(Struct):
|
class PldRx(Struct):
|
||||||
|
@ -148,6 +150,10 @@ class PldRx(Struct):
|
||||||
exit.
|
exit.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
# TODO, ensure we pull the current `MsgCodec`'s custom
|
||||||
|
# dec/enc_hook settings as well ?
|
||||||
|
# -[ ] see `._codec.mk_codec()` inputs
|
||||||
|
#
|
||||||
orig_dec: MsgDec = self._pld_dec
|
orig_dec: MsgDec = self._pld_dec
|
||||||
limit_dec: MsgDec = mk_dec(
|
limit_dec: MsgDec = mk_dec(
|
||||||
spec=spec,
|
spec=spec,
|
||||||
|
@ -455,11 +461,16 @@ def limit_plds(
|
||||||
|
|
||||||
'''
|
'''
|
||||||
__tracebackhide__: bool = True
|
__tracebackhide__: bool = True
|
||||||
|
curr_ctx: Context|None = current_ipc_ctx()
|
||||||
|
if curr_ctx is None:
|
||||||
|
raise RuntimeError(
|
||||||
|
'No IPC `Context` is active !?\n'
|
||||||
|
'Did you open `limit_plds()` from outside '
|
||||||
|
'a `Portal.open_context()` scope-block?'
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
curr_ctx: Context = current_ipc_ctx()
|
|
||||||
rx: PldRx = curr_ctx._pld_rx
|
rx: PldRx = curr_ctx._pld_rx
|
||||||
orig_pldec: MsgDec = rx.pld_dec
|
orig_pldec: MsgDec = rx.pld_dec
|
||||||
|
|
||||||
with rx.limit_plds(
|
with rx.limit_plds(
|
||||||
spec=spec,
|
spec=spec,
|
||||||
**dec_kwargs,
|
**dec_kwargs,
|
||||||
|
@ -469,6 +480,11 @@ def limit_plds(
|
||||||
f'{pldec}\n'
|
f'{pldec}\n'
|
||||||
)
|
)
|
||||||
yield pldec
|
yield pldec
|
||||||
|
|
||||||
|
except BaseException:
|
||||||
|
__tracebackhide__: bool = False
|
||||||
|
raise
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
log.runtime(
|
log.runtime(
|
||||||
'Reverted to previous payload-decoder\n\n'
|
'Reverted to previous payload-decoder\n\n'
|
||||||
|
|
|
@ -599,15 +599,15 @@ def mk_msg_spec(
|
||||||
Msg[payload_type_union],
|
Msg[payload_type_union],
|
||||||
Generic[PayloadT],
|
Generic[PayloadT],
|
||||||
)
|
)
|
||||||
defstruct_bases: tuple = (
|
# defstruct_bases: tuple = (
|
||||||
Msg, # [payload_type_union],
|
# Msg, # [payload_type_union],
|
||||||
# Generic[PayloadT],
|
# # Generic[PayloadT],
|
||||||
# ^-XXX-^: not allowed? lul..
|
# # ^-XXX-^: not allowed? lul..
|
||||||
)
|
# )
|
||||||
ipc_msg_types: list[Msg] = []
|
ipc_msg_types: list[Msg] = []
|
||||||
|
|
||||||
idx_msg_types: list[Msg] = []
|
idx_msg_types: list[Msg] = []
|
||||||
defs_msg_types: list[Msg] = []
|
# defs_msg_types: list[Msg] = []
|
||||||
nc_msg_types: list[Msg] = []
|
nc_msg_types: list[Msg] = []
|
||||||
|
|
||||||
for msgtype in __msg_types__:
|
for msgtype in __msg_types__:
|
||||||
|
@ -625,7 +625,7 @@ def mk_msg_spec(
|
||||||
# TODO: wait why do we need the dynamic version here?
|
# TODO: wait why do we need the dynamic version here?
|
||||||
# XXX ANSWER XXX -> BC INHERITANCE.. don't work w generics..
|
# XXX ANSWER XXX -> BC INHERITANCE.. don't work w generics..
|
||||||
#
|
#
|
||||||
# NOTE previously bc msgtypes WERE NOT inheritting
|
# NOTE previously bc msgtypes WERE NOT inheriting
|
||||||
# directly the `Generic[PayloadT]` type, the manual method
|
# directly the `Generic[PayloadT]` type, the manual method
|
||||||
# of generic-paraming with `.__class_getitem__()` wasn't
|
# of generic-paraming with `.__class_getitem__()` wasn't
|
||||||
# working..
|
# working..
|
||||||
|
@ -662,38 +662,35 @@ def mk_msg_spec(
|
||||||
|
|
||||||
# with `msgspec.structs.defstruct`
|
# with `msgspec.structs.defstruct`
|
||||||
# XXX ALSO DOESN'T WORK
|
# XXX ALSO DOESN'T WORK
|
||||||
defstruct_msgtype = defstruct(
|
# defstruct_msgtype = defstruct(
|
||||||
name=msgtype.__name__,
|
# name=msgtype.__name__,
|
||||||
fields=[
|
# fields=[
|
||||||
('cid', str),
|
# ('cid', str),
|
||||||
|
|
||||||
# XXX doesn't seem to work..
|
# # XXX doesn't seem to work..
|
||||||
# ('pld', PayloadT),
|
# # ('pld', PayloadT),
|
||||||
|
|
||||||
('pld', payload_type_union),
|
|
||||||
],
|
|
||||||
bases=defstruct_bases,
|
|
||||||
)
|
|
||||||
defs_msg_types.append(defstruct_msgtype)
|
|
||||||
|
|
||||||
|
# ('pld', payload_type_union),
|
||||||
|
# ],
|
||||||
|
# bases=defstruct_bases,
|
||||||
|
# )
|
||||||
|
# defs_msg_types.append(defstruct_msgtype)
|
||||||
# assert index_paramed_msg_type == manual_paramed_msg_subtype
|
# assert index_paramed_msg_type == manual_paramed_msg_subtype
|
||||||
|
|
||||||
# paramed_msg_type = manual_paramed_msg_subtype
|
# paramed_msg_type = manual_paramed_msg_subtype
|
||||||
|
|
||||||
# ipc_payload_msgs_type_union |= index_paramed_msg_type
|
# ipc_payload_msgs_type_union |= index_paramed_msg_type
|
||||||
|
|
||||||
idx_spec: Union[Type[Msg]] = Union[*idx_msg_types]
|
idx_spec: Union[Type[Msg]] = Union[*idx_msg_types]
|
||||||
def_spec: Union[Type[Msg]] = Union[*defs_msg_types]
|
# def_spec: Union[Type[Msg]] = Union[*defs_msg_types]
|
||||||
nc_spec: Union[Type[Msg]] = Union[*nc_msg_types]
|
nc_spec: Union[Type[Msg]] = Union[*nc_msg_types]
|
||||||
|
|
||||||
specs: dict[str, Union[Type[Msg]]] = {
|
specs: dict[str, Union[Type[Msg]]] = {
|
||||||
'indexed_generics': idx_spec,
|
'indexed_generics': idx_spec,
|
||||||
'defstruct': def_spec,
|
# 'defstruct': def_spec,
|
||||||
'types_new_class': nc_spec,
|
'types_new_class': nc_spec,
|
||||||
}
|
}
|
||||||
msgtypes_table: dict[str, list[Msg]] = {
|
msgtypes_table: dict[str, list[Msg]] = {
|
||||||
'indexed_generics': idx_msg_types,
|
'indexed_generics': idx_msg_types,
|
||||||
'defstruct': defs_msg_types,
|
# 'defstruct': defs_msg_types,
|
||||||
'types_new_class': nc_msg_types,
|
'types_new_class': nc_msg_types,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
uv.lock
28
uv.lock
|
@ -147,7 +147,31 @@ wheels = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "msgspec"
|
name = "msgspec"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
source = { git = "https://github.com/jcrist/msgspec.git#dd965dce22e5278d4935bea923441ecde31b5325" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cf/9b/95d8ce458462b8b71b8a70fa94563b2498b89933689f3a7b8911edfae3d7/msgspec-0.19.0.tar.gz", hash = "sha256:604037e7cd475345848116e89c553aa9a233259733ab51986ac924ab1b976f8e", size = 216934 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/24/d4/2ec2567ac30dab072cce3e91fb17803c52f0a37aab6b0c24375d2b20a581/msgspec-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa77046904db764b0462036bc63ef71f02b75b8f72e9c9dd4c447d6da1ed8f8e", size = 187939 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/c0/18226e4328897f4f19875cb62bb9259fe47e901eade9d9376ab5f251a929/msgspec-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:047cfa8675eb3bad68722cfe95c60e7afabf84d1bd8938979dd2b92e9e4a9551", size = 182202 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/81/25/3a4b24d468203d8af90d1d351b77ea3cffb96b29492855cf83078f16bfe4/msgspec-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e78f46ff39a427e10b4a61614a2777ad69559cc8d603a7c05681f5a595ea98f7", size = 209029 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/2e/db7e189b57901955239f7689b5dcd6ae9458637a9c66747326726c650523/msgspec-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c7adf191e4bd3be0e9231c3b6dc20cf1199ada2af523885efc2ed218eafd011", size = 210682 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/03/97/7c8895c9074a97052d7e4a1cc1230b7b6e2ca2486714eb12c3f08bb9d284/msgspec-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f04cad4385e20be7c7176bb8ae3dca54a08e9756cfc97bcdb4f18560c3042063", size = 214003 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/61/e892997bcaa289559b4d5869f066a8021b79f4bf8e955f831b095f47a4cd/msgspec-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45c8fb410670b3b7eb884d44a75589377c341ec1392b778311acdbfa55187716", size = 216833 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/3d/71b2dffd3a1c743ffe13296ff701ee503feaebc3f04d0e75613b6563c374/msgspec-0.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:70eaef4934b87193a27d802534dc466778ad8d536e296ae2f9334e182ac27b6c", size = 186184 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/5f/a70c24f075e3e7af2fae5414c7048b0e11389685b7f717bb55ba282a34a7/msgspec-0.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f98bd8962ad549c27d63845b50af3f53ec468b6318400c9f1adfe8b092d7b62f", size = 190485 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/b0/1b9763938cfae12acf14b682fcf05c92855974d921a5a985ecc197d1c672/msgspec-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:43bbb237feab761b815ed9df43b266114203f53596f9b6e6f00ebd79d178cdf2", size = 183910 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/87/81/0c8c93f0b92c97e326b279795f9c5b956c5a97af28ca0fbb9fd86c83737a/msgspec-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfc033c02c3e0aec52b71710d7f84cb3ca5eb407ab2ad23d75631153fdb1f12", size = 210633 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/ef/c5422ce8af73928d194a6606f8ae36e93a52fd5e8df5abd366903a5ca8da/msgspec-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d911c442571605e17658ca2b416fd8579c5050ac9adc5e00c2cb3126c97f73bc", size = 213594 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/19/2b/4137bc2ed45660444842d042be2cf5b18aa06efd2cda107cff18253b9653/msgspec-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:757b501fa57e24896cf40a831442b19a864f56d253679f34f260dcb002524a6c", size = 214053 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/e6/8ad51bdc806aac1dc501e8fe43f759f9ed7284043d722b53323ea421c360/msgspec-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5f0f65f29b45e2816d8bded36e6b837a4bf5fb60ec4bc3c625fa2c6da4124537", size = 219081 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b1/ef/27dd35a7049c9a4f4211c6cd6a8c9db0a50647546f003a5867827ec45391/msgspec-0.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:067f0de1c33cfa0b6a8206562efdf6be5985b988b53dd244a8e06f993f27c8c0", size = 187467 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/cb/2842c312bbe618d8fefc8b9cedce37f773cdc8fa453306546dba2c21fd98/msgspec-0.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f12d30dd6266557aaaf0aa0f9580a9a8fbeadfa83699c487713e355ec5f0bd86", size = 190498 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/58/95/c40b01b93465e1a5f3b6c7d91b10fb574818163740cc3acbe722d1e0e7e4/msgspec-0.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82b2c42c1b9ebc89e822e7e13bbe9d17ede0c23c187469fdd9505afd5a481314", size = 183950 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/f0/5b764e066ce9aba4b70d1db8b087ea66098c7c27d59b9dd8a3532774d48f/msgspec-0.19.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19746b50be214a54239aab822964f2ac81e38b0055cca94808359d779338c10e", size = 210647 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/87/bc14f49bc95c4cb0dd0a8c56028a67c014ee7e6818ccdce74a4862af259b/msgspec-0.19.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60ef4bdb0ec8e4ad62e5a1f95230c08efb1f64f32e6e8dd2ced685bcc73858b5", size = 213563 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/53/2f/2b1c2b056894fbaa975f68f81e3014bb447516a8b010f1bed3fb0e016ed7/msgspec-0.19.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac7f7c377c122b649f7545810c6cd1b47586e3aa3059126ce3516ac7ccc6a6a9", size = 213996 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/aa/5a/4cd408d90d1417e8d2ce6a22b98a6853c1b4d7cb7669153e4424d60087f6/msgspec-0.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5bc1472223a643f5ffb5bf46ccdede7f9795078194f14edd69e3aab7020d327", size = 219087 },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/23/d8/f15b40611c2d5753d1abb0ca0da0c75348daf1252220e5dda2867bd81062/msgspec-0.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:317050bc0f7739cb30d257ff09152ca309bf5a369854bbf1e57dffc310c1f20f", size = 187432 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy-extensions"
|
name = "mypy-extensions"
|
||||||
|
@ -351,7 +375,7 @@ dev = [
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "colorlog", specifier = ">=6.8.2,<7" },
|
{ name = "colorlog", specifier = ">=6.8.2,<7" },
|
||||||
{ name = "msgspec", git = "https://github.com/jcrist/msgspec.git" },
|
{ name = "msgspec", specifier = ">=0.19.0" },
|
||||||
{ name = "pdbp", specifier = ">=1.6,<2" },
|
{ name = "pdbp", specifier = ">=1.6,<2" },
|
||||||
{ name = "tabcompleter", specifier = ">=1.4.0" },
|
{ name = "tabcompleter", specifier = ">=1.4.0" },
|
||||||
{ name = "tricycle", specifier = ">=0.4.1,<0.5" },
|
{ name = "tricycle", specifier = ">=0.4.1,<0.5" },
|
||||||
|
|
Loading…
Reference in New Issue