forked from goodboy/tractor
				
			Restore `breakpoint()` hook after runtime exits
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.proper_breakpoint_hooking
							parent
							
								
									d0a65e8922
								
							
						
					
					
						commit
						4d3c109277
					
				| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -22,8 +22,9 @@ from contextlib import asynccontextmanager
 | 
			
		|||
from functools import partial
 | 
			
		||||
import importlib
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
import signal
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import typing
 | 
			
		||||
import warnings
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -256,6 +259,15 @@ async def open_root_actor(
 | 
			
		|||
                )
 | 
			
		||||
    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")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +303,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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue