Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7f38ec0

Browse files
committed
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
1 parent f655dff commit 7f38ec0

3 files changed

Lines changed: 98 additions & 54 deletions

File tree

Lib/idlelib/NEWS.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@ What's New in IDLEfork 0.9b1?
77

88
*Release date: XX-XXX-2003*
99

10+
- Interrupt the subprocess if it is running when the user attempts to
11+
restart the shell, run a module, or exit.
12+
13+
- Improved exception reporting when running commands or scripts from the
14+
command line.
15+
16+
- Added a comment to the shell startup header to indicate when IDLE is not
17+
using the subprocess. (For now, set PyShell.use_subprocess to False to run
18+
in this mode.)
19+
20+
- Restore the ability to run without the subprocess. This can be important for
21+
some platforms or configurations. (Running without the subprocess allows the
22+
debugger to trace through parts of IDLE itself, which may or may not be
23+
desirable, depending on your point of view. In addition, the traditional
24+
reload/import tricks must be use if user source code is changed.)
25+
1026
- Improve the error message a user gets when saving a file with non-ASCII
1127
characters and no source encoding is specified. Done by adding a dialog
1228
'EncodingMessage', which contains the line to add in a fixed-font entry

Lib/idlelib/PyShell.py

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import idlever
3232

3333
import rpc
34+
import Debugger
3435
import RemoteDebugger
3536

3637
IDENTCHARS = string.ascii_letters + string.digits + "_"
@@ -160,9 +161,10 @@ def store_file_breaks(self):
160161
# a temporary file save feature the save breaks functionality
161162
# needs to be re-verified, since the breaks at the time the
162163
# temp file is created may differ from the breaks at the last
163-
# permanent save of the file. A break introduced after a save
164-
# will be effective, but not persistent. This is necessary to
165-
# keep the saved breaks synched with the saved file.
164+
# permanent save of the file. Currently, a break introduced
165+
# after a save will be effective, but not persistent.
166+
# This is necessary to keep the saved breaks synched with the
167+
# saved file.
166168
#
167169
# Breakpoints are set as tagged ranges in the text. Certain
168170
# kinds of edits cause these ranges to be deleted: Inserting
@@ -361,17 +363,18 @@ def restart_subprocess(self):
361363
# Kill subprocess, spawn a new one, accept connection.
362364
self.rpcclt.close()
363365
self.unix_terminate()
364-
self.tkconsole.executing = False
366+
console = self.tkconsole
367+
console.executing = False
365368
self.spawn_subprocess()
366369
self.rpcclt.accept()
367370
self.transfer_path()
368371
# annotate restart in shell window and mark it
369-
console = self.tkconsole
370372
console.text.delete("iomark", "end-1c")
371373
halfbar = ((int(console.width) - 16) // 2) * '='
372374
console.write(halfbar + ' RESTART ' + halfbar)
373375
console.text.mark_set("restart", "end-1c")
374376
console.text.mark_gravity("restart", "left")
377+
console.showprompt()
375378
# restart subprocess debugger
376379
if debug:
377380
# Restarted debugger connects to current instance of debug GUI
@@ -489,8 +492,9 @@ def execfile(self, filename, source=None):
489492
code = compile(source, filename, "exec")
490493
except (OverflowError, SyntaxError):
491494
self.tkconsole.resetoutput()
492-
console = self.tkconsole.console
493-
print >>console, 'Traceback (most recent call last):'
495+
tkerr = self.tkconsole.stderr
496+
print>>tkerr, '*** Error in script or command!\n'
497+
print>>tkerr, 'Traceback (most recent call last):'
494498
InteractiveInterpreter.showsyntaxerror(self, filename)
495499
self.tkconsole.showprompt()
496500
else:
@@ -608,30 +612,34 @@ def runcode(self, code):
608612
warnings.filters[:] = self.save_warnings_filters
609613
self.save_warnings_filters = None
610614
debugger = self.debugger
611-
self.tkconsole.beginexecuting()
612615
try:
613-
if not debugger and self.rpcclt is not None:
614-
self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
615-
(code,), {})
616-
elif debugger:
617-
debugger.run(code, self.locals)
618-
else:
619-
exec code in self.locals
620-
except SystemExit:
621-
if tkMessageBox.askyesno(
622-
"Exit?",
623-
"Do you want to exit altogether?",
624-
default="yes",
625-
master=self.tkconsole.text):
626-
raise
627-
else:
616+
self.tkconsole.beginexecuting()
617+
try:
618+
if not debugger and self.rpcclt is not None:
619+
self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
620+
(code,), {})
621+
elif debugger:
622+
debugger.run(code, self.locals)
623+
else:
624+
exec code in self.locals
625+
except SystemExit:
626+
if tkMessageBox.askyesno(
627+
"Exit?",
628+
"Do you want to exit altogether?",
629+
default="yes",
630+
master=self.tkconsole.text):
631+
raise
632+
else:
633+
self.showtraceback()
634+
except:
628635
self.showtraceback()
629-
except:
630-
self.showtraceback()
636+
finally:
637+
if not use_subprocess:
638+
self.tkconsole.endexecuting()
631639

632640
def write(self, s):
633641
"Override base class method"
634-
self.tkconsole.console.write(s)
642+
self.tkconsole.stderr.write(s)
635643

636644
class PyShell(OutputWindow):
637645

