[Python-checkins] cpython (merge 3.5 -> default): Merge with 3.5

terry.reedy python-checkins at python.org
Fri Nov 20 19:37:35 EST 2015


https://hg.python.org/cpython/rev/dfadf250610e
changeset: 99252:dfadf250610e
parent: 99248:3128f51967b4
parent: 99251:2eb9c4abfee1
user: Terry Jan Reedy <tjreedy at udel.edu>
date: Fri Nov 20 19:37:14 2015 -0500
summary:
 Merge with 3.5
files:
 Lib/idlelib/Debugger.py | 60 +++++++++++++++++++++++++---
 1 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py
--- a/Lib/idlelib/Debugger.py
+++ b/Lib/idlelib/Debugger.py
@@ -17,7 +17,10 @@
 self.set_step()
 return
 message = self.__frame2message(frame)
- self.gui.interaction(message, frame)
+ try:
+ self.gui.interaction(message, frame)
+ except (TclError, RuntimeError):
+ pass
 
 def user_exception(self, frame, info):
 if self.in_rpc_code(frame):
@@ -59,8 +62,42 @@
 self.frame = None
 self.make_gui()
 self.interacting = 0
+ self.nesting_level = 0
 
 def run(self, *args):
+ # Deal with the scenario where we've already got a program running
+ # in the debugger and we want to start another. If that is the case,
+ # our second 'run' was invoked from an event dispatched not from
+ # the main event loop, but from the nested event loop in 'interaction'
+ # below. So our stack looks something like this:
+ # outer main event loop
+ # run()
+ # <running program with traces>
+ # callback to debugger's interaction()
+ # nested event loop
+ # run() for second command
+ #
+ # This kind of nesting of event loops causes all kinds of problems
+ # (see e.g. issue #24455) especially when dealing with running as a
+ # subprocess, where there's all kinds of extra stuff happening in
+ # there - insert a traceback.print_stack() to check it out.
+ #
+ # By this point, we've already called restart_subprocess() in
+ # ScriptBinding. However, we also need to unwind the stack back to
+ # that outer event loop. To accomplish this, we:
+ # - return immediately from the nested run()
+ # - abort_loop ensures the nested event loop will terminate
+ # - the debugger's interaction routine completes normally
+ # - the restart_subprocess() will have taken care of stopping
+ # the running program, which will also let the outer run complete
+ #
+ # That leaves us back at the outer main event loop, at which point our
+ # after event can fire, and we'll come back to this routine with a
+ # clean stack.
+ if self.nesting_level > 0:
+ self.abort_loop()
+ self.root.after(100, lambda: self.run(*args))
+ return
 try:
 self.interacting = 1
 return self.idb.run(*args)
@@ -71,6 +108,7 @@
 if self.interacting:
 self.top.bell()
 return
+ self.abort_loop()
 if self.stackviewer:
 self.stackviewer.close(); self.stackviewer = None
 # Clean up pyshell if user clicked debugger control close widget.
@@ -191,7 +229,12 @@
 b.configure(state="normal")
 #
 self.top.wakeup()
- self.root.mainloop()
+ # Nested main loop: Tkinter's main loop is not reentrant, so use
+ # Tcl's vwait facility, which reenters the event loop until an
+ # event handler sets the variable we're waiting on
+ self.nesting_level += 1
+ self.root.tk.call('vwait', '::idledebugwait')
+ self.nesting_level -= 1
 #
 for b in self.buttons:
 b.configure(state="disabled")
@@ -215,23 +258,26 @@
 
 def cont(self):
 self.idb.set_continue()
- self.root.quit()
+ self.abort_loop()
 
 def step(self):
 self.idb.set_step()
- self.root.quit()
+ self.abort_loop()
 
 def next(self):
 self.idb.set_next(self.frame)
- self.root.quit()
+ self.abort_loop()
 
 def ret(self):
 self.idb.set_return(self.frame)
- self.root.quit()
+ self.abort_loop()
 
 def quit(self):
 self.idb.set_quit()
- self.root.quit()
+ self.abort_loop()
+
+ def abort_loop(self):
+ self.root.tk.call('set', '::idledebugwait', '1')
 
 stackviewer = None
 
-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /