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