Compare commits

..

No commits in common. "fb04f746057f634061f443602c37e291e305ad21" and "b875b35b984fae8e3ca79613f81d94cf057a5fea" have entirely different histories.

12 changed files with 70 additions and 226 deletions

View File

@ -1,18 +0,0 @@
First generate a built disti:
```
python -m pip install --upgrade build
python -m build --sdist --outdir dist/alpha5/
```
Then try a test ``pypi`` upload:
```
python -m twine upload --repository testpypi dist/alpha5/*
```
The push to `pypi` for realz.
```
python -m twine upload --repository testpypi dist/alpha5/*
```

View File

@ -1703,28 +1703,15 @@ class Context:
# TODO: expose as mod func instead! # TODO: expose as mod func instead!
structfmt = pretty_struct.Struct.pformat structfmt = pretty_struct.Struct.pformat
if self._in_overrun: if self._in_overrun:
report: str = ( log.warning(
f'Queueing OVERRUN msg on caller task:\n\n'
f'{flow_body}' f'{flow_body}'
f'{structfmt(msg)}\n' f'{structfmt(msg)}\n'
) )
over_q: deque = self._overflow_q
self._overflow_q.append(msg) self._overflow_q.append(msg)
if len(over_q) == over_q.maxlen:
report = (
'FAILED to queue OVERRUN msg, OVERAN the OVERRUN QUEUE !!\n\n'
+ report
)
# log.error(report)
log.debug(report)
else:
report = (
'Queueing OVERRUN msg on caller task:\n\n'
+ report
)
log.debug(report)
# XXX NOTE XXX # XXX NOTE XXX
# overrun is the ONLY case where returning early is fine! # overrun is the ONLY case where returning early is fine!
return False return False

View File

@ -609,7 +609,6 @@ class RemoteActorError(Exception):
# just after <Type( # just after <Type(
# |___ .. # |___ ..
tb_body_indent=1, tb_body_indent=1,
boxer_header=self.relay_uid,
) )
tail = '' tail = ''

View File

@ -95,10 +95,6 @@ async def open_root_actor(
hide_tb: bool = True, hide_tb: bool = True,
# TODO, a way for actors to augment passing derived
# read-only state to sublayers?
# extra_rt_vars: dict|None = None,
) -> Actor: ) -> Actor:
''' '''
Runtime init entry point for ``tractor``. Runtime init entry point for ``tractor``.

View File

@ -456,14 +456,11 @@ class Actor:
) )
if _pre_chan: if _pre_chan:
log.warning(
# con_status += ( # con_status += (
# ^TODO^ swap once we minimize conn duplication # ^TODO^ swap once we minimize conn duplication
# -[ ] last thing might be reg/unreg runtime reqs? f' -> Wait, we already have IPC with `{uid_short}`??\n'
# log.warning( f' |_{_pre_chan}\n'
log.debug(
f'?Wait?\n'
f'We already have IPC with peer {uid_short!r}\n'
f'|_{_pre_chan}\n'
) )
# IPC connection tracking for both peers and new children: # IPC connection tracking for both peers and new children:

View File

