Skip to content

Commit 67fd0ea

Browse files
committed
1. Stake Freddy.
e.g. further improve subprocess interrupt, exceptions, and termination. 2. Remove the workarounds in PyShell.py and ScriptBinding.py involving interrupting the subprocess prior to killing it, not necessary anymore. 3. Fix a bug introduced at PyShell Rev 1.66: was getting extra shell menu every time the shell window was recreated. M PyShell.py M ScriptBinding.py M rpc.py M run.py
1 parent ebc198f commit 67fd0ea

4 files changed

Lines changed: 57 additions & 64 deletions

File tree

Lib/idlelib/PyShell.py

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,14 @@ def delete(self, index1, index2=None):
296296
pass
297297
UndoDelegator.delete(self, index1, index2)
298298

299+
300+
class MyRPCClient(rpc.RPCClient):
301+
302+
def handle_EOF(self):
303+
"Override the base class - just re-raise EOFError"
304+
raise EOFError
305+
306+
299307
class ModifiedInterpreter(InteractiveInterpreter):
300308

301309
def __init__(self, tkconsole):
@@ -329,7 +337,7 @@ def start_subprocess(self):
329337
for i in range(3):
330338
time.sleep(i)
331339
try:
332-
self.rpcclt = rpc.RPCClient(addr)
340+
self.rpcclt = MyRPCClient(addr)
333341
break
334342
except socket.error, err:
335343
print>>sys.__stderr__,"IDLE socket error: " + err[1]\
@@ -426,9 +434,10 @@ def poll_subprocess(self):
426434
except (EOFError, IOError, KeyboardInterrupt):
427435
# lost connection or subprocess terminated itself, restart
428436
# [the KBI is from rpc.SocketIO.handle_EOF()]
437+
if self.tkconsole.closing:
438+
return
429439
response = None
430440
self.restart_subprocess()
431-
self.tkconsole.endexecuting()
432441
if response:
433442
self.tkconsole.resetoutput()
434443
self.active_seq = None
@@ -673,7 +682,9 @@ class PyShell(OutputWindow):
673682

674683
def __init__(self, flist=None):
675684
if use_subprocess:
676-
self.menu_specs.insert(2, ("shell", "_Shell"))
685+
ms = self.menu_specs
686+
if ms[2][0] != "shell":
687+
ms.insert(2, ("shell", "_Shell"))
677688
self.interp = ModifiedInterpreter(self)
678689
if flist is None:
679690
root = Tk()
@@ -793,15 +804,9 @@ def close(self):
793804
parent=self.text)
794805
if response == False:
795806
return "cancel"
796-
# interrupt the subprocess
797-
self.canceled = True
798-
if use_subprocess:
799-
self.interp.interrupt_subprocess()
800-
return "cancel"
801-
else:
802-
self.closing = True
803-
# Wait for poll_subprocess() rescheduling to stop
804-
self.text.after(2 * self.pollinterval, self.close2)
807+
self.closing = True
808+
# Wait for poll_subprocess() rescheduling to stop
809+
self.text.after(2 * self.pollinterval, self.close2)
805810

806811
def close2(self):
807812
return EditorWindow.close(self)
@@ -885,7 +890,10 @@ def cancel_callback(self, event=None):
885890
if self.reading:
886891
self.top.quit()
887892
elif (self.executing and self.interp.rpcclt):
888-
self.interp.interrupt_subprocess()
893+
if self.interp.getdebugger():
894+
self.interp.restart_subprocess()
895+
else:
896+
self.interp.interrupt_subprocess()
889897
return "break"
890898

891899
def eof_callback(self, event):
@@ -1021,16 +1029,7 @@ def view_restart_mark(self, event=None):
10211029
self.text.see("restart")
10221030

10231031
def restart_shell(self, event=None):
1024-
if self.executing:
1025-
self.cancel_callback()
1026-
# Wait for subprocess to interrupt and restart
1027-
# This can be a long time if shell is scrolling on a slow system
1028-
# XXX 14 May 03 KBK This delay (and one in ScriptBinding) could be
1029-
# shorter if we didn't print the KeyboardInterrupt on
1030-
# restarting while user code is running....
1031-
self.text.after(2000, self.interp.restart_subprocess)
1032-
else:
1033-
self.interp.restart_subprocess()
1032+
self.interp.restart_subprocess()
10341033

10351034
def showprompt(self):
10361035
self.resetoutput()

