From be39e592a20ef5fb711a2ee669e7f27b991b31ae Mon Sep 17 00:00:00 2001 From: Quentin Peter Date: Fri, 31 Mar 2023 07:46:12 +0200 Subject: [PATCH] improve recursive debugger --- spyder_kernels/customize/code_runner.py | 24 ++------------ spyder_kernels/customize/spyderpdb.py | 42 ++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/spyder_kernels/customize/code_runner.py b/spyder_kernels/customize/code_runner.py index e463a72c..71d40b84 100644 --- a/spyder_kernels/customize/code_runner.py +++ b/spyder_kernels/customize/code_runner.py @@ -161,33 +161,15 @@ def _debugger_exec(self, filename, continue_if_has_breakpoints): return session = self.shell.pdb_session - sys.settrace(None) - - # Create child debugger - debugger = SpyderPdb( - completekey=session.completekey, - stdin=session.stdin, stdout=session.stdout) - debugger.use_rawinput = session.use_rawinput - debugger.prompt = "(%s) " % session.prompt.strip() - debugger.set_remote_filename(filename) - debugger.continue_if_has_breakpoints = continue_if_has_breakpoints + with session.recursive_debugger() as debugger: + debugger.set_remote_filename(filename) + debugger.continue_if_has_breakpoints = continue_if_has_breakpoints - try: def debug_exec(code, glob, loc): return sys.call_tracing(debugger.run, (code, glob, loc)) # Enter recursive debugger yield debug_exec - finally: - # Reset parent debugger - sys.settrace(session.trace_dispatch) - session.lastcmd = debugger.lastcmd - - # Reset _previous_step so that get_pdb_state() notifies Spyder about - # a changed debugger position. The reset is required because the - # recursive debugger might change the position, but the parent - # debugger (self) is not aware of this. - session._previous_step = None def _exec_file( self, diff --git a/spyder_kernels/customize/spyderpdb.py b/spyder_kernels/customize/spyderpdb.py index 70adb587..1f02e01c 100755 --- a/spyder_kernels/customize/spyderpdb.py +++ b/spyder_kernels/customize/spyderpdb.py @@ -10,6 +10,7 @@ import ast import bdb import builtins +from contextlib import contextmanager import logging import os import sys @@ -603,12 +604,43 @@ def do_debug(self, arg): argument (which is an arbitrary expression or statement to be executed in the current environment). """ + with self.recursive_debugger() as debugger: + self.message("ENTERING RECURSIVE DEBUGGER") + try: + globals = self.curframe.f_globals + locals = self.curframe_locals + return sys.call_tracing(debugger.run, (arg, globals, locals)) + except Exception: + exc_info = sys.exc_info()[:2] + self.error( + traceback.format_exception_only(*exc_info)[-1].strip()) + finally: + self.message("LEAVING RECURSIVE DEBUGGER") + + @contextmanager + def recursive_debugger(self): + """Get a recursive debugger.""" + # Save and restore tracing function + trace_function = sys.gettrace() + sys.settrace(None) + + # Create child debugger + debugger = self.__class__( + completekey=self.completekey, + stdin=self.stdin, stdout=self.stdout) + debugger.prompt = "(%s) " % self.prompt.strip() try: - super(SpyderPdb, self).do_debug(arg) - except Exception: - exc_info = sys.exc_info()[:2] - self.error( - traceback.format_exception_only(*exc_info)[-1].strip()) + yield debugger + finally: + # Reset parent debugger + sys.settrace(trace_function) + self.lastcmd = debugger.lastcmd + + # Reset _previous_step so that get_pdb_state() notifies Spyder about + # a changed debugger position. The reset is required because the + # recursive debugger might change the position, but the parent + # debugger (self) is not aware of this. + self._previous_step = None def user_return(self, frame, return_value): """This function is called when a return trap is set here."""