Add `breakpoint()` hook restoration example + test
parent
cf3e6c1218
commit
b3ee20d3b9
|
@ -6,19 +6,46 @@ import tractor
|
|||
|
||||
|
||||
async def main() -> None:
|
||||
async with tractor.open_nursery(debug_mode=True) as an:
|
||||
|
||||
assert os.environ['PYTHONBREAKPOINT'] == 'tractor._debug._set_trace'
|
||||
# intially unset, no entry.
|
||||
orig_pybp_var: int = os.environ.get('PYTHONBREAKPOINT')
|
||||
assert orig_pybp_var in {None, "0"}
|
||||
|
||||
async with tractor.open_nursery(
|
||||
debug_mode=True,
|
||||
) as an:
|
||||
assert an
|
||||
assert (
|
||||
(pybp_var := os.environ['PYTHONBREAKPOINT'])
|
||||
==
|
||||
'tractor.devx._debug._sync_pause_from_builtin'
|
||||
)
|
||||
|
||||
# TODO: an assert that verifies the hook has indeed been, hooked
|
||||
# XD
|
||||
assert sys.breakpointhook is not tractor._debug._set_trace
|
||||
assert (
|
||||
(pybp_hook := sys.breakpointhook)
|
||||
is not tractor.devx._debug._set_trace
|
||||
)
|
||||
|
||||
print(
|
||||
f'$PYTHONOBREAKPOINT: {pybp_var!r}\n'
|
||||
f'`sys.breakpointhook`: {pybp_hook!r}\n'
|
||||
)
|
||||
breakpoint()
|
||||
pass # first bp, tractor hook set.
|
||||
|
||||
# TODO: an assert that verifies the hook is unhooked..
|
||||
# XXX AFTER EXIT (of actor-runtime) verify the hook is unset..
|
||||
#
|
||||
# YES, this is weird but it's how stdlib docs say to do it..
|
||||
# https://docs.python.org/3/library/sys.html#sys.breakpointhook
|
||||
assert os.environ.get('PYTHONBREAKPOINT') is orig_pybp_var
|
||||
assert sys.breakpointhook
|
||||
|
||||
# now ensure a regular builtin pause still works
|
||||
breakpoint()
|
||||
pass # last bp, stdlib hook restored
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
trio.run(main)
|
||||
|
|
|
@ -1231,6 +1231,53 @@ def test_shield_pause(
|
|||
child.expect(EOF)
|
||||
|
||||
|
||||
def test_breakpoint_hook_restored(
|
||||
spawn,
|
||||
):
|
||||
'''
|
||||
Ensures our actor runtime sets a custom `breakpoint()` hook
|
||||
on open then restores the stdlib's default on close.
|
||||
|
||||
The hook state validation is done via `assert`s inside the
|
||||
invoked script with only `breakpoint()` (not `tractor.pause()`)
|
||||
calls used.
|
||||
|
||||
'''
|
||||
child = spawn('restore_builtin_breakpoint')
|
||||
|
||||
child.expect(PROMPT)
|
||||
assert_before(
|
||||
child,
|
||||
[
|
||||
_pause_msg,
|
||||
"<Task '__main__.main'",
|
||||
"('root'",
|
||||
"first bp, tractor hook set",
|
||||
]
|
||||
)
|
||||
child.sendline('c')
|
||||
child.expect(PROMPT)
|
||||
assert_before(
|
||||
child,
|
||||
[
|
||||
"last bp, stdlib hook restored",
|
||||
]
|
||||
)
|
||||
|
||||
# since the stdlib hook was already restored there should be NO
|
||||
# `tractor` `log.pdb()` content from console!
|
||||
assert not in_prompt_msg(
|
||||
child,
|
||||
[
|
||||
_pause_msg,
|
||||
"<Task '__main__.main'",
|
||||
"('root'",
|
||||
],
|
||||
)
|
||||
child.sendline('c')
|
||||
child.expect(EOF)
|
||||
|
||||
|
||||
# TODO: better error for "non-ideal" usage from the root actor.
|
||||
# -[ ] if called from an async scope emit a message that suggests
|
||||
# using `await tractor.pause()` instead since it's less overhead
|
||||
|
@ -1248,6 +1295,7 @@ def test_sync_pause_from_bg_task_in_root_actor_():
|
|||
'''
|
||||
...
|
||||
|
||||
|
||||
# TODO: needs ANSI code stripping tho, see `assert_before()` # above!
|
||||
def test_correct_frames_below_hidden():
|
||||
'''
|
||||
|
@ -1264,8 +1312,9 @@ def test_cant_pause_from_paused_task():
|
|||
'''
|
||||
Pausing from with an already paused task should raise an error.
|
||||
|
||||
Normally this should only happen in practise while debugging the call stack of `tractor.pause()` itself, likely
|
||||
by a `.pause()` line somewhere inside our runtime.
|
||||
Normally this should only happen in practise while debugging the
|
||||
call stack of `tractor.pause()` itself, likely by a `.pause()`
|
||||
line somewhere inside our runtime.
|
||||
|
||||
'''
|
||||
...
|
||||
|
|
Loading…
Reference in New Issue