diff --git a/pudb/debugger.py b/pudb/debugger.py index 824c186e..eebc53f2 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -227,33 +227,6 @@ def __del__(self): self._tty_file.close() self._tty_file = None - # These (dispatch_line and set_continue) are copied from bdb with the - # patch from https://bugs.python.org/issue16482 applied. See - # https://github.com/inducer/pudb/pull/90. - def dispatch_line(self, frame): - if self.stop_here(frame) or self.break_here(frame): - self.user_line(frame) - if self.quitting: - raise bdb.BdbQuit - # Do not re-install the local trace when we are finished debugging, - # see issues 16482 and 7238. - if not sys.gettrace(): - return None - return self.trace_dispatch - - def set_continue(self): - # Don't stop except at breakpoints or when finished - self._set_stopinfo(self.botframe, None, -1) - if not self.breaks: - # no breakpoints; run without debugger overhead - sys.settrace(None) - frame = sys._getframe().f_back - while frame: - del frame.f_trace - if frame is self.botframe: - break - frame = frame.f_back - def set_jump(self, frame, line): frame.f_lineno = line @@ -279,29 +252,41 @@ def set_trace(self, frame=None, as_breakpoint=None, paused=True): as_breakpoint = True if frame is None: - frame = thisframe = sys._getframe().f_back - else: - thisframe = frame + frame = sys._getframe().f_back + assert frame is not None + # See pudb issue #52. If this works well enough we should upstream to # stdlib bdb.py. # self.reset() - while frame: - frame.f_trace = self.trace_dispatch - self.botframe = frame - frame = frame.f_back + if paused: + self.enterframe = frame - thisframe_info = ( - self.canonic(thisframe.f_code.co_filename), thisframe.f_lineno) - if thisframe_info not in self.set_traces or self.set_traces[thisframe_info]: + thisframe = frame + while thisframe: + thisframe.f_trace = self.trace_dispatch + self.botframe = thisframe + if sys.version_info >= (3, 13): + # save trace flags, to be restored by set_continue + self.frame_trace_lines_opcodes[thisframe] = ( # pylint: disable=no-member + thisframe.f_trace_lines, + thisframe.f_trace_opcodes) + + # We need f_trace_lines == True for the debugger to work + thisframe.f_trace_lines = True + + thisframe = thisframe.f_back + + frame_info = (self.canonic(frame.f_code.co_filename), frame.f_lineno) + if frame_info not in self.set_traces or self.set_traces[frame_info]: if as_breakpoint: - self.set_traces[thisframe_info] = True + self.set_traces[frame_info] = True if self.ui.source_code_provider is not None: self.ui.set_source_code_provider( self.ui.source_code_provider, force_update=True) if paused: - self.set_step() + self._set_stopinfo(frame, None) else: self.set_continue() sys.settrace(self.trace_dispatch) @@ -460,9 +445,6 @@ def user_call(self, frame, argument_list): def user_line(self, frame): """This function is called when we stop or break at this line.""" - if "__exc_tuple__" in frame.f_locals: - del frame.f_locals["__exc_tuple__"] - if self._waiting_for_mainpyfile(frame): return @@ -486,7 +468,7 @@ def user_return(self, frame, return_value): if self._waiting_for_mainpyfile(frame): return - if "__exc_tuple__" not in frame.f_locals: + if "__exception__" not in frame.f_locals: self.interaction(frame) def _waiting_for_mainpyfile(self, frame): @@ -502,13 +484,15 @@ def _waiting_for_mainpyfile(self, frame): return True return False - def user_exception(self, frame, exc_tuple): + def user_exception(self, frame, exc_info): """This function is called if an exception occurs, but only if we are to stop at or just below this level.""" - frame.f_locals["__exc_tuple__"] = exc_tuple + + exc_type, exc_value, _exc_traceback = exc_info + frame.f_locals["__exception__"] = exc_type, exc_value if not self._wait_for_mainpyfile: - self.interaction(frame, exc_tuple) + self.interaction(frame, exc_info) # {{{ entrypoints