diff --git a/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py b/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py index f9adb25..348a5ee 100644 --- a/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py +++ b/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py @@ -12,18 +12,31 @@ async def breakpoint_forever(): while True: await tractor.breakpoint() + # NOTE: if the test never sent 'q'/'quit' commands + # on the pdb repl, without this checkpoint line the + # repl would spin in this actor forever. + # await trio.sleep(0) + async def spawn_until(depth=0): """"A nested nursery that triggers another ``NameError``. """ async with tractor.open_nursery() as n: if depth < 1: - # await n.run_in_actor('breakpoint_forever', breakpoint_forever) - await n.run_in_actor( + + await n.run_in_actor(breakpoint_forever) + + p = await n.run_in_actor( name_error, name='name_error' ) + await trio.sleep(0.5) + # rx and propagate error from child + await p.result() + else: + # recusrive call to spawn another process branching layer of + # the tree depth -= 1 await n.run_in_actor( spawn_until, @@ -53,6 +66,7 @@ async def main(): """ async with tractor.open_nursery( debug_mode=True, + # loglevel='cancel', ) as n: # spawn both actors @@ -67,8 +81,16 @@ async def main(): name='spawner1', ) + # TODO: test this case as well where the parent don't see + # the sub-actor errors by default and instead expect a user + # ctrl-c to kill the root. + with trio.move_on_after(3): + await trio.sleep_forever() + # gah still an issue here. await portal.result() + + # should never get here await portal1.result() diff --git a/tests/test_debugger.py b/tests/test_debugger.py index aa972d7..8704bb1 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -10,6 +10,7 @@ TODO: - wonder if any of it'll work on OS X? """ +import itertools from os import path from typing import Optional import platform @@ -783,24 +784,31 @@ def test_multi_nested_subactors_error_through_nurseries( timed_out_early: bool = False - for i in range(12): + for send_char in itertools.cycle(['c', 'q']): try: child.expect(r"\(Pdb\+\+\)") - child.sendline('c') - time.sleep(0.1) + child.sendline(send_char) + time.sleep(0.01) except EOF: - - # race conditions on how fast the continue is sent? - print(f"Failed early on {i}?") - timed_out_early = True break - else: - child.expect(pexpect.EOF) - if not timed_out_early: - before = str(child.before.decode()) - assert "NameError" in before + assert_before(child, [ + + # boxed source errors + "NameError: name 'doggypants' is not defined", + "tractor._exceptions.RemoteActorError: ('name_error'", + "bdb.BdbQuit", + + # first level subtrees + "tractor._exceptions.RemoteActorError: ('spawner0'", + # "tractor._exceptions.RemoteActorError: ('spawner1'", + + # propagation of errors up through nested subtrees + "tractor._exceptions.RemoteActorError: ('spawn_until_0'", + "tractor._exceptions.RemoteActorError: ('spawn_until_1'", + "tractor._exceptions.RemoteActorError: ('spawn_until_2'", + ]) @pytest.mark.timeout(15)