Compare commits
No commits in common. "9a70a214c16b4d0458e079f9ab5da1fdefc7dd14" and "93f70c63a4c7b91098aa28e6d48e4109fc0cd07b" have entirely different histories.
9a70a214c1
...
93f70c63a4
|
@ -24,9 +24,10 @@ async def spawn_until(depth=0):
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
'''
|
"""The main ``tractor`` routine.
|
||||||
The process tree should look as approximately as follows when the
|
|
||||||
debugger first engages:
|
The process tree should look as approximately as follows when the debugger
|
||||||
|
first engages:
|
||||||
|
|
||||||
python examples/debugging/multi_nested_subactors_bp_forever.py
|
python examples/debugging/multi_nested_subactors_bp_forever.py
|
||||||
├─ python -m tractor._child --uid ('spawner1', '7eab8462 ...)
|
├─ python -m tractor._child --uid ('spawner1', '7eab8462 ...)
|
||||||
|
@ -36,11 +37,10 @@ async def main():
|
||||||
└─ python -m tractor._child --uid ('spawner0', '1d42012b ...)
|
└─ python -m tractor._child --uid ('spawner0', '1d42012b ...)
|
||||||
└─ python -m tractor._child --uid ('name_error', '6c2733b8 ...)
|
└─ python -m tractor._child --uid ('name_error', '6c2733b8 ...)
|
||||||
|
|
||||||
'''
|
"""
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
loglevel='devx',
|
loglevel='warning'
|
||||||
enable_transports=['uds'],
|
|
||||||
) as n:
|
) as n:
|
||||||
|
|
||||||
# spawn both actors
|
# spawn both actors
|
||||||
|
|
|
@ -37,7 +37,6 @@ async def main(
|
||||||
enable_stack_on_sig=True,
|
enable_stack_on_sig=True,
|
||||||
# maybe_enable_greenback=False,
|
# maybe_enable_greenback=False,
|
||||||
loglevel='devx',
|
loglevel='devx',
|
||||||
enable_transports=['uds'],
|
|
||||||
) as an,
|
) as an,
|
||||||
):
|
):
|
||||||
ptl: tractor.Portal = await an.start_actor(
|
ptl: tractor.Portal = await an.start_actor(
|
||||||
|
|
|
@ -33,11 +33,8 @@ async def just_bp(
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
|
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
debug_mode=True,
|
debug_mode=True,
|
||||||
enable_transports=['uds'],
|
|
||||||
loglevel='devx',
|
|
||||||
) as n:
|
) as n:
|
||||||
p = await n.start_actor(
|
p = await n.start_actor(
|
||||||
'bp_boi',
|
'bp_boi',
|
||||||
|
|
|
@ -10,14 +10,10 @@ TODO:
|
||||||
- wonder if any of it'll work on OS X?
|
- wonder if any of it'll work on OS X?
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import itertools
|
import itertools
|
||||||
import platform
|
import platform
|
||||||
import time
|
import time
|
||||||
from typing import (
|
|
||||||
TYPE_CHECKING,
|
|
||||||
)
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pexpect.exceptions import (
|
from pexpect.exceptions import (
|
||||||
|
@ -38,9 +34,6 @@ from .conftest import (
|
||||||
assert_before,
|
assert_before,
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from ..conftest import PexpectSpawner
|
|
||||||
|
|
||||||
# TODO: The next great debugger audit could be done by you!
|
# TODO: The next great debugger audit could be done by you!
|
||||||
# - recurrent entry to breakpoint() from single actor *after* and an
|
# - recurrent entry to breakpoint() from single actor *after* and an
|
||||||
# error in another task?
|
# error in another task?
|
||||||
|
@ -1069,88 +1062,6 @@ def test_shield_pause(
|
||||||
child.expect(EOF)
|
child.expect(EOF)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
'quit_early', [False, True]
|
|
||||||
)
|
|
||||||
def test_ctxep_pauses_n_maybe_ipc_breaks(
|
|
||||||
spawn: PexpectSpawner,
|
|
||||||
quit_early: bool,
|
|
||||||
):
|
|
||||||
'''
|
|
||||||
Audit generator embedded `.pause()`es from within a `@context`
|
|
||||||
endpoint with a chan close at the end, requiring that ctl-c is
|
|
||||||
mashed and zombie reaper kills sub with no hangs.
|
|
||||||
|
|
||||||
'''
|
|
||||||
child = spawn('subactor_bp_in_ctx')
|
|
||||||
child.expect(PROMPT)
|
|
||||||
|
|
||||||
# 3 iters for the `gen()` pause-points
|
|
||||||
for i in range(3):
|
|
||||||
assert_before(
|
|
||||||
child,
|
|
||||||
[
|
|
||||||
_pause_msg,
|
|
||||||
"('bp_boi'", # actor name
|
|
||||||
"<Task 'just_bp'", # task name
|
|
||||||
]
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
i == 1
|
|
||||||
and
|
|
||||||
quit_early
|
|
||||||
):
|
|
||||||
child.sendline('q')
|
|
||||||
child.expect(PROMPT)
|
|
||||||
assert_before(
|
|
||||||
child,
|
|
||||||
["tractor._exceptions.RemoteActorError: remote task raised a 'BdbQuit'",
|
|
||||||
"bdb.BdbQuit",
|
|
||||||
"('bp_boi'",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
child.sendline('c')
|
|
||||||
child.expect(EOF)
|
|
||||||
assert_before(
|
|
||||||
child,
|
|
||||||
["tractor._exceptions.RemoteActorError: remote task raised a 'BdbQuit'",
|
|
||||||
"bdb.BdbQuit",
|
|
||||||
"('bp_boi'",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
break # end-of-test
|
|
||||||
|
|
||||||
child.sendline('c')
|
|
||||||
try:
|
|
||||||
child.expect(PROMPT)
|
|
||||||
except TIMEOUT:
|
|
||||||
# no prompt since we hang due to IPC chan purposely
|
|
||||||
# closed so verify we see error reporting as well as
|
|
||||||
# a failed crash-REPL request msg and can CTL-c our way
|
|
||||||
# out.
|
|
||||||
assert_before(
|
|
||||||
child,
|
|
||||||
['peer IPC channel closed abruptly?',
|
|
||||||
'another task closed this fd',
|
|
||||||
'Debug lock request was CANCELLED?',
|
|
||||||
"TransportClosed: 'MsgpackUDSStream' was already closed locally ?",]
|
|
||||||
|
|
||||||
# XXX races on whether these show/hit?
|
|
||||||
# 'Failed to REPl via `_pause()` You called `tractor.pause()` from an already cancelled scope!',
|
|
||||||
# 'AssertionError',
|
|
||||||
)
|
|
||||||
# OSc(ancel) the hanging tree
|
|
||||||
do_ctlc(
|
|
||||||
child=child,
|
|
||||||
expect_prompt=False,
|
|
||||||
)
|
|
||||||
child.expect(EOF)
|
|
||||||
assert_before(
|
|
||||||
child,
|
|
||||||
['KeyboardInterrupt'],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: better error for "non-ideal" usage from the root actor.
|
# TODO: better error for "non-ideal" usage from the root actor.
|
||||||
# -[ ] if called from an async scope emit a message that suggests
|
# -[ ] if called from an async scope emit a message that suggests
|
||||||
# using `await tractor.pause()` instead since it's less overhead
|
# using `await tractor.pause()` instead since it's less overhead
|
||||||
|
|
|
@ -135,12 +135,12 @@ 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'
|
||||||
+
|
+
|
||||||
pformat.nest_from_op(
|
pformat.nest_from_op(
|
||||||
input_op='>(', # see syntax ideas above
|
input_op='>(', # see syntax ideas above
|
||||||
text=actor_info,
|
tree_str=actor_info,
|
||||||
nest_indent=2, # since "complete"
|
back_from_op=2, # since "complete"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
logmeth = log.info
|
logmeth = log.info
|
||||||
|
@ -149,8 +149,8 @@ def _trio_main(
|
||||||
+
|
+
|
||||||
pformat.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
|
||||||
text=actor_info,
|
tree_str=actor_info,
|
||||||
nest_indent=1,
|
back_from_op=1,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
|
@ -167,7 +167,7 @@ def _trio_main(
|
||||||
+
|
+
|
||||||
pformat.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)
|
||||||
text=actor_info,
|
tree_str=actor_info,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except BaseException as err:
|
except BaseException as err:
|
||||||
|
@ -177,7 +177,7 @@ def _trio_main(
|
||||||
+
|
+
|
||||||
pformat.nest_from_op(
|
pformat.nest_from_op(
|
||||||
input_op='x)>', # closed by error
|
input_op='x)>', # closed by error
|
||||||
text=actor_info,
|
tree_str=actor_info,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# NOTE since we raise a tb will already be shown on the
|
# NOTE since we raise a tb will already be shown on the
|
||||||
|
|
|
@ -521,7 +521,7 @@ async def open_root_actor(
|
||||||
|
|
||||||
op_nested_actor_repr: str = _pformat.nest_from_op(
|
op_nested_actor_repr: str = _pformat.nest_from_op(
|
||||||
input_op='>) ',
|
input_op='>) ',
|
||||||
text=actor.pformat(),
|
tree_str=actor.pformat(),
|
||||||
nest_prefix='|_',
|
nest_prefix='|_',
|
||||||
)
|
)
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
|
@ -255,7 +255,7 @@ async def _errors_relayed_via_ipc(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
is_rpc: bool,
|
is_rpc: bool,
|
||||||
|
|
||||||
hide_tb: bool = True,
|
hide_tb: bool = False,
|
||||||
debug_kbis: bool = False,
|
debug_kbis: bool = False,
|
||||||
task_status: TaskStatus[
|
task_status: TaskStatus[
|
||||||
Context | BaseException
|
Context | BaseException
|
||||||
|
@ -380,9 +380,9 @@ async def _errors_relayed_via_ipc(
|
||||||
# they can be individually ccancelled.
|
# they can be individually ccancelled.
|
||||||
finally:
|
finally:
|
||||||
|
|
||||||
# if the error is not from user code and instead a failure of
|
# if the error is not from user code and instead a failure
|
||||||
# an internal-runtime-RPC or IPC-connection, we do (prolly) want
|
# of a runtime RPC or transport failure we do prolly want to
|
||||||
# to show this frame!
|
# show this frame
|
||||||
if (
|
if (
|
||||||
rpc_err
|
rpc_err
|
||||||
and (
|
and (
|
||||||
|
|
|
@ -1698,10 +1698,10 @@ async def async_main(
|
||||||
)
|
)
|
||||||
|
|
||||||
op_nested_actor_repr: str = _pformat.nest_from_op(
|
op_nested_actor_repr: str = _pformat.nest_from_op(
|
||||||
input_op=')>',
|
input_op=')> ',
|
||||||
text=actor.pformat(),
|
tree_str=actor.pformat(),
|
||||||
nest_prefix='|_',
|
nest_prefix='|_',
|
||||||
nest_indent=1, # under >
|
back_from_op=2,
|
||||||
)
|
)
|
||||||
teardown_report += (
|
teardown_report += (
|
||||||
'Actor runtime exited\n'
|
'Actor runtime exited\n'
|
||||||
|
|
|
@ -593,10 +593,9 @@ async def _open_and_supervise_one_cancels_all_nursery(
|
||||||
# final exit
|
# final exit
|
||||||
|
|
||||||
|
|
||||||
# @api_frame
|
|
||||||
@acm
|
@acm
|
||||||
|
# @api_frame
|
||||||
async def open_nursery(
|
async def open_nursery(
|
||||||
*, # named params only!
|
|
||||||
hide_tb: bool = True,
|
hide_tb: bool = True,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
# ^TODO, paramspec for `open_root_actor()`
|
# ^TODO, paramspec for `open_root_actor()`
|
||||||
|
|
|
@ -249,29 +249,14 @@ def pformat_cs(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: move this func to some kinda `.devx.pformat.py` eventually
|
||||||
|
# as we work out our multi-domain state-flow-syntax!
|
||||||
def nest_from_op(
|
def nest_from_op(
|
||||||
input_op: str, # TODO, Literal of all op-"symbols" from below?
|
input_op: str,
|
||||||
text: str, # TODO? better name, like `text`?
|
|
||||||
|
|
||||||
nest_prefix: str = '|_',
|
|
||||||
nest_indent: int = 0,
|
|
||||||
# XXX indent `next_prefix` "to-the-right-of" `input_op`
|
|
||||||
# by this count of whitespaces (' ').
|
|
||||||
|
|
||||||
) -> 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
|
# ?TODO? an idea for a syntax to the state of concurrent systems
|
||||||
# concurrent systems as a "3-domain" (execution, scope, storage)
|
# as a "3-domain" (execution, scope, storage) model and using
|
||||||
# model and using a minimal ascii/utf-8 operator-set.
|
# a minimal ascii/utf-8 operator-set.
|
||||||
#
|
#
|
||||||
# try not to take any of this seriously yet XD
|
# try not to take any of this seriously yet XD
|
||||||
#
|
#
|
||||||
|
@ -337,29 +322,37 @@ def nest_from_op(
|
||||||
#
|
#
|
||||||
# =>{ recv-req to open
|
# =>{ recv-req to open
|
||||||
# <={ send-status that it closed
|
# <={ send-status that it closed
|
||||||
#
|
|
||||||
if (
|
|
||||||
nest_prefix
|
|
||||||
and
|
|
||||||
nest_indent
|
|
||||||
):
|
|
||||||
nest_prefix: str = textwrap.indent(
|
|
||||||
nest_prefix,
|
|
||||||
prefix=nest_indent*' ',
|
|
||||||
)
|
|
||||||
|
|
||||||
tree_str_indent: int = len(nest_prefix)
|
tree_str: str,
|
||||||
|
|
||||||
|
# NOTE: so move back-from-the-left of the `input_op` by
|
||||||
|
# this amount.
|
||||||
|
back_from_op: int = 0,
|
||||||
|
nest_prefix: str = ''
|
||||||
|
|
||||||
|
) -> 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.
|
||||||
|
|
||||||
|
'''
|
||||||
indented_tree_str: str = textwrap.indent(
|
indented_tree_str: str = textwrap.indent(
|
||||||
text,
|
tree_str,
|
||||||
prefix=' '*tree_str_indent
|
prefix=' ' *(
|
||||||
|
len(input_op)
|
||||||
|
-
|
||||||
|
(back_from_op + 1)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
# inject any provided nesting-prefix chars
|
# inject any provided nesting-prefix chars
|
||||||
# into the head of the first line.
|
# into the head of the first line.
|
||||||
if nest_prefix:
|
if nest_prefix:
|
||||||
indented_tree_str: str = (
|
indented_tree_str: str = (
|
||||||
f'{nest_prefix}{indented_tree_str[tree_str_indent:]}'
|
f'{nest_prefix}'
|
||||||
|
f'{indented_tree_str[len(nest_prefix):]}'
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
f'{input_op}\n'
|
f'{input_op}\n'
|
||||||
f'{indented_tree_str}'
|
f'{indented_tree_str}'
|
||||||
|
|
Loading…
Reference in New Issue