From 9431a81d37a7a7c7679c9f7cdfa184a92b2ca72a Mon Sep 17 00:00:00 2001 From: goodboy Date: Fri, 1 May 2026 00:13:22 -0400 Subject: [PATCH] Update debug examples + harden `test_debugger` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass explicit `loglevel` to `spawn()` calls in `test_debugger` tests — required for pexpect pattern matching now that examples no longer hard-code log levels. Also, - make `expect()` return the decoded `before` str. - add `start_method` param + fork-backend timeout slack (+4s) in nested-error test. - clean up debug examples: drop unused loglevels, rename `n` -> `an`, fix docstrings, add TODO comments for tpt parametrize via osenv. (this commit msg was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code --- examples/debugging/multi_daemon_subactors.py | 9 ++---- ...ed_subactors_error_up_through_nurseries.py | 2 +- ...root_cancelled_but_child_is_in_tty_lock.py | 4 +-- .../root_timeout_while_child_crashed.py | 13 +++++--- examples/debugging/subactor_bp_in_ctx.py | 5 +++ examples/debugging/subactor_error.py | 1 - tests/devx/conftest.py | 9 +++--- tests/devx/test_debugger.py | 32 +++++++++++++++---- 8 files changed, 49 insertions(+), 26 deletions(-) diff --git a/examples/debugging/multi_daemon_subactors.py b/examples/debugging/multi_daemon_subactors.py index 844a228a..e313803a 100644 --- a/examples/debugging/multi_daemon_subactors.py +++ b/examples/debugging/multi_daemon_subactors.py @@ -27,12 +27,9 @@ async def main(): ''' async with tractor.open_nursery( debug_mode=True, - loglevel='cancel', - # loglevel='devx', - ) as n: - - p0 = await n.start_actor('bp_forever', enable_modules=[__name__]) - p1 = await n.start_actor('name_error', enable_modules=[__name__]) + ) as an: + p0 = await an.start_actor('bp_forever', enable_modules=[__name__]) + p1 = await an.start_actor('name_error', enable_modules=[__name__]) # retreive results async with p0.open_stream_from(breakpoint_forever) as stream: 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 b63f1945..6cfce50f 100644 --- a/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py +++ b/examples/debugging/multi_nested_subactors_error_up_through_nurseries.py @@ -67,7 +67,7 @@ async def main(): """ async with tractor.open_nursery( debug_mode=True, - # loglevel='cancel', + loglevel='pdb', ) as n: # spawn both actors diff --git a/examples/debugging/root_cancelled_but_child_is_in_tty_lock.py b/examples/debugging/root_cancelled_but_child_is_in_tty_lock.py index 72c6de4c..93daa33b 100644 --- a/examples/debugging/root_cancelled_but_child_is_in_tty_lock.py +++ b/examples/debugging/root_cancelled_but_child_is_in_tty_lock.py @@ -39,8 +39,8 @@ async def main(): ''' async with tractor.open_nursery( debug_mode=True, - loglevel='devx', - enable_transports=['uds'], + enable_transports=['uds'], # TODO, apss this via osenv? + loglevel='devx', # XXX, required for test! ) as n: # spawn both actors diff --git a/examples/debugging/root_timeout_while_child_crashed.py b/examples/debugging/root_timeout_while_child_crashed.py index e313672f..4dfc699d 100644 --- a/examples/debugging/root_timeout_while_child_crashed.py +++ b/examples/debugging/root_timeout_while_child_crashed.py @@ -1,4 +1,3 @@ - import trio import tractor @@ -9,16 +8,22 @@ async def key_error(): async def main(): - """Root dies + ''' + Root is fail-after-cancelled while blocking and child RPC fails + simultaneously. - """ + ''' async with tractor.open_nursery( debug_mode=True, - loglevel='debug' + # loglevel='debug' # ?XXX required? ) as n: # spawn both actors portal = await n.run_in_actor(key_error) + print( + f'Child is up @ {portal.chan.aid.reprol()}' + ) + # XXX: originally a bug caused by this is where root would enter # the debugger and clobber the tty used by the repl even though diff --git a/examples/debugging/subactor_bp_in_ctx.py b/examples/debugging/subactor_bp_in_ctx.py index 0ca7097f..5bfff331 100644 --- a/examples/debugging/subactor_bp_in_ctx.py +++ b/examples/debugging/subactor_bp_in_ctx.py @@ -36,6 +36,11 @@ async def just_bp( async def main(): + # !TODO, parametrize the --tpt-proto={key} with osenv vars just + # like we do for loglevel/spawn-backend! + # - [ ] run on both tpts for all such debugger tests? + # - [ ] special skip for macos! + # if platform.system() != 'Darwin': tpt = 'uds' else: diff --git a/examples/debugging/subactor_error.py b/examples/debugging/subactor_error.py index d7aee447..4bd809f9 100644 --- a/examples/debugging/subactor_error.py +++ b/examples/debugging/subactor_error.py @@ -9,7 +9,6 @@ async def name_error(): async def main(): async with tractor.open_nursery( debug_mode=True, - # loglevel='transport', ) as an: # TODO: ideally the REPL arrives at this frame in the parent, diff --git a/tests/devx/conftest.py b/tests/devx/conftest.py index 2c621f41..94a1682d 100644 --- a/tests/devx/conftest.py +++ b/tests/devx/conftest.py @@ -269,13 +269,10 @@ def ctlc( def expect( child, - - # normally a `pdb` prompt by default - patt: str, - + patt: str, # often a `pdbp`-prompt **kwargs, -) -> None: +) -> str: ''' Expect wrapper that prints last seen console data before failing. @@ -286,6 +283,8 @@ def expect( patt, **kwargs, ) + before = str(child.before.decode()) + return before except TIMEOUT: before = str(child.before.decode()) print(before) diff --git a/tests/devx/test_debugger.py b/tests/devx/test_debugger.py index 34f1b6ba..be1289ff 100644 --- a/tests/devx/test_debugger.py +++ b/tests/devx/test_debugger.py @@ -765,6 +765,7 @@ def test_multi_subactors_root_errors( def test_multi_nested_subactors_error_through_nurseries( ci_env: bool, spawn: PexpectSpawner, + start_method: str, # TODO: address debugger issue for nested tree: # https://github.com/goodboy/tractor/issues/320 @@ -781,16 +782,16 @@ def test_multi_nested_subactors_error_through_nurseries( # A test (below) has now been added to explicitly verify this is # fixed. - child = spawn('multi_nested_subactors_error_up_through_nurseries') - - # timed_out_early: bool = False - + child = spawn( + 'multi_nested_subactors_error_up_through_nurseries', + loglevel='pdb', + ) for ( i, send_char, ) in enumerate(itertools.cycle(['c', 'q'])): - timeout: float = -1 + timeout: float = child.timeout if ( _non_linux and @@ -803,6 +804,15 @@ def test_multi_nested_subactors_error_through_nurseries( elif i == 0: timeout = 5 + # XXX forking backends may take longer due to + # determinstic IPC cancellation. + if ( + start_method in [ + 'main_thread_forkserver', + ] + ): + timeout += 4 + try: child.expect( PROMPT, @@ -1187,7 +1197,11 @@ def test_ctxep_pauses_n_maybe_ipc_breaks( mashed and zombie reaper kills sub with no hangs. ''' - child = spawn('subactor_bp_in_ctx') + child = spawn( + 'subactor_bp_in_ctx', + loglevel='devx' + # ^XXX REQUIRED for below patt matching! + ) child.expect(PROMPT) # 3 iters for the `gen()` pause-points @@ -1277,7 +1291,11 @@ def test_crash_handling_within_cancelled_root_actor( call. ''' - child = spawn('root_self_cancelled_w_error') + child = spawn( + 'root_self_cancelled_w_error', + loglevel='cancel', + # ^XXX REQUIRED for below patt matching! + ) child.expect(PROMPT) assert_before(