Skip to content

gh-58319: IDLE: Add interrupt handle when open debugger #1821

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
28 changes: 28 additions & 0 deletions Lib/idlelib/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Idb(bdb.Bdb):

def __init__(self, gui):
self.gui = gui # An instance of Debugger or proxy of remote.
self._interrupt = False
bdb.Bdb.__init__(self)

def user_line(self, frame):
Expand All @@ -32,6 +33,28 @@ def user_exception(self, frame, info):
message = self.__frame2message(frame)
self.gui.interaction(message, frame, info)

def user_interrupt(self, value):
# Clear sys.settrace to prevent debugger trace in Idb
sys.settrace(None)

old_value = self._interrupt
self._interrupt = value
return old_value

def break_here(self, frame):
if self._interrupt:
self._interrupt = False
return True
return bdb.Bdb.break_here(self, frame)

def set_continue(self):
bdb.Bdb.set_continue(self)
# The code in bdb will clear sys.settrace
# if there are no breakpoints. This resets
# it so that Ctrl-C still works.
if sys.gettrace() is None:
sys.settrace(self.trace_dispatch)

def in_rpc_code(self, frame):
if frame.f_code.co_filename.count('rpc.py'):
return True
Expand Down Expand Up @@ -265,22 +288,27 @@ def __frame2fileline(self, frame):
return filename, lineno

def cont(self):
self.idb.user_interrupt(False)
self.idb.set_continue()
self.abort_loop()

def step(self):
self.idb.user_interrupt(False)
self.idb.set_step()
self.abort_loop()

def next(self):
self.idb.user_interrupt(False)
self.idb.set_next(self.frame)
self.abort_loop()

def ret(self):
self.idb.user_interrupt(False)
self.idb.set_return(self.frame)
self.abort_loop()

def quit(self):
self.idb.user_interrupt(False)
self.idb.set_quit()
self.abort_loop()

Expand Down
9 changes: 8 additions & 1 deletion Lib/idlelib/debugger_r.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ def clear_all_file_breaks(self, filename):
msg = self.idb.clear_all_file_breaks(filename)
return msg

def user_interrupt(self, value):
return self.idb.user_interrupt(value)

#----------called by a FrameProxy----------

def frame_attr(self, fid, name):
Expand Down Expand Up @@ -190,7 +193,7 @@ def start_debugger(rpchandler, gui_adap_oid):
idb = debugger.Idb(gui_proxy)
idb_adap = IdbAdapter(idb)
rpchandler.register(idb_adap_oid, idb_adap)
return idb_adap_oid
return idb_adap_oid, idb


#=======================================
Expand Down Expand Up @@ -343,6 +346,10 @@ def clear_all_file_breaks(self, filename):
msg = self.call("clear_all_file_breaks", filename)
return msg

def user_interrupt(self, value):
return self.call("user_interrupt", value)


def start_remote_debugger(rpcclt, pyshell):
"""Start the subprocess debugger, initialize the debugger GUI and RPC link

Expand Down
6 changes: 2 additions & 4 deletions Lib/idlelib/pyshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -1211,10 +1211,8 @@ def cancel_callback(self, event=None):
self.endoffile = False
self.canceled = True
if (self.executing and self.interp.rpcclt):
if self.interp.getdebugger():
self.interp.restart_subprocess()
else:
self.interp.interrupt_subprocess()
self.interp.write("\nKeyboardInterrupt\n")
self.interp.interrupt_subprocess()
if self.reading:
self.top.quit() # exit the nested mainloop() in readline()
return "break"
Expand Down
8 changes: 7 additions & 1 deletion Lib/idlelib/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ class Executive:

def __init__(self, rpchandler):
self.rpchandler = rpchandler
self.idb = None
if idlelib.testing is False:
self.locals = __main__.__dict__
self.calltip = calltip.Calltip()
Expand Down Expand Up @@ -605,13 +606,18 @@ def runcode(self, code):
def interrupt_the_server(self):
if interruptable:
thread.interrupt_main()
elif self.idb:
self.idb.user_interrupt(True)

def start_the_debugger(self, gui_adap_oid):
return debugger_r.start_debugger(self.rpchandler, gui_adap_oid)
oid, idb = debugger_r.start_debugger(self.rpchandler, gui_adap_oid)
self.idb = idb
return oid

def stop_the_debugger(self, idb_adap_oid):
"Unregister the Idb Adapter. Link objects and Idb then subject to GC"
self.rpchandler.unregister(idb_adap_oid)
self.idb = None

def get_the_calltip(self, name):
return self.calltip.fetch_tip(name)
Expand Down