@ -1420,10 +1420,6 @@ def any_connected_locker_child() -> bool:
return False return False
_ctlc_ignore_header: str = (
'Ignoring SIGINT while debug REPL in use'
)
def sigint_shield( def sigint_shield(
signum: int, signum: int,
frame: 'frame', # type: ignore # noqa frame: 'frame', # type: ignore # noqa
@ -1505,9 +1501,7 @@ def sigint_shield(
# NOTE: don't emit this with `.pdb()` level in # NOTE: don't emit this with `.pdb()` level in
# root without a higher level. # root without a higher level.
log.runtime( log.runtime(
_ctlc_ignore_header f'Ignoring SIGINT while debug REPL in use by child '
+
f' by child '
f'{uid_in_debug}\n' f'{uid_in_debug}\n'
) )
problem = None problem = None
@ -1541,9 +1535,7 @@ def sigint_shield(
# NOTE: since we emit this msg on ctl-c, we should # NOTE: since we emit this msg on ctl-c, we should
# also always re-print the prompt the tail block! # also always re-print the prompt the tail block!
log.pdb( log.pdb(
_ctlc_ignore_header 'Ignoring SIGINT while pdb REPL in use by root actor..\n'
+
f' by root actor..\n'
f'{DebugStatus.repl_task}\n' f'{DebugStatus.repl_task}\n'
f' |_{repl}\n' f' |_{repl}\n'
) )
@ -1604,20 +1596,16 @@ def sigint_shield(
repl repl
): ):
log.pdb( log.pdb(
_ctlc_ignore_header f'Ignoring SIGINT while local task using debug REPL\n'
+ f'|_{repl_task}\n'
f' by local task\n\n'
f'{repl_task}\n'
f' |_{repl}\n' f' |_{repl}\n'
) )
elif req_task: elif req_task:
log.debug( log.debug(
_ctlc_ignore_header 'Ignoring SIGINT while debug request task is open but either,\n'
+ '- someone else is already REPL-in and has the `Lock`, or\n'
f' by local request-task and either,\n' '- some other local task already is replin?\n'
f'- someone else is already REPL-in and has the `Lock`, or\n' f'|_{req_task}\n'
f'- some other local task already is replin?\n\n'
f'{req_task}\n'
) )
# TODO can we remove this now? # TODO can we remove this now?

View File

@ -234,7 +234,7 @@ def find_caller_info(
_frame2callerinfo_cache: dict[FrameType, CallerInfo] = {} _frame2callerinfo_cache: dict[FrameType, CallerInfo] = {}
# TODO: -[x] move all this into new `.devx._frame_stack`! # TODO: -[x] move all this into new `.devx._code`!
# -[ ] consider rename to _callstack? # -[ ] consider rename to _callstack?
# -[ ] prolly create a `@runtime_api` dec? # -[ ] prolly create a `@runtime_api` dec?
# |_ @api_frame seems better? # |_ @api_frame seems better?
@ -286,18 +286,3 @@ def api_frame(
wrapped._call_infos: dict[FrameType, CallerInfo] = _frame2callerinfo_cache wrapped._call_infos: dict[FrameType, CallerInfo] = _frame2callerinfo_cache
wrapped.__api_func__: bool = True wrapped.__api_func__: bool = True
return wrapper(wrapped) return wrapper(wrapped)
# TODO: something like this instead of the adhoc frame-unhiding
# blocks all over the runtime!! XD
# -[ ] ideally we can expect a certain error (set) and if something
# else is raised then all frames below the wrapped one will be
# un-hidden via `__tracebackhide__: bool = False`.
# |_ might need to dynamically mutate the code objs like
# `pdbp.hideframe()` does?
# -[ ] use this as a `@acm` decorator as introed in 3.10?
# @acm
# async def unhide_frame_when_not(
# error_set: set[BaseException],
# ) -> TracebackType:
# ...

View File

@ -53,7 +53,6 @@ def pformat_boxed_tb(
tb_box_indent: int|None = None, tb_box_indent: int|None = None,
tb_body_indent: int = 1, tb_body_indent: int = 1,
boxer_header: str = '-'
) -> str: ) -> str:
''' '''
@ -89,9 +88,9 @@ def pformat_boxed_tb(
tb_box: str = ( tb_box: str = (
f'|\n' f'|\n'
f' ------ {boxer_header} ------\n' f' ------ - ------\n'
f'{tb_body}' f'{tb_body}'
f' ------ {boxer_header}- ------\n' f' ------ - ------\n'
f'_|\n' f'_|\n'
) )
tb_box_indent: str = ( tb_box_indent: str = (

View File

@ -41,10 +41,8 @@ import textwrap
from typing import ( from typing import (
Any, Any,
Callable, Callable,
Protocol,
Type, Type,
TYPE_CHECKING, TYPE_CHECKING,
TypeVar,
Union, Union,
) )
from types import ModuleType from types import ModuleType
@ -183,11 +181,7 @@ def mk_dec(
dec_hook: Callable|None = None, dec_hook: Callable|None = None,
) -> MsgDec: ) -> MsgDec:
'''
Create an IPC msg decoder, normally used as the
`PayloadMsg.pld: PayloadT` field decoder inside a `PldRx`.
'''
return MsgDec( return MsgDec(
_dec=msgpack.Decoder( _dec=msgpack.Decoder(
type=spec, # like `MsgType[Any]` type=spec, # like `MsgType[Any]`
@ -233,13 +227,6 @@ def pformat_msgspec(
join_char: str = '\n', join_char: str = '\n',
) -> str: ) -> str:
'''
Pretty `str` format the `msgspec.msgpack.Decoder.type` attribute
for display in (console) log messages as a nice (maybe multiline)
presentation of all supported `Struct`s (subtypes) available for
typed decoding.
'''
dec: msgpack.Decoder = getattr(codec, 'dec', codec) dec: msgpack.Decoder = getattr(codec, 'dec', codec)
return join_char.join( return join_char.join(
mk_msgspec_table( mk_msgspec_table(
@ -643,57 +630,31 @@ def limit_msg_spec(
# # import pdbp; pdbp.set_trace() # # import pdbp; pdbp.set_trace()
# assert ext_codec.pld_spec == extended_spec # assert ext_codec.pld_spec == extended_spec
# yield ext_codec # yield ext_codec
# TODO: make something similar to this inside `._codec` such that
# user can just pass a type table of some sort?
# -[ ] we would need to decode all msgs to `pretty_struct.Struct`
# and then call `.to_dict()` on them?
# -[x] we're going to need to re-impl all the stuff changed in the
# runtime port such that it can handle dicts or `Msg`s?
# #
# ^-TODO-^ is it impossible to make something like this orr!? # def mk_dict_msg_codec_hooks() -> tuple[Callable, Callable]:
# '''
# TODO: make an auto-custom hook generator from a set of input custom # Deliver a `enc_hook()`/`dec_hook()` pair which does
# types? # manual convertion from our above native `Msg` set
# -[ ] below is a proto design using a `TypeCodec` idea? # to `dict` equivalent (wire msgs) in order to keep legacy compat
# with the original runtime implementation.
# #
# type var for the expected interchange-lib's # Note: this is is/was primarly used while moving the core
# IPC-transport type when not available as a built-in # runtime over to using native `Msg`-struct types wherein we
# serialization output. # start with the send side emitting without loading
WireT = TypeVar('WireT') # a typed-decoder and then later flipping the switch over to
# load to the native struct types once all runtime usage has
# been adjusted appropriately.
# TODO: some kinda (decorator) API for built-in subtypes #
# that builds this implicitly by inspecting the `mro()`? # '''
class TypeCodec(Protocol): # return (
''' # # enc_to_dict,
A per-custom-type wire-transport serialization translator # dec_from_dict,
description type. # )
'''
src_type: Type
wire_type: WireT
def encode(obj: Type) -> WireT:
...
def decode(
obj_type: Type[WireT],
obj: WireT,
) -> Type:
...
class MsgpackTypeCodec(TypeCodec):
...
def mk_codec_hooks(
type_codecs: list[TypeCodec],
) -> tuple[Callable, Callable]:
'''
Deliver a `enc_hook()`/`dec_hook()` pair which handle
manual convertion from an input `Type` set such that whenever
the `TypeCodec.filter()` predicate matches the
`TypeCodec.decode()` is called on the input native object by
the `dec_hook()` and whenever the
`isiinstance(obj, TypeCodec.type)` matches against an
`enc_hook(obj=obj)` the return value is taken from a
`TypeCodec.encode(obj)` callback.
'''
...

View File

@ -30,9 +30,9 @@ from msgspec import (
Struct as _Struct, Struct as _Struct,
structs, structs,
) )
# from pprint import ( from pprint import (
# saferepr, saferepr,
# ) )
from tractor.log import get_logger from tractor.log import get_logger
@ -75,8 +75,8 @@ class DiffDump(UserList):
for k, left, right in self: for k, left, right in self:
repstr += ( repstr += (
f'({k},\n' f'({k},\n'
f' |_{repr(left)},\n' f'\t{repr(left)},\n'
f' |_{repr(right)},\n' f'\t{repr(right)},\n'
')\n' ')\n'
) )
repstr += ']\n' repstr += ']\n'
@ -144,22 +144,15 @@ def pformat(
field_indent=indent + field_indent, field_indent=indent + field_indent,
) )
else: else: # the `pprint` recursion-safe format:
val_str: str = repr(v)
# XXX LOL, below just seems to be f#$%in causing
# recursion errs..
#
# the `pprint` recursion-safe format:
# https://docs.python.org/3.11/library/pprint.html#pprint.saferepr # https://docs.python.org/3.11/library/pprint.html#pprint.saferepr
# try: try:
# val_str: str = saferepr(v) val_str: str = saferepr(v)
# except Exception: except Exception:
# log.exception( log.exception(
# 'Failed to `saferepr({type(struct)})` !?\n' 'Failed to `saferepr({type(struct)})` !?\n'
# ) )
# raise return _Struct.__repr__(struct)
# return _Struct.__repr__(struct)
# TODO: LOLOL use `textwrap.indent()` instead dawwwwwg! # TODO: LOLOL use `textwrap.indent()` instead dawwwwwg!
obj_str += (field_ws + f'{k}: {typ_name} = {val_str},\n') obj_str += (field_ws + f'{k}: {typ_name} = {val_str},\n')
@ -210,7 +203,12 @@ class Struct(
return sin_props return sin_props
pformat = pformat pformat = pformat
# __repr__ = pformat
# __str__ = __repr__ = pformat
# TODO: use a pprint.PrettyPrinter instance around ONLY rendering
# inside a known tty?
# def __repr__(self) -> str:
# ...
def __repr__(self) -> str: def __repr__(self) -> str:
try: try:
return pformat(self) return pformat(self)
@ -220,13 +218,6 @@ class Struct(
) )
return _Struct.__repr__(self) return _Struct.__repr__(self)
# __repr__ = pformat
# __str__ = __repr__ = pformat
# TODO: use a pprint.PrettyPrinter instance around ONLY rendering
# inside a known tty?
# def __repr__(self) -> str:
# ...
def copy( def copy(
self, self,
update: dict | None = None, update: dict | None = None,
@ -276,15 +267,13 @@ class Struct(
fi.type(getattr(self, fi.name)), fi.type(getattr(self, fi.name)),
) )
# TODO: make a mod func instead and just point to it here for
# method impl?
def __sub__( def __sub__(
self, self,
other: Struct, other: Struct,
) -> DiffDump[tuple[str, Any, Any]]: ) -> DiffDump[tuple[str, Any, Any]]:
''' '''
Compare fields/items key-wise and return a `DiffDump` Compare fields/items key-wise and return a ``DiffDump``
for easy visual REPL comparison B) for easy visual REPL comparison B)
''' '''
@ -301,42 +290,3 @@ class Struct(
)) ))
return diffs return diffs
@classmethod
def fields_diff(
cls,
other: dict|Struct,
) -> DiffDump[tuple[str, Any, Any]]:
'''
Very similar to `PrettyStruct.__sub__()` except accepts an
input `other: dict` (presumably that would normally be called
like `Struct(**other)`) which returns a `DiffDump` of the
fields of the struct and the `dict`'s fields.
'''
nullish = object()
consumed: dict = other.copy()
diffs: DiffDump[tuple[str, Any, Any]] = DiffDump()
for fi in structs.fields(cls):
field_name: str = fi.name
# ours: Any = getattr(self, field_name)
theirs: Any = consumed.pop(field_name, nullish)
if theirs is nullish:
diffs.append((
field_name,
f'{fi.type!r}',
'NOT-DEFINED in `other: dict`',
))
# when there are lingering fields in `other` that this struct
# DOES NOT define we also append those.
if consumed:
for k, v in consumed.items():
diffs.append((
k,
f'NOT-DEFINED for `{cls.__name__}`',
f'`other: dict` has value = {v!r}',
))
return diffs

View File

@ -245,14 +245,14 @@ def _run_asyncio_task(
result != orig and result != orig and
aio_err is None and aio_err is None and
# in the `open_channel_from()` case we don't # in the ``open_channel_from()`` case we don't
# relay through the "return value". # relay through the "return value".
not provide_channels not provide_channels
): ):
to_trio.send_nowait(result) to_trio.send_nowait(result)
finally: finally:
# if the task was spawned using `open_channel_from()` # if the task was spawned using ``open_channel_from()``
# then we close the channels on exit. # then we close the channels on exit.
if provide_channels: if provide_channels:
# only close the sender side which will relay # only close the sender side which will relay
@ -500,7 +500,7 @@ async def run_task(
''' '''
# simple async func # simple async func
chan: LinkedTaskChannel = _run_asyncio_task( chan = _run_asyncio_task(
func, func,
qsize=1, qsize=1,
**kwargs, **kwargs,
@ -530,7 +530,7 @@ async def open_channel_from(
spawned ``asyncio`` task and ``trio``. spawned ``asyncio`` task and ``trio``.
''' '''
chan: LinkedTaskChannel = _run_asyncio_task( chan = _run_asyncio_task(
target, target,
qsize=2**8, qsize=2**8,
provide_channels=True, provide_channels=True,

View File

@ -382,7 +382,7 @@ class BroadcastReceiver(ReceiveChannel):
# likely it makes sense to unwind back to the # likely it makes sense to unwind back to the
# underlying? # underlying?
# import tractor # import tractor
# await tractor.pause() # await tractor.breakpoint()
log.warning( log.warning(
f'Only one sub left for {self}?\n' f'Only one sub left for {self}?\n'
'We can probably unwind from breceiver?' 'We can probably unwind from breceiver?'