From abf8bb2813cb09364a293542506d17c55166acfc Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Tue, 6 Oct 2020 09:21:53 -0400 Subject: [PATCH] Add a deep nested error propagation test --- ...ed_subactors_error_up_through_nurseries.py | 58 +++++++++++++++++++ .../debugging/multi_subactor_root_errors.py | 4 +- tests/test_debugger.py | 21 +++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 examples/debugging/multi_nested_subactors_error_up_through_nurseries.py diff --git a/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py b/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py new file mode 100644 index 0000000..488fffa --- /dev/null +++ b/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py @@ -0,0 +1,58 @@ +import tractor + + +async def name_error(): + "Raise a ``NameError``" + getattr(doggypants) + + +async def breakpoint_forever(): + "Indefinitely re-enter debugger in child actor." + while True: + await tractor.breakpoint() + + +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('name_error', name_error) + else: + depth -= 1 + await n.run_in_actor(f'spawn_until_{depth}', spawn_until, depth=depth) + + +async def main(): + """The main ``tractor`` routine. + + The process tree should look as approximately as follows when the debugger + first engages: + + python examples/debugging/multi_nested_subactors_bp_forever.py + ├─ python -m tractor._child --uid ('spawner1', '7eab8462 ...) + │ └─ python -m tractor._child --uid ('spawn_until_3', 'afcba7a8 ...) + │ └─ python -m tractor._child --uid ('spawn_until_2', 'd2433d13 ...) + │ └─ python -m tractor._child --uid ('spawn_until_1', '1df589de ...) + │ └─ python -m tractor._child --uid ('spawn_until_0', '3720602b ...) + │ + └─ python -m tractor._child --uid ('spawner0', '1d42012b ...) + └─ python -m tractor._child --uid ('spawn_until_2', '2877e155 ...) + └─ python -m tractor._child --uid ('spawn_until_1', '0502d786 ...) + └─ python -m tractor._child --uid ('spawn_until_0', 'de918e6d ...) + + """ + async with tractor.open_nursery() as n: + + # spawn both actors + portal = await n.run_in_actor('spawner0', spawn_until, depth=3) + portal1 = await n.run_in_actor('spawner1', spawn_until, depth=4) + + # gah still an issue here. + # await portal.result() + # await portal1.result() + + +if __name__ == '__main__': + tractor.run(main, debug_mode=True) diff --git a/examples/debugging/multi_subactor_root_errors.py b/examples/debugging/multi_subactor_root_errors.py index f7a4372..05f0fa7 100644 --- a/examples/debugging/multi_subactor_root_errors.py +++ b/examples/debugging/multi_subactor_root_errors.py @@ -19,8 +19,8 @@ async def main(): The process tree should look as approximately as follows: - -python examples/debugging/multi_subactors.py - |-python -m tractor._child --uid ('name_error', 'a7caf490 ...) + python examples/debugging/multi_subactors.py + ├─ python -m tractor._child --uid ('name_error', 'a7caf490 ...) `-python -m tractor._child --uid ('spawn_error', '52ee14a5 ...) `-python -m tractor._child --uid ('name_error', '3391222c ...) """ diff --git a/tests/test_debugger.py b/tests/test_debugger.py index 8c87791..2540c2e 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -310,3 +310,24 @@ def test_multi_subactors_root_errors(spawn): before = str(child.before.decode()) assert "AssertionError" in before + + +def test_multi_nested_subactors_error_through_nurseries(spawn): + """Verify deeply nested actors that error trigger debugger entries + at each level up the tree. + """ + + # TODO: inside this script there's still a bug where if the parent + # errors before a 2 levels lower actor has released the lock, the + # parent tries to cancel it but it's stuck in the debugger? + + child = spawn('multi_nested_subactors_error_up_through_nurseries') + + for _ in range(12): + child.expect(r"\(Pdb\+\+\)") + child.sendline('c') + + child.expect(pexpect.EOF) + + before = str(child.before.decode()) + assert "NameError" in before