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
|
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):
|
def test_multi_subactors_root_errors(spawn):
|
||||||
"""Multiple subactors, both erroring and breakpointing as well as
|
"""Multiple subactors, both erroring and breakpointing as well as
|
||||||
a nested subactor erroring.
|
a nested subactor erroring.
|
||||||
|
|
|
@ -20,8 +20,8 @@ from ._state import current_actor
|
||||||
from . import _state
|
from . import _state
|
||||||
from ._exceptions import RemoteActorError, ModuleNotExposed
|
from ._exceptions import RemoteActorError, ModuleNotExposed
|
||||||
from ._debug import breakpoint, post_mortem
|
from ._debug import breakpoint, post_mortem
|
||||||
from . import msg
|
|
||||||
from . import _spawn
|
from . import _spawn
|
||||||
|
from . import msg
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -60,16 +60,23 @@ async def _main(
|
||||||
"""
|
"""
|
||||||
logger = log.get_logger('tractor')
|
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:
|
if start_method is not None:
|
||||||
_spawn.try_set_start_method(start_method)
|
_spawn.try_set_start_method(start_method)
|
||||||
|
|
||||||
if debug_mode and _spawn._spawn_method == 'trio':
|
if debug_mode and _spawn._spawn_method == 'trio':
|
||||||
_state._runtime_vars['_debug_mode'] = True
|
_state._runtime_vars['_debug_mode'] = True
|
||||||
|
|
||||||
# expose internal debug module to every actor allowing
|
# expose internal debug module to every actor allowing
|
||||||
# for use of ``await tractor.breakpoint()``
|
# for use of ``await tractor.breakpoint()``
|
||||||
kwargs.setdefault('rpc_module_paths', []).append('tractor._debug')
|
kwargs.setdefault('rpc_module_paths', []).append('tractor._debug')
|
||||||
|
|
||||||
elif debug_mode:
|
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)
|
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.
|
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(
|
return trio.run(
|
||||||
partial(
|
partial(
|
||||||
# our entry
|
# our entry
|
||||||
|
|
|
@ -301,7 +301,18 @@ class Actor:
|
||||||
try:
|
try:
|
||||||
return getattr(self._mods[ns], funcname)
|
return getattr(self._mods[ns], funcname)
|
||||||
except KeyError as err:
|
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(
|
async def _stream_handler(
|
||||||
self,
|
self,
|
||||||
|
@ -591,7 +602,7 @@ class Actor:
|
||||||
# Receive runtime state from our parent
|
# Receive runtime state from our parent
|
||||||
parent_data = await chan.recv()
|
parent_data = await chan.recv()
|
||||||
log.debug(
|
log.debug(
|
||||||
"Recieved state from parent:\n"
|
"Received state from parent:\n"
|
||||||
f"{parent_data}"
|
f"{parent_data}"
|
||||||
)
|
)
|
||||||
accept_addr = (
|
accept_addr = (
|
||||||
|
@ -599,6 +610,7 @@ class Actor:
|
||||||
parent_data.pop('bind_port'),
|
parent_data.pop('bind_port'),
|
||||||
)
|
)
|
||||||
rvs = parent_data.pop('_runtime_vars')
|
rvs = parent_data.pop('_runtime_vars')
|
||||||
|
log.debug(f"Runtime vars are: {rvs}")
|
||||||
rvs['_is_root'] = False
|
rvs['_is_root'] = False
|
||||||
_state._runtime_vars.update(rvs)
|
_state._runtime_vars.update(rvs)
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ async def get_root(
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> typing.AsyncGenerator[Union[Portal, LocalPortal], None]:
|
) -> typing.AsyncGenerator[Union[Portal, LocalPortal], None]:
|
||||||
host, port = _runtime_vars['_root_mailbox']
|
host, port = _runtime_vars['_root_mailbox']
|
||||||
|
assert host is not None
|
||||||
async with _connect_chan(host, port) as chan:
|
async with _connect_chan(host, port) as chan:
|
||||||
async with open_portal(chan, **kwargs) as portal:
|
async with open_portal(chan, **kwargs) as portal:
|
||||||
yield portal
|
yield portal
|
||||||
|
|
Loading…
Reference in New Issue