Formally add a `nest_from_op()` for "sclang"-fmting
Moving it from where i (oddly) first wrote it up in `._entry` to a more proper place with its pals in `.devx.pformat` ;p Iface summary, what caller provides: - `input_op`: a "sclang" chars-symbol to represent the conc "operation", - `text`: the "entity" being *operated on*, - `nest_prefix/indent`: what the ^ will be prefixed with. - `prefix_op: bool` so that, when unset, the `input_op` is instead used as a suffix to the first line of `text`. - `next_indent: int|None = None` such that when set (and not null) we use that exact ws-indent instead of calculating it from the `len(nest_prefix)` allowing for specifying a `0`-indent easily. - includes logic where we either get a non-zero value and apply it strictly to both the `nest_prefix` and `text`, OR we auto-calc it from any `nest_prefix`, NOT a conflation of both.. - `op_suffix: str = '\n'` for instead of assuming `f'{input_op}\n'`. - `rm_from_first_ln: str` which allows removing chars from the first line of `text` after a `str.strip()` (handy for removing the '<Channel' first chevron from type-reprs). There's also a huge comment-doc for "sclang" into the fn body which is the terrible "primer" on this whole idea for the moment XDmain
parent
2248ffb74f
commit
fc57a4d639
|
@ -22,7 +22,6 @@ from __future__ import annotations
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import os
|
import os
|
||||||
import textwrap
|
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
|
@ -35,7 +34,10 @@ from .log import (
|
||||||
get_logger,
|
get_logger,
|
||||||
)
|
)
|
||||||
from . import _state
|
from . import _state
|
||||||
from .devx import _debug
|
from .devx import (
|
||||||
|
_debug,
|
||||||
|
pformat,
|
||||||
|
)
|
||||||
from .to_asyncio import run_as_asyncio_guest
|
from .to_asyncio import run_as_asyncio_guest
|
||||||
from ._addr import UnwrappedAddress
|
from ._addr import UnwrappedAddress
|
||||||
from ._runtime import (
|
from ._runtime import (
|
||||||
|
@ -103,107 +105,6 @@ def _mp_main(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# TODO: move this func to some kinda `.devx._conc_lang.py` eventually
|
|
||||||
# as we work out our multi-domain state-flow-syntax!
|
|
||||||
def nest_from_op(
|
|
||||||
input_op: str,
|
|
||||||
#
|
|
||||||
# ?TODO? an idea for a syntax to the state of concurrent systems
|
|
||||||
# as a "3-domain" (execution, scope, storage) model and using
|
|
||||||
# a minimal ascii/utf-8 operator-set.
|
|
||||||
#
|
|
||||||
# try not to take any of this seriously yet XD
|
|
||||||
#
|
|
||||||
# > is a "play operator" indicating (CPU bound)
|
|
||||||
# exec/work/ops required at the "lowest level computing"
|
|
||||||
#
|
|
||||||
# execution primititves (tasks, threads, actors..) denote their
|
|
||||||
# lifetime with '(' and ')' since parentheses normally are used
|
|
||||||
# in many langs to denote function calls.
|
|
||||||
#
|
|
||||||
# starting = (
|
|
||||||
# >( opening/starting; beginning of the thread-of-exec (toe?)
|
|
||||||
# (> opened/started, (finished spawning toe)
|
|
||||||
# |_<Task: blah blah..> repr of toe, in py these look like <objs>
|
|
||||||
#
|
|
||||||
# >) closing/exiting/stopping,
|
|
||||||
# )> closed/exited/stopped,
|
|
||||||
# |_<Task: blah blah..>
|
|
||||||
# [OR <), )< ?? ]
|
|
||||||
#
|
|
||||||
# ending = )
|
|
||||||
# >c) cancelling to close/exit
|
|
||||||
# c)> cancelled (caused close), OR?
|
|
||||||
# |_<Actor: ..>
|
|
||||||
# OR maybe "<c)" which better indicates the cancel being
|
|
||||||
# "delivered/returned" / returned" to LHS?
|
|
||||||
#
|
|
||||||
# >x) erroring to eventuall exit
|
|
||||||
# x)> errored and terminated
|
|
||||||
# |_<Actor: ...>
|
|
||||||
#
|
|
||||||
# scopes: supers/nurseries, IPC-ctxs, sessions, perms, etc.
|
|
||||||
# >{ opening
|
|
||||||
# {> opened
|
|
||||||
# }> closed
|
|
||||||
# >} closing
|
|
||||||
#
|
|
||||||
# storage: like queues, shm-buffers, files, etc..
|
|
||||||
# >[ opening
|
|
||||||
# [> opened
|
|
||||||
# |_<FileObj: ..>
|
|
||||||
#
|
|
||||||
# >] closing
|
|
||||||
# ]> closed
|
|
||||||
|
|
||||||
# IPC ops: channels, transports, msging
|
|
||||||
# => req msg
|
|
||||||
# <= resp msg
|
|
||||||
# <=> 2-way streaming (of msgs)
|
|
||||||
# <- recv 1 msg
|
|
||||||
# -> send 1 msg
|
|
||||||
#
|
|
||||||
# TODO: still not sure on R/L-HS approach..?
|
|
||||||
# =>( send-req to exec start (task, actor, thread..)
|
|
||||||
# (<= recv-req to ^
|
|
||||||
#
|
|
||||||
# (<= recv-req ^
|
|
||||||
# <=( recv-resp opened remote exec primitive
|
|
||||||
# <=) recv-resp closed
|
|
||||||
#
|
|
||||||
# )<=c req to stop due to cancel
|
|
||||||
# c=>) req to stop due to cancel
|
|
||||||
#
|
|
||||||
# =>{ recv-req to open
|
|
||||||
# <={ send-status that it closed
|
|
||||||
|
|
||||||
tree_str: str,
|
|
||||||
|
|
||||||
# NOTE: so move back-from-the-left of the `input_op` by
|
|
||||||
# this amount.
|
|
||||||
back_from_op: int = 0,
|
|
||||||
) -> str:
|
|
||||||
'''
|
|
||||||
Depth-increment the input (presumably hierarchy/supervision)
|
|
||||||
input "tree string" below the provided `input_op` execution
|
|
||||||
operator, so injecting a `"\n|_{input_op}\n"`and indenting the
|
|
||||||
`tree_str` to nest content aligned with the ops last char.
|
|
||||||
|
|
||||||
'''
|
|
||||||
return (
|
|
||||||
f'{input_op}\n'
|
|
||||||
+
|
|
||||||
textwrap.indent(
|
|
||||||
tree_str,
|
|
||||||
prefix=(
|
|
||||||
len(input_op)
|
|
||||||
-
|
|
||||||
(back_from_op + 1)
|
|
||||||
) * ' ',
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _trio_main(
|
def _trio_main(
|
||||||
actor: Actor,
|
actor: Actor,
|
||||||
*,
|
*,
|
||||||
|
@ -234,9 +135,9 @@ def _trio_main(
|
||||||
f' loglevel: {actor.loglevel}\n'
|
f' loglevel: {actor.loglevel}\n'
|
||||||
)
|
)
|
||||||
log.info(
|
log.info(
|
||||||
'Starting new `trio` subactor:\n'
|
'Starting new `trio` subactor\n'
|
||||||
+
|
+
|
||||||
nest_from_op(
|
pformat.nest_from_op(
|
||||||
input_op='>(', # see syntax ideas above
|
input_op='>(', # see syntax ideas above
|
||||||
tree_str=actor_info,
|
tree_str=actor_info,
|
||||||
back_from_op=2, # since "complete"
|
back_from_op=2, # since "complete"
|
||||||
|
@ -246,7 +147,7 @@ def _trio_main(
|
||||||
exit_status: str = (
|
exit_status: str = (
|
||||||
'Subactor exited\n'
|
'Subactor exited\n'
|
||||||
+
|
+
|
||||||
nest_from_op(
|
pformat.nest_from_op(
|
||||||
input_op=')>', # like a "closed-to-play"-icon from super perspective
|
input_op=')>', # like a "closed-to-play"-icon from super perspective
|
||||||
tree_str=actor_info,
|
tree_str=actor_info,
|
||||||
back_from_op=1,
|
back_from_op=1,
|
||||||
|
@ -264,7 +165,7 @@ def _trio_main(
|
||||||
exit_status: str = (
|
exit_status: str = (
|
||||||
'Actor received KBI (aka an OS-cancel)\n'
|
'Actor received KBI (aka an OS-cancel)\n'
|
||||||
+
|
+
|
||||||
nest_from_op(
|
pformat.nest_from_op(
|
||||||
input_op='c)>', # closed due to cancel (see above)
|
input_op='c)>', # closed due to cancel (see above)
|
||||||
tree_str=actor_info,
|
tree_str=actor_info,
|
||||||
)
|
)
|
||||||
|
@ -274,7 +175,7 @@ def _trio_main(
|
||||||
exit_status: str = (
|
exit_status: str = (
|
||||||
'Main actor task exited due to crash?\n'
|
'Main actor task exited due to crash?\n'
|
||||||
+
|
+
|
||||||
nest_from_op(
|
pformat.nest_from_op(
|
||||||
input_op='x)>', # closed by error
|
input_op='x)>', # closed by error
|
||||||
tree_str=actor_info,
|
tree_str=actor_info,
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Pretty formatters for use throughout the code base.
|
Pretty formatters for use throughout our internals.
|
||||||
Mostly handy for logging and exception message content.
|
|
||||||
|
Handy for logging and exception message content but also for `repr()`
|
||||||
|
in REPL(s).
|
||||||
|
|
||||||
'''
|
'''
|
||||||
import sys
|
import sys
|
||||||
|
@ -224,8 +226,8 @@ def pformat_cs(
|
||||||
field_prefix: str = ' |_',
|
field_prefix: str = ' |_',
|
||||||
) -> str:
|
) -> str:
|
||||||
'''
|
'''
|
||||||
Pretty format info about a `trio.CancelScope` including most
|
Pretty format info about a `trio.CancelScope` including most of
|
||||||
of its public state and `._cancel_status`.
|
its public state and `._cancel_status`.
|
||||||
|
|
||||||
The output can be modified to show a "var name" for the
|
The output can be modified to show a "var name" for the
|
||||||
instance as a field prefix, just a simple str before each
|
instance as a field prefix, just a simple str before each
|
||||||
|
@ -247,3 +249,169 @@ def pformat_cs(
|
||||||
+
|
+
|
||||||
fields
|
fields
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def nest_from_op(
|
||||||
|
input_op: str, # TODO, Literal of all op-"symbols" from below?
|
||||||
|
text: str,
|
||||||
|
prefix_op: bool = True, # unset is to suffix the first line
|
||||||
|
# optionally suffix `text`, by def on a newline
|
||||||
|
op_suffix='\n',
|
||||||
|
|
||||||
|
nest_prefix: str = '|_',
|
||||||
|
nest_indent: int|None = None,
|
||||||
|
# XXX indent `next_prefix` "to-the-right-of" `input_op`
|
||||||
|
# by this count of whitespaces (' ').
|
||||||
|
rm_from_first_ln: str|None = None,
|
||||||
|
|
||||||
|
) -> str:
|
||||||
|
'''
|
||||||
|
Depth-increment the input (presumably hierarchy/supervision)
|
||||||
|
input "tree string" below the provided `input_op` execution
|
||||||
|
operator, so injecting a `"\n|_{input_op}\n"`and indenting the
|
||||||
|
`tree_str` to nest content aligned with the ops last char.
|
||||||
|
|
||||||
|
'''
|
||||||
|
# `sclang` "structurred-concurrency-language": an ascii-encoded
|
||||||
|
# symbolic alphabet to describe concurrent systems.
|
||||||
|
#
|
||||||
|
# ?TODO? aa more fomal idea for a syntax to the state of
|
||||||
|
# concurrent systems as a "3-domain" (execution, scope, storage)
|
||||||
|
# model and using a minimal ascii/utf-8 operator-set.
|
||||||
|
#
|
||||||
|
# try not to take any of this seriously yet XD
|
||||||
|
#
|
||||||
|
# > is a "play operator" indicating (CPU bound)
|
||||||
|
# exec/work/ops required at the "lowest level computing"
|
||||||
|
#
|
||||||
|
# execution primititves (tasks, threads, actors..) denote their
|
||||||
|
# lifetime with '(' and ')' since parentheses normally are used
|
||||||
|
# in many langs to denote function calls.
|
||||||
|
#
|
||||||
|
# starting = (
|
||||||
|
# >( opening/starting; beginning of the thread-of-exec (toe?)
|
||||||
|
# (> opened/started, (finished spawning toe)
|
||||||
|
# |_<Task: blah blah..> repr of toe, in py these look like <objs>
|
||||||
|
#
|
||||||
|
# >) closing/exiting/stopping,
|
||||||
|
# )> closed/exited/stopped,
|
||||||
|
# |_<Task: blah blah..>
|
||||||
|
# [OR <), )< ?? ]
|
||||||
|
#
|
||||||
|
# ending = )
|
||||||
|
# >c) cancelling to close/exit
|
||||||
|
# c)> cancelled (caused close), OR?
|
||||||
|
# |_<Actor: ..>
|
||||||
|
# OR maybe "<c)" which better indicates the cancel being
|
||||||
|
# "delivered/returned" / returned" to LHS?
|
||||||
|
#
|
||||||
|
# >x) erroring to eventuall exit
|
||||||
|
# x)> errored and terminated
|
||||||
|
# |_<Actor: ...>
|
||||||
|
#
|
||||||
|
# scopes: supers/nurseries, IPC-ctxs, sessions, perms, etc.
|
||||||
|
# >{ opening
|
||||||
|
# {> opened
|
||||||
|
# }> closed
|
||||||
|
# >} closing
|
||||||
|
#
|
||||||
|
# storage: like queues, shm-buffers, files, etc..
|
||||||
|
# >[ opening
|
||||||
|
# [> opened
|
||||||
|
# |_<FileObj: ..>
|
||||||
|
#
|
||||||
|
# >] closing
|
||||||
|
# ]> closed
|
||||||
|
|
||||||
|
# IPC ops: channels, transports, msging
|
||||||
|
# => req msg
|
||||||
|
# <= resp msg
|
||||||
|
# <=> 2-way streaming (of msgs)
|
||||||
|
# <- recv 1 msg
|
||||||
|
# -> send 1 msg
|
||||||
|
#
|
||||||
|
# TODO: still not sure on R/L-HS approach..?
|
||||||
|
# =>( send-req to exec start (task, actor, thread..)
|
||||||
|
# (<= recv-req to ^
|
||||||
|
#
|
||||||
|
# (<= recv-req ^
|
||||||
|
# <=( recv-resp opened remote exec primitive
|
||||||
|
# <=) recv-resp closed
|
||||||
|
#
|
||||||
|
# )<=c req to stop due to cancel
|
||||||
|
# c=>) req to stop due to cancel
|
||||||
|
#
|
||||||
|
# =>{ recv-req to open
|
||||||
|
# <={ send-status that it closed
|
||||||
|
#
|
||||||
|
if (
|
||||||
|
nest_prefix
|
||||||
|
and
|
||||||
|
nest_indent != 0
|
||||||
|
):
|
||||||
|
if nest_indent is not None:
|
||||||
|
nest_prefix: str = textwrap.indent(
|
||||||
|
nest_prefix,
|
||||||
|
prefix=nest_indent*' ',
|
||||||
|
)
|
||||||
|
nest_indent: int = len(nest_prefix)
|
||||||
|
|
||||||
|
# determine body-text indent either by,
|
||||||
|
# - using wtv explicit indent value is provided,
|
||||||
|
# OR
|
||||||
|
# - auto-calcing the indent to embed `text` under
|
||||||
|
# the `nest_prefix` if provided, **IFF** `nest_indent=None`.
|
||||||
|
tree_str_indent: int = 0
|
||||||
|
if nest_indent not in {0, None}:
|
||||||
|
tree_str_indent = nest_indent
|
||||||
|
elif (
|
||||||
|
nest_prefix
|
||||||
|
and
|
||||||
|
nest_indent != 0
|
||||||
|
):
|
||||||
|
tree_str_indent = len(nest_prefix)
|
||||||
|
|
||||||
|
indented_tree_str: str = text
|
||||||
|
if tree_str_indent:
|
||||||
|
indented_tree_str: str = textwrap.indent(
|
||||||
|
text,
|
||||||
|
prefix=' '*tree_str_indent,
|
||||||
|
)
|
||||||
|
|
||||||
|
# inject any provided nesting-prefix chars
|
||||||
|
# into the head of the first line.
|
||||||
|
if nest_prefix:
|
||||||
|
indented_tree_str: str = (
|
||||||
|
f'{nest_prefix}{indented_tree_str[tree_str_indent:]}'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not prefix_op
|
||||||
|
or
|
||||||
|
rm_from_first_ln
|
||||||
|
):
|
||||||
|
tree_lns: list[str] = indented_tree_str.splitlines()
|
||||||
|
first: str = tree_lns[0]
|
||||||
|
if rm_from_first_ln:
|
||||||
|
first = first.strip().replace(
|
||||||
|
rm_from_first_ln,
|
||||||
|
'',
|
||||||
|
)
|
||||||
|
indented_tree_str: str = '\n'.join(tree_lns[1:])
|
||||||
|
|
||||||
|
if prefix_op:
|
||||||
|
indented_tree_str = (
|
||||||
|
f'{first}\n'
|
||||||
|
f'{indented_tree_str}'
|
||||||
|
)
|
||||||
|
|
||||||
|
if prefix_op:
|
||||||
|
return (
|
||||||
|
f'{input_op}{op_suffix}'
|
||||||
|
f'{indented_tree_str}'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return (
|
||||||
|
f'{first}{input_op}{op_suffix}'
|
||||||
|
f'{indented_tree_str}'
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue