From b772fce990760c11e9bc1828b4d98eafd4a36d4d Mon Sep 17 00:00:00 2001 From: Louie Lu Date: Thu, 25 May 2017 15:48:20 +0800 Subject: [PATCH 1/6] bpo-14111: IDLE: Add interrupt handle when open debugger Patched by: Roger Serwy --- Lib/idlelib/debugger.py | 25 +++++++++++++++++++++++++ Lib/idlelib/debugger_r.py | 9 ++++++++- Lib/idlelib/pyshell.py | 5 +---- Lib/idlelib/run.py | 8 +++++++- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index 114d0d128e883e..16e74f069ad87e 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -13,6 +13,7 @@ class Idb(bdb.Bdb): def __init__(self, gui): self.gui = gui + self._interrupt = False bdb.Bdb.__init__(self) def user_line(self, frame): @@ -32,6 +33,25 @@ def user_exception(self, frame, info): message = self.__frame2message(frame) self.gui.interaction(message, frame, info) + def user_interrupt(self, value): + 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 @@ -265,22 +285,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() diff --git a/Lib/idlelib/debugger_r.py b/Lib/idlelib/debugger_r.py index bc971276de6727..7f9331b9689432 100644 --- a/Lib/idlelib/debugger_r.py +++ b/Lib/idlelib/debugger_r.py @@ -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): @@ -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 #======================================= @@ -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 diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 5b0e5b267642ab..a4d310c4605329 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1087,10 +1087,7 @@ def cancel_callback(self, event=None): self.endoffile = 0 self.canceled = 1 if (self.executing and self.interp.rpcclt): - if self.interp.getdebugger(): - self.interp.restart_subprocess() - else: - self.interp.interrupt_subprocess() + self.interp.interrupt_subprocess() if self.reading: self.top.quit() # exit the nested mainloop() in readline() return "break" diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 12c339f1058b72..5ee34ad72e2704 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -450,6 +450,7 @@ def __init__(self, rpchandler): self.locals = __main__.__dict__ self.calltip = calltips.CallTips() self.autocomplete = autocomplete.AutoComplete() + self.idb = None def runcode(self, code): global interruptable @@ -479,13 +480,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) From 8c1086c5f7150b64d55161d225c538a9ec237128 Mon Sep 17 00:00:00 2001 From: Louie Lu Date: Thu, 25 May 2017 16:23:17 +0800 Subject: [PATCH 2/6] Fix debugger step into bdb after go and interrupt --- Lib/idlelib/debugger.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index 16e74f069ad87e..50fd127f7bb996 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -34,6 +34,9 @@ def user_exception(self, frame, info): 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 From c5e3daedc94e66300490339f6e3b6ae2a2783686 Mon Sep 17 00:00:00 2001 From: Louie Lu Date: Thu, 25 May 2017 16:24:01 +0800 Subject: [PATCH 3/6] Add KeyboardInterrupt word when interrupt in debugger run --- Lib/idlelib/pyshell.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index a4d310c4605329..33a7af8b2183e4 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1087,6 +1087,7 @@ def cancel_callback(self, event=None): self.endoffile = 0 self.canceled = 1 if (self.executing and self.interp.rpcclt): + self.interp.write("\nKeyboardInterrupt\n") self.interp.interrupt_subprocess() if self.reading: self.top.quit() # exit the nested mainloop() in readline() From b0aea6e828b3f9e2c39d2cc2c51aea0320849d68 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Wed, 2 Dec 2020 10:10:49 -0500 Subject: [PATCH 4/6] Add back new line in pr --- Lib/idlelib/debugger.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py index 2586b816b29ca4..63f4951b6d977f 100644 --- a/Lib/idlelib/debugger.py +++ b/Lib/idlelib/debugger.py @@ -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): From 81e308d25096ab4ac0a2462ac8f9a487b8f48ccd Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 27 Nov 2022 23:49:10 -0500 Subject: [PATCH 5/6] Update run.py --- Lib/idlelib/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 576ac2cb5ad60a..430d02f97e0ce4 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -562,12 +562,12 @@ 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() self.autocomplete = autocomplete.AutoComplete() - self.idb = None else: self.locals = {} From b82d04f9910351554538f6932614e3e035c8be53 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 27 Nov 2022 23:50:40 -0500 Subject: [PATCH 6/6] Update run.py --- Lib/idlelib/run.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 430d02f97e0ce4..4e4a655b4bfa97 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -563,7 +563,6 @@ 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()