forked from goodboy/tractor
				
			Try overriding `_GeneratorContextManager.__exit__()`; didn't work..
Using either of `@pdb.hideframe` or `__tracebackhide__` on stdlib methods doesn't seem to work either.. This all seems to have something to do with async generator usage I think ?sigintsaviour_citesthackin
							parent
							
								
									99c4319940
								
							
						
					
					
						commit
						7964a9f6f8
					
				| 
						 | 
					@ -18,12 +18,15 @@
 | 
				
			||||||
Multi-core debugging for da peeps!
 | 
					Multi-core debugging for da peeps!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					from __future__ import annotations
 | 
				
			||||||
import bdb
 | 
					import bdb
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import signal
 | 
					import signal
 | 
				
			||||||
from functools import partial
 | 
					from functools import partial
 | 
				
			||||||
from contextlib import asynccontextmanager as acm
 | 
					from contextlib import asynccontextmanager as acm
 | 
				
			||||||
from contextlib import contextmanager as cm
 | 
					from contextlib import contextmanager as cm
 | 
				
			||||||
 | 
					from contextlib import _GeneratorContextManager
 | 
				
			||||||
 | 
					import contextlib
 | 
				
			||||||
from typing import (
 | 
					from typing import (
 | 
				
			||||||
    Tuple,
 | 
					    Tuple,
 | 
				
			||||||
    Optional,
 | 
					    Optional,
 | 
				
			||||||
| 
						 | 
					@ -40,7 +43,8 @@ from trio_typing import TaskStatus
 | 
				
			||||||
from .log import get_logger
 | 
					from .log import get_logger
 | 
				
			||||||
from ._discovery import get_root
 | 
					from ._discovery import get_root
 | 
				
			||||||
from ._state import is_root_process, debug_mode
 | 
					from ._state import is_root_process, debug_mode
 | 
				
			||||||
from ._exceptions import is_multi_cancelled, ContextCancelled
 | 
					from ._exceptions import is_multi_cancelled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					try:
 | 
				
			||||||
    # wtf: only exported when installed in dev mode?
 | 
					    # wtf: only exported when installed in dev mode?
 | 
				
			||||||
| 
						 | 
					@ -54,6 +58,19 @@ except ImportError:
 | 
				
			||||||
log = get_logger(__name__)
 | 
					log = get_logger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class noexittbGCM(_GeneratorContextManager):
 | 
				
			||||||
 | 
					    # @pdb.hideframe
 | 
				
			||||||
 | 
					    def __exit__(self, type, value, traceback):
 | 
				
			||||||
 | 
					        __tracebackhide__ = True
 | 
				
			||||||
 | 
					        # try:
 | 
				
			||||||
 | 
					        return super().__exit__(type, value, traceback)
 | 
				
			||||||
 | 
					        # except:
 | 
				
			||||||
 | 
					        #     print('EXITED')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					contextlib._GeneratorContextManager = noexittbGCM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__all__ = ['breakpoint', 'post_mortem']
 | 
					__all__ = ['breakpoint', 'post_mortem']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,17 +115,19 @@ class PdbwTeardown(pdbpp.Pdb):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            super().set_continue()
 | 
					            super().set_continue()
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            global _local_task_in_debug
 | 
					            global _local_task_in_debug, _pdb_release_hook
 | 
				
			||||||
            _local_task_in_debug = None
 | 
					            _local_task_in_debug = None
 | 
				
			||||||
            _pdb_release_hook()
 | 
					            if _pdb_release_hook:
 | 
				
			||||||
 | 
					                _pdb_release_hook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_quit(self):
 | 
					    def set_quit(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            super().set_quit()
 | 
					            super().set_quit()
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            global _local_task_in_debug
 | 
					            global _local_task_in_debug, _pdb_release_hook
 | 
				
			||||||
            _local_task_in_debug = None
 | 
					            _local_task_in_debug = None
 | 
				
			||||||
            _pdb_release_hook()
 | 
					            if _pdb_release_hook:
 | 
				
			||||||
 | 
					                _pdb_release_hook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# TODO: will be needed whenever we get to true remote debugging.
 | 
					# TODO: will be needed whenever we get to true remote debugging.
 | 
				
			||||||
| 
						 | 
					@ -252,7 +271,7 @@ async def _hijack_stdin_for_child(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with (
 | 
					    with (
 | 
				
			||||||
        trio.CancelScope(shield=True),
 | 
					        trio.CancelScope(shield=True),
 | 
				
			||||||
        disable_sigint(),
 | 
					        # disable_sigint(),
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -270,10 +289,12 @@ async def _hijack_stdin_for_child(
 | 
				
			||||||
        except (
 | 
					        except (
 | 
				
			||||||
            # BaseException,
 | 
					            # BaseException,
 | 
				
			||||||
            trio.MultiError,
 | 
					            trio.MultiError,
 | 
				
			||||||
            trio.BrokenResourceError,
 | 
					            Exception,
 | 
				
			||||||
            trio.Cancelled,  # by local cancellation
 | 
					            # trio.BrokenResourceError,
 | 
				
			||||||
            trio.ClosedResourceError,  # by self._rx_chan
 | 
					            # trio.Cancelled,  # by local cancellation
 | 
				
			||||||
            ContextCancelled,
 | 
					            # trio.ClosedResourceError,  # by self._rx_chan
 | 
				
			||||||
 | 
					            # ContextCancelled,
 | 
				
			||||||
 | 
					            # ConnectionResetError,
 | 
				
			||||||
        ) as err:
 | 
					        ) as err:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # XXX: there may be a race with the portal teardown
 | 
					            # XXX: there may be a race with the portal teardown
 | 
				
			||||||
| 
						 | 
					@ -485,6 +506,7 @@ async def _breakpoint(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@cm
 | 
					@cm
 | 
				
			||||||
 | 
					@pdb.hideframe
 | 
				
			||||||
def _open_pdb() -> Iterator[PdbwTeardown]:
 | 
					def _open_pdb() -> Iterator[PdbwTeardown]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # XXX: setting these flags on the pdb instance are absolutely
 | 
					    # XXX: setting these flags on the pdb instance are absolutely
 | 
				
			||||||
| 
						 | 
					@ -492,6 +514,7 @@ def _open_pdb() -> Iterator[PdbwTeardown]:
 | 
				
			||||||
    # stdlib's pdb supports entering the current sync frame on a SIGINT,
 | 
					    # stdlib's pdb supports entering the current sync frame on a SIGINT,
 | 
				
			||||||
    # with ``trio`` we pretty much never want this and if we did we can
 | 
					    # with ``trio`` we pretty much never want this and if we did we can
 | 
				
			||||||
    # handle it in the ``tractor`` task runtime.
 | 
					    # handle it in the ``tractor`` task runtime.
 | 
				
			||||||
 | 
					    __tracebackhide__ = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pdb = PdbwTeardown()
 | 
					    pdb = PdbwTeardown()
 | 
				
			||||||
    pdb.allow_kbdint = True
 | 
					    pdb.allow_kbdint = True
 | 
				
			||||||
| 
						 | 
					@ -564,7 +587,7 @@ def shield_sigint(
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # If we haven't tried to cancel the runtime then do that instead
 | 
					        # If we haven't tried to cancel the runtime then do that instead
 | 
				
			||||||
        # of raising a KBI (which may non-gracefully destroy
 | 
					        # of raising a KBI (which may non-gracefully destroy
 | 
				
			||||||
        # a ``trio.run()``). 
 | 
					        # a ``trio.run()``).
 | 
				
			||||||
        if not actor._cancel_called:
 | 
					        if not actor._cancel_called:
 | 
				
			||||||
            actor.cancel_soon()
 | 
					            actor.cancel_soon()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -591,6 +614,7 @@ def shield_sigint(
 | 
				
			||||||
        print(pdb.prompt, end='', flush=True)
 | 
					        print(pdb.prompt, end='', flush=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pdb.hideframe
 | 
				
			||||||
@cm
 | 
					@cm
 | 
				
			||||||
def disable_sigint(
 | 
					def disable_sigint(
 | 
				
			||||||
    pdb: Optional[PdbwTeardown] = None
 | 
					    pdb: Optional[PdbwTeardown] = None
 | 
				
			||||||
| 
						 | 
					@ -601,10 +625,10 @@ def disable_sigint(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # ensure the ``contextlib.contextmanager`` frame inside the wrapping
 | 
					    # ensure the ``contextlib.contextmanager`` frame inside the wrapping
 | 
				
			||||||
    # ``.__exit__()`` method isn't shown either.
 | 
					    # ``.__exit__()`` method isn't shown either.
 | 
				
			||||||
    frame = sys._getframe()
 | 
					    # frame = sys._getframe()
 | 
				
			||||||
    last_f = frame.f_back
 | 
					    # last_f = frame.f_back
 | 
				
			||||||
    if last_f:
 | 
					    # last_f.f_globals['__tracebackhide__'] = True
 | 
				
			||||||
        last_f.f_globals['__tracebackhide__'] = True
 | 
					
 | 
				
			||||||
    # NOTE: this seems like a form of cpython bug wherein
 | 
					    # NOTE: this seems like a form of cpython bug wherein
 | 
				
			||||||
    # it's likely that ``functools.WRAPPER_ASSIGNMENTS`` should
 | 
					    # it's likely that ``functools.WRAPPER_ASSIGNMENTS`` should
 | 
				
			||||||
    # probably contain this attr name?
 | 
					    # probably contain this attr name?
 | 
				
			||||||
| 
						 | 
					@ -625,8 +649,13 @@ def disable_sigint(
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _set_trace(actor=None):
 | 
					@pdb.hideframe
 | 
				
			||||||
 | 
					def _set_trace(
 | 
				
			||||||
 | 
					    actor: Optional[tractor.Actor] = None
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
    __tracebackhide__ = True
 | 
					    __tracebackhide__ = True
 | 
				
			||||||
 | 
					    actor = actor or tractor.current_actor()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with (
 | 
					    with (
 | 
				
			||||||
        _open_pdb() as pdb,
 | 
					        _open_pdb() as pdb,
 | 
				
			||||||
        disable_sigint(pdb=pdb),
 | 
					        disable_sigint(pdb=pdb),
 | 
				
			||||||
| 
						 | 
					@ -640,7 +669,8 @@ def _set_trace(actor=None):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            # we entered the global ``breakpoint()`` built-in from sync code
 | 
					            # we entered the global ``breakpoint()`` built-in from sync code?
 | 
				
			||||||
 | 
					            assert 0, 'Woa this path finally triggered?'
 | 
				
			||||||
            global _local_task_in_debug, _pdb_release_hook
 | 
					            global _local_task_in_debug, _pdb_release_hook
 | 
				
			||||||
            _local_task_in_debug = 'sync'
 | 
					            _local_task_in_debug = 'sync'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -651,7 +681,7 @@ def _set_trace(actor=None):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pdb.set_trace(
 | 
					            pdb.set_trace(
 | 
				
			||||||
                # start 2 levels up in user code
 | 
					                # start 2 levels up in user code
 | 
				
			||||||
                frame=sys._getframe().f_back,
 | 
					                frame=sys._getframe().f_back.f_back,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -661,11 +691,15 @@ breakpoint = partial(
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pdb.hideframe
 | 
				
			||||||
def _post_mortem(actor):
 | 
					def _post_mortem(actor):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __tracebackhide__ = True
 | 
					    __tracebackhide__ = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with (
 | 
					    with (
 | 
				
			||||||
 | 
					        # noop()
 | 
				
			||||||
        _open_pdb() as pdb,
 | 
					        _open_pdb() as pdb,
 | 
				
			||||||
        disable_sigint(pdb=pdb),
 | 
					        # disable_sigint(pdb=pdb),
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        log.pdb(f"\nAttaching to pdb in crashed actor: {actor.uid}\n")
 | 
					        log.pdb(f"\nAttaching to pdb in crashed actor: {actor.uid}\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue