Skip to content

Commit

Permalink
Restore breakpoint() hook after runtime exits
Browse files Browse the repository at this point in the history
Previously we were leaking our (pdb++) override into the Python runtime
which would always result in a runtime error whenever `breakpoint()` is
called outside our runtime; after exit of the root actor . This
explicitly restores any previous hook override (detected during startup)
or deletes the hook and restores the environment if none existed prior.

Also adds a new WIP debugging example script to ensure breakpointing
works as normal after runtime close; this will be added to the test
suite.
  • Loading branch information
goodboy committed May 15, 2023
1 parent 95535b2 commit 79622bb
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
24 changes: 24 additions & 0 deletions examples/debugging/restore_builtin_breakpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import sys

import trio
import tractor


async def main() -> None:
async with tractor.open_nursery(debug_mode=True) as an:

assert os.environ['PYTHONBREAKPOINT'] == 'tractor._debug._set_trace'

# TODO: an assert that verifies the hook has indeed been, hooked
# XD
assert sys.breakpointhook is not tractor._debug._set_trace

breakpoint()

# TODO: an assert that verifies the hook is unhooked..
assert sys.breakpointhook
breakpoint()

if __name__ == '__main__':
trio.run(main)
18 changes: 15 additions & 3 deletions tractor/_root.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
from functools import partial
import importlib
import logging
import os
import signal
import sys
import os
import typing
import warnings

Expand Down Expand Up @@ -84,8 +85,10 @@ async def open_root_actor(
'''
# Override the global debugger hook to make it play nice with
# ``trio``, see:
# ``trio``, see much discussion in:
# https://github.com/python-trio/trio/issues/1155#issuecomment-742964018
builtin_bp_handler = sys.breakpointhook
orig_bp_path: str | None = os.environ.get('PYTHONBREAKPOINT', None)
os.environ['PYTHONBREAKPOINT'] = 'tractor._debug._set_trace'

# attempt to retreive ``trio``'s sigint handler and stash it
Expand Down Expand Up @@ -254,6 +257,15 @@ async def open_root_actor(
await actor.cancel()
finally:
_state._current_actor = None

# restore breakpoint hook state
sys.breakpointhook = builtin_bp_handler
if orig_bp_path is not None:
os.environ['PYTHONBREAKPOINT'] = orig_bp_path
else:
# clear env back to having no entry
os.environ.pop('PYTHONBREAKPOINT')

logger.runtime("Root actor terminated")


Expand Down Expand Up @@ -289,7 +301,7 @@ def run_daemon(
async def _main():

async with open_root_actor(
arbiter_addr=registry_addr,
registry_addr=registry_addr,
name=name,
start_method=start_method,
debug_mode=debug_mode,
Expand Down

0 comments on commit 79622bb

Please sign in to comment.