diff options
author | Kurt B. Kaiser <kbk@shore.net> | 2003-05-15 03:19:42 (GMT) |
---|---|---|
committer | Kurt B. Kaiser <kbk@shore.net> | 2003-05-15 03:19:42 (GMT) |
commit | 7f38ec0849fd2b19e660350c59d42b8b5cfae2d1 (patch) | |
tree | 243051301d3e14045e8b118b83ab7fa7d8719e05 | |
parent | f655dff80782cd6bf59d64985299bd07546cb98b (diff) | |
download | cpython-7f38ec0849fd2b19e660350c59d42b8b5cfae2d1.zip cpython-7f38ec0849fd2b19e660350c59d42b8b5cfae2d1.tar.gz cpython-7f38ec0849fd2b19e660350c59d42b8b5cfae2d1.tar.bz2 |
1. Restore the capability to run and debug without a subprocess.
2. Add an indicator to the shell startup notice when running w/o
subprocess.
3. Improve exception reporting when running a command or script from the
command line.
4. Clarify the fact that breakpoints set or cleared after a file is
saved will revert to the saved state if the file is closed without
re-saving.
5. If user tries to exit or restart when user code is running, interrupt
the user code. This helps to eliminate occasional hanging
subprocesses on Windows (except for Freddy :).
M NEWS.txt
M PyShell.py
M ScriptBinding.py
-rw-r--r-- | Lib/idlelib/NEWS.txt | 16 | ||||
-rw-r--r-- | Lib/idlelib/PyShell.py | 119 | ||||
-rw-r--r-- | Lib/idlelib/ScriptBinding.py | 17 |
3 files changed, 98 insertions, 54 deletions
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt index ba0307e..d24c34b9 100644 --- a/Lib/idlelib/NEWS.txt +++ b/Lib/idlelib/NEWS.txt @@ -7,6 +7,22 @@ What's New in IDLEfork 0.9b1? *Release date: XX-XXX-2003* +- Interrupt the subprocess if it is running when the user attempts to + restart the shell, run a module, or exit. + +- Improved exception reporting when running commands or scripts from the + command line. + +- Added a comment to the shell startup header to indicate when IDLE is not + using the subprocess. (For now, set PyShell.use_subprocess to False to run + in this mode.) + +- Restore the ability to run without the subprocess. This can be important for + some platforms or configurations. (Running without the subprocess allows the + debugger to trace through parts of IDLE itself, which may or may not be + desirable, depending on your point of view. In addition, the traditional + reload/import tricks must be use if user source code is changed.) + - Improve the error message a user gets when saving a file with non-ASCII characters and no source encoding is specified. Done by adding a dialog 'EncodingMessage', which contains the line to add in a fixed-font entry diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index 6e3a43a..f3312a8 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -31,6 +31,7 @@ from configHandler import idleConf import idlever import rpc +import Debugger import RemoteDebugger IDENTCHARS = string.ascii_letters + string.digits + "_" @@ -160,9 +161,10 @@ class PyShellEditorWindow(EditorWindow): # a temporary file save feature the save breaks functionality # needs to be re-verified, since the breaks at the time the # temp file is created may differ from the breaks at the last - # permanent save of the file. A break introduced after a save - # will be effective, but not persistent. This is necessary to - # keep the saved breaks synched with the saved file. + # permanent save of the file. Currently, a break introduced + # after a save will be effective, but not persistent. + # This is necessary to keep the saved breaks synched with the + # saved file. # # Breakpoints are set as tagged ranges in the text. Certain # kinds of edits cause these ranges to be deleted: Inserting @@ -361,17 +363,18 @@ class ModifiedInterpreter(InteractiveInterpreter): # Kill subprocess, spawn a new one, accept connection. self.rpcclt.close() self.unix_terminate() - self.tkconsole.executing = False + console = self.tkconsole + console.executing = False self.spawn_subprocess() self.rpcclt.accept() self.transfer_path() # annotate restart in shell window and mark it - console = self.tkconsole console.text.delete("iomark", "end-1c") halfbar = ((int(console.width) - 16) // 2) * '=' console.write(halfbar + ' RESTART ' + halfbar) console.text.mark_set("restart", "end-1c") console.text.mark_gravity("restart", "left") + console.showprompt() # restart subprocess debugger if debug: # Restarted debugger connects to current instance of debug GUI @@ -489,8 +492,9 @@ class ModifiedInterpreter(InteractiveInterpreter): code = compile(source, filename, "exec") except (OverflowError, SyntaxError): self.tkconsole.resetoutput() - console = self.tkconsole.console - print >>console, 'Traceback (most recent call last):' + tkerr = self.tkconsole.stderr + print>>tkerr, '*** Error in script or command!\n' + print>>tkerr, 'Traceback (most recent call last):' InteractiveInterpreter.showsyntaxerror(self, filename) self.tkconsole.showprompt() else: @@ -608,30 +612,34 @@ class ModifiedInterpreter(InteractiveInterpreter): warnings.filters[:] = self.save_warnings_filters self.save_warnings_filters = None debugger = self.debugger - self.tkconsole.beginexecuting() try: - if not debugger and self.rpcclt is not None: - self.active_seq = self.rpcclt.asyncqueue("exec", "runcode", - (code,), {}) - elif debugger: - debugger.run(code, self.locals) - else: - exec code in self.locals - except SystemExit: - if tkMessageBox.askyesno( - "Exit?", - "Do you want to exit altogether?", - default="yes", - master=self.tkconsole.text): - raise - else: + self.tkconsole.beginexecuting() + try: + if not debugger and self.rpcclt is not None: + self.active_seq = self.rpcclt.asyncqueue("exec", "runcode", + (code,), {}) + elif debugger: + debugger.run(code, self.locals) + else: + exec code in self.locals + except SystemExit: + if tkMessageBox.askyesno( + "Exit?", + "Do you want to exit altogether?", + default="yes", + master=self.tkconsole.text): + raise + else: + self.showtraceback() + except: self.showtraceback() - except: - self.showtraceback() + finally: + if not use_subprocess: + self.tkconsole.endexecuting() def write(self, s): "Override base class method" - self.tkconsole.console.write(s) + self.tkconsole.stderr.write(s) class PyShell(OutputWindow): @@ -741,22 +749,13 @@ class PyShell(OutputWindow): self.set_debugger_indicator() def open_debugger(self): - # XXX KBK 13Jun02 An RPC client always exists now? Open remote - # debugger and return...dike the rest of this fcn and combine - # with open_remote_debugger? if self.interp.rpcclt: - return self.open_remote_debugger() - import Debugger - self.interp.setdebugger(Debugger.Debugger(self)) - sys.ps1 = "[DEBUG ON]\n>>> " - self.showprompt() - self.set_debugger_indicator() - - def open_remote_debugger(self): - gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self) - self.interp.setdebugger(gui) - # Load all PyShellEditorWindow breakpoints: - gui.load_breakpoints() + dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, + self) + else: + dbg_gui = Debugger.Debugger(self) + self.interp.setdebugger(dbg_gui) + dbg_gui.load_breakpoints() sys.ps1 = "[DEBUG ON]\n>>> " self.showprompt() self.set_debugger_indicator() @@ -779,18 +778,22 @@ class PyShell(OutputWindow): "Kill?", "The program is still running!\n Do you want to kill it?", default="ok", - master=self.text) + parent=self.text) if response == False: return "cancel" # interrupt the subprocess - self.closing = True - self.endexecuting() - return EditorWindow.close(self) + self.canceled = True + if use_subprocess: + self.interp.interrupt_subprocess() + return "cancel" + else: + return EditorWindow.close(self) def _close(self): "Extend EditorWindow._close(), shut down debugger and execution server" self.close_debugger() - self.interp.kill_subprocess() + if use_subprocess: + self.interp.kill_subprocess() # Restore std streams sys.stdout = self.save_stdout sys.stderr = self.save_stderr @@ -814,9 +817,13 @@ class PyShell(OutputWindow): def begin(self): self.resetoutput() - self.write("Python %s on %s\n%s\nIDLEfork %s\n" % + if use_subprocess: + nosub = '' + else: + nosub = "==== No Subprocess ====" + self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" % (sys.version, sys.platform, self.COPYRIGHT, - idlever.IDLE_VERSION)) + idlever.IDLE_VERSION, nosub)) self.showprompt() import Tkinter Tkinter._default_root = None @@ -853,7 +860,7 @@ class PyShell(OutputWindow): pass if not (self.executing or self.reading): self.resetoutput() - self.write("KeyboardInterrupt\n") + self.interp.write("KeyboardInterrupt\n") self.showprompt() return "break" self.endoffile = 0 @@ -997,8 +1004,16 @@ class PyShell(OutputWindow): self.text.see("restart") def restart_shell(self, event=None): - self.interp.restart_subprocess() - self.showprompt() + if self.executing: + self.cancel_callback() + # Wait for subprocess to interrupt and restart + # This can be a long time if shell is scrolling on a slow system + # XXX 14 May 03 KBK This delay (and one in ScriptBinding) could be + # shorter if we didn't print the KeyboardInterrupt on + # restarting while user code is running.... + self.text.after(2000, self.interp.restart_subprocess) + else: + self.interp.restart_subprocess() def showprompt(self): self.resetoutput() @@ -1030,6 +1045,8 @@ class PyShell(OutputWindow): pass if self.canceled: self.canceled = 0 + if not use_subprocess: + raise KeyboardInterrupt class PseudoFile: diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py index 9604cb8..d404fc9 100644 --- a/Lib/idlelib/ScriptBinding.py +++ b/Lib/idlelib/ScriptBinding.py @@ -22,6 +22,7 @@ import string import tabnanny import tokenize import tkMessageBox +import PyShell IDENTCHARS = string.ascii_letters + string.digits + "_" @@ -38,8 +39,6 @@ To fix case 2, change all tabs to spaces by using Select All followed \ by Untabify Region (both in the Edit menu).""" -# XXX 11Jun02 KBK TBD Implement stop-execution - class ScriptBinding: menudefs = [ @@ -124,7 +123,19 @@ class ScriptBinding: flist = self.editwin.flist shell = flist.open_shell() interp = shell.interp - interp.restart_subprocess() + if PyShell.use_subprocess: + shell.restart_shell() + if shell.executing: + delay = 2700 + else: + delay = 500 + # Wait for the interrupt and reset to finish + shell.text.after(delay, self.run_module_event2, interp, + filename, code) + else: + self.run_module_event2(interp, filename, code) + + def run_module_event2(self, interp, filename, code): # XXX Too often this discards arguments the user just set... interp.runcommand("""if 1: _filename = %s |