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
This commit is contained in:
Kurt B. Kaiser 2003-05-24 20:59:15 +00:00
parent ebc198faa9
commit 67fd0ea46d
4 changed files with 57 additions and 64 deletions

View file

@ -296,6 +296,14 @@ def delete(self, index1, index2=None):
pass
UndoDelegator.delete(self, index1, index2)
class MyRPCClient(rpc.RPCClient):
def handle_EOF(self):
"Override the base class - just re-raise EOFError"
raise EOFError
class ModifiedInterpreter(InteractiveInterpreter):
def __init__(self, tkconsole):
@ -329,7 +337,7 @@ def start_subprocess(self):
for i in range(3):
time.sleep(i)
try:
self.rpcclt = rpc.RPCClient(addr)
self.rpcclt = MyRPCClient(addr)
break
except socket.error, err:
print>>sys.__stderr__,"IDLE socket error: " + err[1]\
@ -426,9 +434,10 @@ def poll_subprocess(self):
except (EOFError, IOError, KeyboardInterrupt):
# lost connection or subprocess terminated itself, restart
# [the KBI is from rpc.SocketIO.handle_EOF()]
if self.tkconsole.closing:
return
response = None
self.restart_subprocess()
self.tkconsole.endexecuting()
if response:
self.tkconsole.resetoutput()
self.active_seq = None
@ -673,7 +682,9 @@ class PyShell(OutputWindow):
def __init__(self, flist=None):
if use_subprocess:
self.menu_specs.insert(2, ("shell", "_Shell"))
ms = self.menu_specs
if ms[2][0] != "shell":
ms.insert(2, ("shell", "_Shell"))
self.interp = ModifiedInterpreter(self)
if flist is None:
root = Tk()
@ -793,15 +804,9 @@ def close(self):
parent=self.text)
if response == False:
return "cancel"
# interrupt the subprocess
self.canceled = True
if use_subprocess:
self.interp.interrupt_subprocess()
return "cancel"
else:
self.closing = True
# Wait for poll_subprocess() rescheduling to stop
self.text.after(2 * self.pollinterval, self.close2)
self.closing = True
# Wait for poll_subprocess() rescheduling to stop
self.text.after(2 * self.pollinterval, self.close2)
def close2(self):
return EditorWindow.close(self)
@ -885,7 +890,10 @@ def cancel_callback(self, event=None):
if self.reading:
self.top.quit()
elif (self.executing and self.interp.rpcclt):
self.interp.interrupt_subprocess()
if self.interp.getdebugger():
self.interp.restart_subprocess()
else:
self.interp.interrupt_subprocess()
return "break"
def eof_callback(self, event):
@ -1021,16 +1029,7 @@ def view_restart_mark(self, event=None):
self.text.see("restart")
def restart_shell(self, event=None):
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()
self.interp.restart_subprocess()
def showprompt(self):
self.resetoutput()

View file

@ -125,17 +125,6 @@ def run_module_event(self, event):
interp = shell.interp
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

View file

@ -41,7 +41,6 @@
import types
import marshal
import interrupt
def unpickle_code(ms):
co = marshal.loads(ms)
@ -327,12 +326,9 @@ def putmessage(self, message):
while len(s) > 0:
try:
n = self.sock.send(s)
except AttributeError:
except (AttributeError, socket.error):
# socket was closed
raise IOError
except socket.error:
self.debug("putmessage:socketerror:pid:%s" % os.getpid())
os._exit(0)
else:
s = s[n:]
@ -471,7 +467,6 @@ def handle_EOF(self):
self.responses[key] = ('EOF', None)
cv.notify()
cv.release()
interrupt.interrupt_main()
# call our (possibly overridden) exit function
self.exithook()

View file

@ -21,7 +21,8 @@
# the socket) and the main thread (which runs user code), plus global
# completion and exit flags:
exit_requested = False
exit_now = False
quitting = False
def main():
"""Start the Python execution server in a subprocess
@ -41,6 +42,8 @@ def main():
register and unregister themselves.
"""
global exit_now
global quitting
port = 8833
if sys.argv[1:]:
port = int(sys.argv[1])
@ -52,8 +55,12 @@ def main():
sockthread.start()
while 1:
try:
if exit_requested:
sys.exit(0)
if exit_now:
try:
sys.exit(0)
except KeyboardInterrupt:
# exiting but got an extra KBI? Try again!
continue
try:
seq, request = rpc.request_queue.get(0)
except Queue.Empty:
@ -63,17 +70,22 @@ def main():
ret = method(*args, **kwargs)
rpc.response_queue.put((seq, ret))
except KeyboardInterrupt:
if quitting:
exit_now = True
continue
except SystemExit:
raise
except:
type, value, tb = sys.exc_info()
try:
print_exception()
rpc.response_queue.put((seq, None))
except:
traceback.print_exc(file=sys.__stderr__)
sys.exit(1.1)
continue
# Link didn't work, print same exception to __stderr__
traceback.print_exception(type, value, tb, file=sys.__stderr__)
sys.exit(0)
else:
continue
def manage_socket(address):
for i in range(6):
@ -89,17 +101,17 @@ def manage_socket(address):
+ err[1] + ", retrying...."
else:
print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
global exit_requested
exit_requested = True
global exit_now
exit_now = True
return
server.handle_request() # A single request only
def print_exception():
flush_stdout()
efile = sys.stderr
typ, val, tb = info = sys.exc_info()
typ, val, tb = sys.exc_info()
tbe = traceback.extract_tb(tb)
print >>efile, 'Traceback (most recent call last):'
print >>efile, '\nTraceback (most recent call last):'
exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
"RemoteDebugger.py", "bdb.py")
cleanup_traceback(tbe, exclude)
@ -161,8 +173,8 @@ def handle_error(self, request, client_address):
except SystemExit:
raise
except EOFError:
global exit_requested
exit_requested = True
global exit_now
exit_now = True
interrupt.interrupt_main()
except:
erf = sys.__stderr__
@ -174,7 +186,7 @@ def handle_error(self, request, client_address):
traceback.print_exc(file=erf)
print>>erf, '\n*** Unrecoverable, server exiting!'
print>>erf, '-'*40
os._exit(0)
sys.exit(0)
class MyHandler(rpc.RPCHandler):
@ -190,15 +202,18 @@ def handle(self):
def exithook(self):
"override SocketIO method - wait for MainThread to shut us down"
while 1: pass
time.sleep(10)
def EOFhook(self):
"Override SocketIO method - terminate wait on callback and exit thread"
global exit_requested
exit_requested = True
global quitting
quitting = True
interrupt.interrupt_main()
def decode_interrupthook(self):
"interrupt awakened thread"
global quitting
quitting = True
interrupt.interrupt_main()
@ -213,15 +228,10 @@ def runcode(self, code):
try:
exec code in self.locals
except:
if exit_requested:
if quitting:
sys.exit(0)
try:
# even print a user code SystemExit exception, continue
print_exception()
except:
# link not working?
traceback.print_exc(file=sys.__stderr__)
sys.exit(1.2)
# even print a user code SystemExit exception, continue
print_exception()
else:
flush_stdout()