Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compatibility with Python 3.13 #664

Merged
merged 4 commits into from
Oct 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 30 additions & 46 deletions pudb/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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

Expand All @@ -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):
Expand All @@ -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

Expand Down