''' That "foreign loop/thread" debug REPL support better ALSO WORK! Same as `test_native_pause.py`. All these tests can be understood (somewhat) by running the equivalent `examples/debugging/` scripts manually. ''' # from functools import partial # import itertools import time # from typing import ( # Iterator, # ) import pytest from pexpect.exceptions import ( # TIMEOUT, EOF, ) from .conftest import ( # _ci_env, do_ctlc, PROMPT, # expect, in_prompt_msg, assert_before, _pause_msg, _crash_msg, _ctlc_ignore_header, # _repl_fail_msg, ) def test_pause_from_sync( spawn, ctlc: bool, ): ''' Verify we can use the `pdbp` REPL from sync functions AND from any thread spawned with `trio.to_thread.run_sync()`. `examples/debugging/sync_bp.py` ''' child = spawn('sync_bp') # first `sync_pause()` after nurseries open child.expect(PROMPT) assert_before( child, [ # pre-prompt line _pause_msg, " similar to the `delay` input to `do_ctlc()` below, setting # this too low can cause the test to fail since the `subactor` # suffers a race where the root/parent sends an actor-cancel # prior to the context task hitting its pause point (and thus # engaging the `sigint_shield()` handler in time); this value # seems be good enuf? time.sleep(0.6) # one of the bg thread or subactor should have # `Lock.acquire()`-ed # (NOT both, which will result in REPL clobbering!) attach_patts: dict[str, list[str]] = { 'subactor': [ "'start_n_sync_pause'", "('subactor'", ], 'inline_root_bg_thread': [ " list[str]: ''' Receive any of a `list[str]` of patterns provided in `attach_patts`. Used to test racing prompts from multiple actors and/or tasks using a common root process' `pdbp` REPL. ''' assert attach_patts child.expect(PROMPT) before = str(child.before.decode()) for attach_key in attach_patts: if attach_key in before: expected_patts: str = attach_patts.pop(attach_key) assert_before( child, expected_patts ) break # from for else: pytest.fail( f'No keys found?\n\n' f'{attach_patts.keys()}\n\n' f'{before}\n' ) # ensure no other task/threads engaged a REPL # at the same time as the one that was detected above. for key, other_patts in attach_patts.copy().items(): assert not in_prompt_msg( child, other_patts, ) if ctlc: do_ctlc( child, patt=prompt, # NOTE same as comment above delay=ctlc_delay, ) return expected_patts # yield child def test_pause_from_asyncio_task( spawn, ctlc: bool # ^TODO, fix for `asyncio`!! ): ''' Verify we can use the `pdbp` REPL from an `asyncio.Task` spawned using APIs in `.to_asyncio`. `examples/debugging/asycio_bp.py` ''' child = spawn('asyncio_bp') # RACE on whether trio/asyncio task bps first attach_patts: dict[str, list[str]] = { # first pause in guest-mode (aka "infecting") # `trio.Task`. 'trio-side': [ _pause_msg, "