Move `Union` serializers to new `msg.` mod

Namely moving `enc/dec_type_union()` from the test mod to a new
`tractor.msg._exts` for general use outside the test suite.
ext_type_plds
Tyler Goodlet 2025-03-07 14:38:22 -05:00
parent 61f6690261
commit e40a76fe83
2 changed files with 103 additions and 57 deletions

View File

@ -5,7 +5,6 @@ Low-level functional audits for our
B~)
'''
import typing
from typing import (
Any,
Type,
@ -32,6 +31,7 @@ from tractor import (
from tractor.msg import (
_codec,
_ctxvar_MsgCodec,
_exts,
NamespacePath,
MsgCodec,
@ -247,57 +247,6 @@ def iter_maybe_sends(
)
def dec_type_union(
type_names: list[str],
) -> 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__),
]:
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
@tractor.context
async def send_back_values(
ctx: Context,
@ -324,7 +273,7 @@ async def send_back_values(
)
# load pld spec from input str
ipc_pld_spec = dec_type_union(
ipc_pld_spec = _exts.dec_type_union(
pld_spec_type_strs,
)
pld_spec_str = str(ipc_pld_spec)
@ -413,7 +362,6 @@ async def send_back_values(
except tractor.MsgTypeError as _mte:
mte = _mte
# await tractor.pause()
if expect_send:
raise RuntimeError(
@ -422,6 +370,10 @@ async def send_back_values(
f'value -> {send_value}: {type(send_value)}\n'
)
# await tractor.pause()
raise mte
async with ctx.open_stream() as ipc:
print(
f'{uid}: Entering streaming block to send remaining values..'
@ -591,8 +543,9 @@ def test_codec_hooks_mod(
)
):
pld_types_str: str = '|'.join(subtypes)
breakpoint()
# breakpoint()
else:
# TODO, use `.msg._exts` utils instead of this!
pld_types_str: str = ipc_pld_spec.__name__
expected_started = Started(
@ -611,7 +564,7 @@ def test_codec_hooks_mod(
if expect_send
]
pld_spec_type_strs: list[str] = enc_type_union(ipc_pld_spec)
pld_spec_type_strs: list[str] = _exts.enc_type_union(ipc_pld_spec)
# XXX should raise an mte (`MsgTypeError`)
# when `add_codec_hooks == False` bc the input
@ -848,11 +801,14 @@ def chk_pld_type(
return roundtrip
# ?TODO? remove since covered in the newer `test_pldrx_limiting`?
def test_limit_msgspec(
debug_mode: bool,
):
'''
Verify that type-limiting the
Internals unit testing to verify that type-limiting an IPC ctx's
msg spec with `Pldrx.limit_plds()` results in various
encapsulated `msgspec` object settings and state.
'''
async def main():

View File

@ -0,0 +1,90 @@
# 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
'''
import typing
from typing import (
Type,
Union,
)
def dec_type_union(
type_names: list[str],
) -> 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__),
]:
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