forked from goodboy/tractor
commit
2674c54c0b
|
@ -0,0 +1,31 @@
|
|||
import tractor
|
||||
import trio
|
||||
|
||||
|
||||
async def breakpoint_forever():
|
||||
"Indefinitely re-enter debugger in child actor."
|
||||
while True:
|
||||
yield 'yo'
|
||||
await tractor.breakpoint()
|
||||
|
||||
|
||||
async def name_error():
|
||||
"Raise a ``NameError``"
|
||||
getattr(doggypants)
|
||||
|
||||
|
||||
async def main():
|
||||
"""Test breakpoint in a streaming actor.
|
||||
"""
|
||||
async with tractor.open_nursery() as n:
|
||||
|
||||
p0 = await n.start_actor('bp_forever', rpc_module_paths=[__name__])
|
||||
p1 = await n.start_actor('name_error', rpc_module_paths=[__name__])
|
||||
|
||||
# retreive results
|
||||
stream = await p0.run(__name__, 'breakpoint_forever')
|
||||
await p1.run(__name__, 'name_error')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tractor.run(main, debug_mode=True, loglevel='error')
|
|
@ -282,6 +282,34 @@ def test_multi_subactors(spawn):
|
|||
assert 'bdb.BdbQuit' in before
|
||||
|
||||
|
||||
def test_multi_daemon_subactors(spawn):
|
||||
"""Multiple daemon subactors, both erroring and breakpointing within a
|
||||
stream.
|
||||
"""
|
||||
child = spawn('multi_daemon_subactors')
|
||||
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
|
||||
before = str(child.before.decode())
|
||||
assert "Attaching pdb to actor: ('bp_forever'" in before
|
||||
|
||||
child.sendline('c')
|
||||
|
||||
# first name_error failure
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "NameError" in before
|
||||
|
||||
child.sendline('c')
|
||||
|
||||
child.expect(r"\(Pdb\+\+\)")
|
||||
before = str(child.before.decode())
|
||||
assert "tractor._exceptions.RemoteActorError: ('name_error'" in before
|
||||
|
||||
child.sendline('c')
|
||||
child.expect(pexpect.EOF)
|
||||
|
||||
|
||||
def test_multi_subactors_root_errors(spawn):
|
||||
"""Multiple subactors, both erroring and breakpointing as well as
|
||||
a nested subactor erroring.
|
||||
|
|
|
@ -20,8 +20,8 @@ from ._state import current_actor
|
|||
from . import _state
|
||||
from ._exceptions import RemoteActorError, ModuleNotExposed
|
||||
from ._debug import breakpoint, post_mortem
|
||||
from . import msg
|
||||
from . import _spawn
|
||||
from . import msg
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
@ -60,16 +60,23 @@ async def _main(
|
|||
"""
|
||||
logger = log.get_logger('tractor')
|
||||
|
||||
# mark top most level process as root actor
|
||||
_state._runtime_vars['_is_root'] = True
|
||||
|
||||
if start_method is not None:
|
||||
_spawn.try_set_start_method(start_method)
|
||||
|
||||
if debug_mode and _spawn._spawn_method == 'trio':
|
||||
_state._runtime_vars['_debug_mode'] = True
|
||||
|
||||
# expose internal debug module to every actor allowing
|
||||
# for use of ``await tractor.breakpoint()``
|
||||
kwargs.setdefault('rpc_module_paths', []).append('tractor._debug')
|
||||
|
||||
elif debug_mode:
|
||||
raise RuntimeError("Debug mode is only supported for the `trio` backend!")
|
||||
raise RuntimeError(
|
||||
"Debug mode is only supported for the `trio` backend!"
|
||||
)
|
||||
|
||||
main = partial(async_fn, *args)
|
||||
|
||||
|
@ -134,9 +141,6 @@ def run(
|
|||
|
||||
This is tractor's main entry and the start point for any async actor.
|
||||
"""
|
||||
# mark top most level process as root actor
|
||||
_state._runtime_vars['_is_root'] = True
|
||||
|
||||
return trio.run(
|
||||
partial(
|
||||
# our entry
|
||||
|
|
|
@ -301,7 +301,18 @@ class Actor:
|
|||
try:
|
||||
return getattr(self._mods[ns], funcname)
|
||||
except KeyError as err:
|
||||
raise ModuleNotExposed(*err.args)
|
||||
mne = ModuleNotExposed(*err.args)
|
||||
|
||||
if ns == '__main__':
|
||||
msg = (
|
||||
"\n\nMake sure you exposed the current module using:\n\n"
|
||||
"ActorNursery.start_actor(<name>, rpc_module_paths="
|
||||
"[__name__])"
|
||||
)
|
||||
|
||||
mne.msg += msg
|
||||
|
||||
raise mne
|
||||
|
||||
async def _stream_handler(
|
||||
self,
|
||||
|
@ -591,7 +602,7 @@ class Actor:
|
|||
# Receive runtime state from our parent
|
||||
parent_data = await chan.recv()
|
||||
log.debug(
|
||||
"Recieved state from parent:\n"
|
||||
"Received state from parent:\n"
|
||||
f"{parent_data}"
|
||||
)
|
||||
accept_addr = (
|
||||
|
@ -599,6 +610,7 @@ class Actor:
|
|||
parent_data.pop('bind_port'),
|
||||
)
|
||||
rvs = parent_data.pop('_runtime_vars')
|
||||
log.debug(f"Runtime vars are: {rvs}")
|
||||
rvs['_is_root'] = False
|
||||
_state._runtime_vars.update(rvs)
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ async def get_root(
|
|||
**kwargs,
|
||||
) -> typing.AsyncGenerator[Union[Portal, LocalPortal], None]:
|
||||
host, port = _runtime_vars['_root_mailbox']
|
||||
assert host is not None
|
||||
async with _connect_chan(host, port) as chan:
|
||||
async with open_portal(chan, **kwargs) as portal:
|
||||
yield portal
|
||||
|
|
Loading…
Reference in New Issue