Add `breakpoint()` hook restoration example + test
parent
cf3e6c1218
commit
b3ee20d3b9
|
@ -6,19 +6,46 @@ import tractor
|
||||||
|
|
||||||
|
|
||||||
async def main() -> None:
|
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
|
# TODO: an assert that verifies the hook has indeed been, hooked
|
||||||
# XD
|
# 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()
|
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
|
assert sys.breakpointhook
|
||||||
|
|
||||||
|
# now ensure a regular builtin pause still works
|
||||||
breakpoint()
|
breakpoint()
|
||||||
|
pass # last bp, stdlib hook restored
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
trio.run(main)
|
trio.run(main)
|
||||||
|
|
|
@ -1231,6 +1231,53 @@ def test_shield_pause(
|
||||||
child.expect(EOF)
|
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.
|
# TODO: better error for "non-ideal" usage from the root actor.
|
||||||
# -[ ] if called from an async scope emit a message that suggests
|
# -[ ] if called from an async scope emit a message that suggests
|
||||||
# using `await tractor.pause()` instead since it's less overhead
|
# 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!
|
# TODO: needs ANSI code stripping tho, see `assert_before()` # above!
|
||||||
def test_correct_frames_below_hidden():
|
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.
|
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
|
Normally this should only happen in practise while debugging the
|
||||||
by a `.pause()` line somewhere inside our runtime.
|
call stack of `tractor.pause()` itself, likely by a `.pause()`
|
||||||
|
line somewhere inside our runtime.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
...
|
...
|
||||||
|
|
Loading…
Reference in New Issue