Lib/idlelib/ScriptBinding.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,6 @@ def run_module_event(self, event):
125125
interp = shell.interp
126126
if PyShell.use_subprocess:
127127
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):
139128
# XXX Too often this discards arguments the user just set...
140129
interp.runcommand("""if 1:
141130
_filename = %s

Lib/idlelib/rpc.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import types
4242
import marshal
4343

44-
import interrupt
4544

4645
def unpickle_code(ms):
4746
co = marshal.loads(ms)
@@ -327,12 +326,9 @@ def putmessage(self, message):
327326
while len(s) > 0:
328327
try:
329328
n = self.sock.send(s)
330-
except AttributeError:
329+
except (AttributeError, socket.error):
331330
# socket was closed
332331
raise IOError
333-
except socket.error:
334-
self.debug("putmessage:socketerror:pid:%s" % os.getpid())
335-
os._exit(0)
336332
else:
337333
s = s[n:]
338334

@@ -471,7 +467,6 @@ def handle_EOF(self):
471467
self.responses[key] = ('EOF', None)
472468
cv.notify()
473469
cv.release()
474-
interrupt.interrupt_main()
475470
# call our (possibly overridden) exit function
476471
self.exithook()
477472

Lib/idlelib/run.py

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
# the socket) and the main thread (which runs user code), plus global
2222
# completion and exit flags:
2323

24-
exit_requested = False
24+
exit_now = False
25+
quitting = False
2526

2627
def main():
2728
"""Start the Python execution server in a subprocess
@@ -41,6 +42,8 @@ def main():
4142
register and unregister themselves.
4243
4344
"""
45+
global exit_now
46+
global quitting
4447
port = 8833
4548
if sys.argv[1:]:
4649
port = int(sys.argv[1])
@@ -52,8 +55,12 @@ def main():
5255
sockthread.start()
5356
while 1:
5457
try:
55-
if exit_requested:
56-
sys.exit(0)
58+
if exit_now:
59+
try:
60+
sys.exit(0)
61+
except KeyboardInterrupt:
62+
# exiting but got an extra KBI? Try again!
63+
continue
5764
try:
5865
seq, request = rpc.request_queue.get(0)
5966
except Queue.Empty:
@@ -63,17 +70,22 @@ def main():
6370
ret = method(*args, **kwargs)
6471
rpc.response_queue.put((seq, ret))
6572
except KeyboardInterrupt:
73+
if quitting:
74+
exit_now = True
6675
continue
6776
except SystemExit:
6877
raise
6978
except:
79+
type, value, tb = sys.exc_info()
7080
try:
7181
print_exception()
7282
rpc.response_queue.put((seq, None))
7383
except:
74-
traceback.print_exc(file=sys.__stderr__)
75-
sys.exit(1.1)
76-
continue
84+
# Link didn't work, print same exception to __stderr__
85+
traceback.print_exception(type, value, tb, file=sys.__stderr__)
86+
sys.exit(0)
87+
else:
88+
continue
7789

7890
def manage_socket(address):
7991
for i in range(6):
@@ -89,17 +101,17 @@ def manage_socket(address):
89101
+ err[1] + ", retrying...."
90102
else:
91103
print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
92-
global exit_requested
93-
exit_requested = True
104+
global exit_now
105+
exit_now = True
94106
return
95107
server.handle_request() # A single request only
96108

97109
def print_exception():
98110
flush_stdout()
99111
efile = sys.stderr
100-
typ, val, tb = info = sys.exc_info()
112+
typ, val, tb = sys.exc_info()
101113
tbe = traceback.extract_tb(tb)
102-
print >>efile, 'Traceback (most recent call last):'
114+
print >>efile, '\nTraceback (most recent call last):'
103115
exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
104116
"RemoteDebugger.py", "bdb.py")
105117
cleanup_traceback(tbe, exclude)
@@ -161,8 +173,8 @@ def handle_error(self, request, client_address):
161173
except SystemExit:
162174
raise
163175
except EOFError:
164-
global exit_requested
165-
exit_requested = True
176+
global exit_now
177+
exit_now = True
166178
interrupt.interrupt_main()
167179
except:
168180
erf = sys.__stderr__
@@ -174,7 +186,7 @@ def handle_error(self, request, client_address):
174186
traceback.print_exc(file=erf)
175187
print>>erf, '\n*** Unrecoverable, server exiting!'
176188
print>>erf, '-'*40
177-
os._exit(0)
189+
sys.exit(0)
178190

179191

180192
class MyHandler(rpc.RPCHandler):
@@ -190,15 +202,18 @@ def handle(self):
190202

191203
def exithook(self):
192204
"override SocketIO method - wait for MainThread to shut us down"
193-
while 1: pass
205+
time.sleep(10)
194206

195207
def EOFhook(self):
196208
"Override SocketIO method - terminate wait on callback and exit thread"
197-
global exit_requested
198-
exit_requested = True
209+
global quitting
210+
quitting = True
211+
interrupt.interrupt_main()
199212

200213
def decode_interrupthook(self):
201214
"interrupt awakened thread"
215+
global quitting
216+
quitting = True
202217
interrupt.interrupt_main()
203218

204219

@@ -213,15 +228,10 @@ def runcode(self, code):
213228
try:
214229
exec code in self.locals
215230
except:
216-
if exit_requested:
231+
if quitting:
217232
sys.exit(0)
218-
try:
219-
# even print a user code SystemExit exception, continue
220-
print_exception()
221-
except:
222-
# link not working?
223-
traceback.print_exc(file=sys.__stderr__)
224-
sys.exit(1.2)
233+
# even print a user code SystemExit exception, continue
234+
print_exception()
225235
else:
226236
flush_stdout()
227237

0 commit comments

Comments
 (0)