Commit 5353f4d6 authored by Kurt B. Kaiser's avatar Kurt B. Kaiser

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
parent 9665a685
...@@ -296,6 +296,14 @@ class ModifiedUndoDelegator(UndoDelegator): ...@@ -296,6 +296,14 @@ class ModifiedUndoDelegator(UndoDelegator):
pass pass
UndoDelegator.delete(self, index1, index2) 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): class ModifiedInterpreter(InteractiveInterpreter):
def __init__(self, tkconsole): def __init__(self, tkconsole):
...@@ -329,7 +337,7 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -329,7 +337,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
for i in range(3): for i in range(3):
time.sleep(i) time.sleep(i)
try: try:
self.rpcclt = rpc.RPCClient(addr) self.rpcclt = MyRPCClient(addr)
break break
except socket.error, err: except socket.error, err:
print>>sys.__stderr__,"IDLE socket error: " + err[1]\ print>>sys.__stderr__,"IDLE socket error: " + err[1]\
...@@ -426,9 +434,10 @@ class ModifiedInterpreter(InteractiveInterpreter): ...@@ -426,9 +434,10 @@ class ModifiedInterpreter(InteractiveInterpreter):
except (EOFError, IOError, KeyboardInterrupt): except (EOFError, IOError, KeyboardInterrupt):
# lost connection or subprocess terminated itself, restart # lost connection or subprocess terminated itself, restart
# [the KBI is from rpc.SocketIO.handle_EOF()] # [the KBI is from rpc.SocketIO.handle_EOF()]
if self.tkconsole.closing:
return
response = None response = None
self.restart_subprocess() self.restart_subprocess()
self.tkconsole.endexecuting()
if response: if response:
self.tkconsole.resetoutput() self.tkconsole.resetoutput()
self.active_seq = None self.active_seq = None
...@@ -673,7 +682,9 @@ class PyShell(OutputWindow): ...@@ -673,7 +682,9 @@ class PyShell(OutputWindow):
def __init__(self, flist=None): def __init__(self, flist=None):
if use_subprocess: 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) self.interp = ModifiedInterpreter(self)
if flist is None: if flist is None:
root = Tk() root = Tk()
...@@ -793,12 +804,6 @@ class PyShell(OutputWindow): ...@@ -793,12 +804,6 @@ class PyShell(OutputWindow):
parent=self.text) parent=self.text)
if response == False: if response == False:
return "cancel" return "cancel"
# interrupt the subprocess
self.canceled = True
if use_subprocess:
self.interp.interrupt_subprocess()
return "cancel"
else:
self.closing = True self.closing = True
# Wait for poll_subprocess() rescheduling to stop # Wait for poll_subprocess() rescheduling to stop
self.text.after(2 * self.pollinterval, self.close2) self.text.after(2 * self.pollinterval, self.close2)
...@@ -885,6 +890,9 @@ class PyShell(OutputWindow): ...@@ -885,6 +890,9 @@ class PyShell(OutputWindow):
if self.reading: if self.reading:
self.top.quit() self.top.quit()
elif (self.executing and self.interp.rpcclt): elif (self.executing and self.interp.rpcclt):
if self.interp.getdebugger():
self.interp.restart_subprocess()
else:
self.interp.interrupt_subprocess() self.interp.interrupt_subprocess()
return "break" return "break"
...@@ -1021,15 +1029,6 @@ class PyShell(OutputWindow): ...@@ -1021,15 +1029,6 @@ class PyShell(OutputWindow):
self.text.see("restart") self.text.see("restart")
def restart_shell(self, event=None): 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): def showprompt(self):
......
...@@ -125,17 +125,6 @@ class ScriptBinding: ...@@ -125,17 +125,6 @@ class ScriptBinding:
interp = shell.interp interp = shell.interp
if PyShell.use_subprocess: if PyShell.use_subprocess:
shell.restart_shell() 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... # XXX Too often this discards arguments the user just set...
interp.runcommand("""if 1: interp.runcommand("""if 1:
_filename = %s _filename = %s
......
...@@ -41,7 +41,6 @@ import copy_reg ...@@ -41,7 +41,6 @@ import copy_reg
import types import types
import marshal import marshal
import interrupt
def unpickle_code(ms): def unpickle_code(ms):
co = marshal.loads(ms) co = marshal.loads(ms)
...@@ -327,12 +326,9 @@ class SocketIO: ...@@ -327,12 +326,9 @@ class SocketIO:
while len(s) > 0: while len(s) > 0:
try: try:
n = self.sock.send(s) n = self.sock.send(s)
except AttributeError: except (AttributeError, socket.error):
# socket was closed # socket was closed
raise IOError raise IOError
except socket.error:
self.debug("putmessage:socketerror:pid:%s" % os.getpid())
os._exit(0)
else: else:
s = s[n:] s = s[n:]
...@@ -471,7 +467,6 @@ class SocketIO: ...@@ -471,7 +467,6 @@ class SocketIO:
self.responses[key] = ('EOF', None) self.responses[key] = ('EOF', None)
cv.notify() cv.notify()
cv.release() cv.release()
interrupt.interrupt_main()
# call our (possibly overridden) exit function # call our (possibly overridden) exit function
self.exithook() self.exithook()
......
...@@ -21,7 +21,8 @@ import __main__ ...@@ -21,7 +21,8 @@ import __main__
# the socket) and the main thread (which runs user code), plus global # the socket) and the main thread (which runs user code), plus global
# completion and exit flags: # completion and exit flags:
exit_requested = False exit_now = False
quitting = False
def main(): def main():
"""Start the Python execution server in a subprocess """Start the Python execution server in a subprocess
...@@ -41,6 +42,8 @@ def main(): ...@@ -41,6 +42,8 @@ def main():
register and unregister themselves. register and unregister themselves.
""" """
global exit_now
global quitting
port = 8833 port = 8833
if sys.argv[1:]: if sys.argv[1:]:
port = int(sys.argv[1]) port = int(sys.argv[1])
...@@ -52,8 +55,12 @@ def main(): ...@@ -52,8 +55,12 @@ def main():
sockthread.start() sockthread.start()
while 1: while 1:
try: try:
if exit_requested: if exit_now:
try:
sys.exit(0) sys.exit(0)
except KeyboardInterrupt:
# exiting but got an extra KBI? Try again!
continue
try: try:
seq, request = rpc.request_queue.get(0) seq, request = rpc.request_queue.get(0)
except Queue.Empty: except Queue.Empty:
...@@ -63,16 +70,21 @@ def main(): ...@@ -63,16 +70,21 @@ def main():
ret = method(*args, **kwargs) ret = method(*args, **kwargs)
rpc.response_queue.put((seq, ret)) rpc.response_queue.put((seq, ret))
except KeyboardInterrupt: except KeyboardInterrupt:
if quitting:
exit_now = True
continue continue
except SystemExit: except SystemExit:
raise raise
except: except:
type, value, tb = sys.exc_info()
try: try:
print_exception() print_exception()
rpc.response_queue.put((seq, None)) rpc.response_queue.put((seq, None))
except: except:
traceback.print_exc(file=sys.__stderr__) # Link didn't work, print same exception to __stderr__
sys.exit(1.1) traceback.print_exception(type, value, tb, file=sys.__stderr__)
sys.exit(0)
else:
continue continue
def manage_socket(address): def manage_socket(address):
...@@ -89,17 +101,17 @@ def manage_socket(address): ...@@ -89,17 +101,17 @@ def manage_socket(address):
+ err[1] + ", retrying...." + err[1] + ", retrying...."
else: else:
print>>sys.__stderr__, "\nConnection to Idle failed, exiting." print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
global exit_requested global exit_now
exit_requested = True exit_now = True
return return
server.handle_request() # A single request only server.handle_request() # A single request only
def print_exception(): def print_exception():
flush_stdout() flush_stdout()
efile = sys.stderr efile = sys.stderr
typ, val, tb = info = sys.exc_info() typ, val, tb = sys.exc_info()
tbe = traceback.extract_tb(tb) 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", exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
"RemoteDebugger.py", "bdb.py") "RemoteDebugger.py", "bdb.py")
cleanup_traceback(tbe, exclude) cleanup_traceback(tbe, exclude)
...@@ -161,8 +173,8 @@ class MyRPCServer(rpc.RPCServer): ...@@ -161,8 +173,8 @@ class MyRPCServer(rpc.RPCServer):
except SystemExit: except SystemExit:
raise raise
except EOFError: except EOFError:
global exit_requested global exit_now
exit_requested = True exit_now = True
interrupt.interrupt_main() interrupt.interrupt_main()
except: except:
erf = sys.__stderr__ erf = sys.__stderr__
...@@ -174,7 +186,7 @@ class MyRPCServer(rpc.RPCServer): ...@@ -174,7 +186,7 @@ class MyRPCServer(rpc.RPCServer):
traceback.print_exc(file=erf) traceback.print_exc(file=erf)
print>>erf, '\n*** Unrecoverable, server exiting!' print>>erf, '\n*** Unrecoverable, server exiting!'
print>>erf, '-'*40 print>>erf, '-'*40
os._exit(0) sys.exit(0)
class MyHandler(rpc.RPCHandler): class MyHandler(rpc.RPCHandler):
...@@ -190,15 +202,18 @@ class MyHandler(rpc.RPCHandler): ...@@ -190,15 +202,18 @@ class MyHandler(rpc.RPCHandler):
def exithook(self): def exithook(self):
"override SocketIO method - wait for MainThread to shut us down" "override SocketIO method - wait for MainThread to shut us down"
while 1: pass time.sleep(10)
def EOFhook(self): def EOFhook(self):
"Override SocketIO method - terminate wait on callback and exit thread" "Override SocketIO method - terminate wait on callback and exit thread"
global exit_requested global quitting
exit_requested = True quitting = True
interrupt.interrupt_main()
def decode_interrupthook(self): def decode_interrupthook(self):
"interrupt awakened thread" "interrupt awakened thread"
global quitting
quitting = True
interrupt.interrupt_main() interrupt.interrupt_main()
...@@ -213,15 +228,10 @@ class Executive: ...@@ -213,15 +228,10 @@ class Executive:
try: try:
exec code in self.locals exec code in self.locals
except: except:
if exit_requested: if quitting:
sys.exit(0) sys.exit(0)
try:
# even print a user code SystemExit exception, continue # even print a user code SystemExit exception, continue
print_exception() print_exception()
except:
# link not working?
traceback.print_exc(file=sys.__stderr__)
sys.exit(1.2)
else: else:
flush_stdout() flush_stdout()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment