Skip to content

Commit

Permalink
1. Restore the capability to run and debug without a subprocess.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kbkaiser committed May 15, 2003
1 parent f655dff commit 7f38ec0
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 54 deletions.
16 changes: 16 additions & 0 deletions Lib/idlelib/NEWS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
119 changes: 68 additions & 51 deletions Lib/idlelib/PyShell.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import idlever

import rpc
import Debugger
import RemoteDebugger

IDENTCHARS = string.ascii_letters + string.digits + "_"
Expand Down Expand Up @@ -160,9 +161,10 @@ def store_file_breaks(self):
# 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
Expand Down Expand Up @@ -361,17 +363,18 @@ def restart_subprocess(self):
# 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
Expand Down Expand Up @@ -489,8 +492,9 @@ def execfile(self, filename, source=None):
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:
Expand Down Expand Up @@ -608,30 +612,34 @@ def runcode(self, code):
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):

Expand Down Expand Up @@ -741,22 +749,13 @@ def close_debugger(self):
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()
Expand All @@ -779,18 +778,22 @@ def close(self):
"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
Expand All @@ -814,9 +817,13 @@ def short_title(self):

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
Expand Down Expand Up @@ -853,7 +860,7 @@ def cancel_callback(self, event=None):
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
Expand Down Expand Up @@ -997,8 +1004,16 @@ def view_restart_mark(self, event=None):
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()
Expand Down Expand Up @@ -1030,6 +1045,8 @@ def write(self, s, tags=()):
pass
if self.canceled:
self.canceled = 0
if not use_subprocess:
raise KeyboardInterrupt

class PseudoFile:

Expand Down
17 changes: 14 additions & 3 deletions Lib/idlelib/ScriptBinding.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import tabnanny
import tokenize
import tkMessageBox
import PyShell

IDENTCHARS = string.ascii_letters + string.digits + "_"

Expand All @@ -38,8 +39,6 @@
by Untabify Region (both in the Edit menu)."""


# XXX 11Jun02 KBK TBD Implement stop-execution

class ScriptBinding:

menudefs = [
Expand Down Expand Up @@ -124,7 +123,19 @@ def run_module_event(self, event):
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
Expand Down

0 comments on commit 7f38ec0

Please sign in to comment.