@@ -741,22 +749,13 @@ def close_debugger(self):
741749
self.set_debugger_indicator()
742750

743751
def open_debugger(self):
744-
# XXX KBK 13Jun02 An RPC client always exists now? Open remote
745-
# debugger and return...dike the rest of this fcn and combine
746-
# with open_remote_debugger?
747752
if self.interp.rpcclt:
748-
return self.open_remote_debugger()
749-
import Debugger
750-
self.interp.setdebugger(Debugger.Debugger(self))
751-
sys.ps1 = "[DEBUG ON]\n>>> "
752-
self.showprompt()
753-
self.set_debugger_indicator()
754-
755-
def open_remote_debugger(self):
756-
gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self)
757-
self.interp.setdebugger(gui)
758-
# Load all PyShellEditorWindow breakpoints:
759-
gui.load_breakpoints()
753+
dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt,
754+
self)
755+
else:
756+
dbg_gui = Debugger.Debugger(self)
757+
self.interp.setdebugger(dbg_gui)
758+
dbg_gui.load_breakpoints()
760759
sys.ps1 = "[DEBUG ON]\n>>> "
761760
self.showprompt()
762761
self.set_debugger_indicator()
@@ -779,18 +778,22 @@ def close(self):
779778
"Kill?",
780779
"The program is still running!\n Do you want to kill it?",
781780
default="ok",
782-
master=self.text)
781+
parent=self.text)
783782
if response == False:
784783
return "cancel"
785784
# interrupt the subprocess
786-
self.closing = True
787-
self.endexecuting()
788-
return EditorWindow.close(self)
785+
self.canceled = True
786+
if use_subprocess:
787+
self.interp.interrupt_subprocess()
788+
return "cancel"
789+
else:
790+
return EditorWindow.close(self)
789791

790792
def _close(self):
791793
"Extend EditorWindow._close(), shut down debugger and execution server"
792794
self.close_debugger()
793-
self.interp.kill_subprocess()
795+
if use_subprocess:
796+
self.interp.kill_subprocess()
794797
# Restore std streams
795798
sys.stdout = self.save_stdout
796799
sys.stderr = self.save_stderr
@@ -814,9 +817,13 @@ def short_title(self):
814817

815818
def begin(self):
816819
self.resetoutput()
817-
self.write("Python %s on %s\n%s\nIDLEfork %s\n" %
820+
if use_subprocess:
821+
nosub = ''
822+
else:
823+
nosub = "==== No Subprocess ===="
824+
self.write("Python %s on %s\n%s\nIDLEfork %s %s\n" %
818825
(sys.version, sys.platform, self.COPYRIGHT,
819-
idlever.IDLE_VERSION))
826+
idlever.IDLE_VERSION, nosub))
820827
self.showprompt()
821828
import Tkinter
822829
Tkinter._default_root = None
@@ -853,7 +860,7 @@ def cancel_callback(self, event=None):
853860
pass
854861
if not (self.executing or self.reading):
855862
self.resetoutput()
856-
self.write("KeyboardInterrupt\n")
863+
self.interp.write("KeyboardInterrupt\n")
857864
self.showprompt()
858865
return "break"
859866
self.endoffile = 0
@@ -997,8 +1004,16 @@ def view_restart_mark(self, event=None):
9971004
self.text.see("restart")
9981005

9991006
def restart_shell(self, event=None):
1000-
self.interp.restart_subprocess()
1001-
self.showprompt()
1007+
if self.executing:
1008+
self.cancel_callback()
1009+
# Wait for subprocess to interrupt and restart
1010+
# This can be a long time if shell is scrolling on a slow system
1011+
# XXX 14 May 03 KBK This delay (and one in ScriptBinding) could be
1012+
# shorter if we didn't print the KeyboardInterrupt on
1013+
# restarting while user code is running....
1014+
self.text.after(2000, self.interp.restart_subprocess)
1015+
else:
1016+
self.interp.restart_subprocess()
10021017

10031018
def showprompt(self):
10041019
self.resetoutput()
@@ -1030,6 +1045,8 @@ def write(self, s, tags=()):
10301045
pass
10311046
if self.canceled:
10321047
self.canceled = 0
1048+
if not use_subprocess:
1049+
raise KeyboardInterrupt
10331050

10341051
class PseudoFile:
10351052

Lib/idlelib/ScriptBinding.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import tabnanny
2323
import tokenize
2424
import tkMessageBox
25+
import PyShell
2526

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

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

4041

41-
# XXX 11Jun02 KBK TBD Implement stop-execution
42-
4342
class ScriptBinding:
4443

4544
menudefs = [
@@ -124,7 +123,19 @@ def run_module_event(self, event):
124123
flist = self.editwin.flist
125124
shell = flist.open_shell()
126125
interp = shell.interp
127-
interp.restart_subprocess()
126+
if PyShell.use_subprocess:
127+
shell.restart_shell()
128+
if shell.executing:
129+
delay = 2700
130+
else:
131+
delay = 500
132+
# Wait for the interrupt and reset to finish
133+
shell.text.after(delay, self.run_module_event2, interp,
134+
filename, code)
135+
else:
136+
self.run_module_event2(interp, filename, code)
137+
138+
def run_module_event2(self, interp, filename, code):
128139
# XXX Too often this discards arguments the user just set...
129140
interp.runcommand("""if 1:
130141
_filename = %s

0 commit comments

Comments
 (0)