summaryrefslogtreecommitdiff
path: root/lib/python2.7/idlelib/run.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/idlelib/run.py')
-rw-r--r--lib/python2.7/idlelib/run.py354
1 files changed, 354 insertions, 0 deletions
diff --git a/lib/python2.7/idlelib/run.py b/lib/python2.7/idlelib/run.py
new file mode 100644
index 0000000..9cc009f
--- /dev/null
+++ b/lib/python2.7/idlelib/run.py
@@ -0,0 +1,354 @@
+import sys
+import io
+import linecache
+import time
+import socket
+import traceback
+import thread
+import threading
+import Queue
+
+from idlelib import CallTips
+from idlelib import AutoComplete
+
+from idlelib import RemoteDebugger
+from idlelib import RemoteObjectBrowser
+from idlelib import StackViewer
+from idlelib import rpc
+from idlelib import PyShell
+from idlelib import IOBinding
+
+import __main__
+
+LOCALHOST = '127.0.0.1'
+
+try:
+ import warnings
+except ImportError:
+ pass
+else:
+ def idle_formatwarning_subproc(message, category, filename, lineno,
+ line=None):
+ """Format warnings the IDLE way"""
+ s = "\nWarning (from warnings module):\n"
+ s += ' File \"%s\", line %s\n' % (filename, lineno)
+ if line is None:
+ line = linecache.getline(filename, lineno)
+ line = line.strip()
+ if line:
+ s += " %s\n" % line
+ s += "%s: %s\n" % (category.__name__, message)
+ return s
+ warnings.formatwarning = idle_formatwarning_subproc
+
+# Thread shared globals: Establish a queue between a subthread (which handles
+# the socket) and the main thread (which runs user code), plus global
+# completion, exit and interruptable (the main thread) flags:
+
+exit_now = False
+quitting = False
+interruptable = False
+
+def main(del_exitfunc=False):
+ """Start the Python execution server in a subprocess
+
+ In the Python subprocess, RPCServer is instantiated with handlerclass
+ MyHandler, which inherits register/unregister methods from RPCHandler via
+ the mix-in class SocketIO.
+
+ When the RPCServer 'server' is instantiated, the TCPServer initialization
+ creates an instance of run.MyHandler and calls its handle() method.
+ handle() instantiates a run.Executive object, passing it a reference to the
+ MyHandler object. That reference is saved as attribute rpchandler of the
+ Executive instance. The Executive methods have access to the reference and
+ can pass it on to entities that they command
+ (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
+ call MyHandler(SocketIO) register/unregister methods via the reference to
+ register and unregister themselves.
+
+ """
+ global exit_now
+ global quitting
+ global no_exitfunc
+ no_exitfunc = del_exitfunc
+ #time.sleep(15) # test subprocess not responding
+ try:
+ assert(len(sys.argv) > 1)
+ port = int(sys.argv[-1])
+ except:
+ print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
+ return
+ sys.argv[:] = [""]
+ sockthread = threading.Thread(target=manage_socket,
+ name='SockThread',
+ args=((LOCALHOST, port),))
+ sockthread.setDaemon(True)
+ sockthread.start()
+ while 1:
+ try:
+ if exit_now:
+ try:
+ exit()
+ except KeyboardInterrupt:
+ # exiting but got an extra KBI? Try again!
+ continue
+ try:
+ seq, request = rpc.request_queue.get(block=True, timeout=0.05)
+ except Queue.Empty:
+ continue
+ method, args, kwargs = request
+ 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:
+ # Link didn't work, print same exception to __stderr__
+ traceback.print_exception(type, value, tb, file=sys.__stderr__)
+ exit()
+ else:
+ continue
+
+def manage_socket(address):
+ for i in range(3):
+ time.sleep(i)
+ try:
+ server = MyRPCServer(address, MyHandler)
+ break
+ except socket.error, err:
+ print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
+ + err.args[1] + ", retrying...."
+ else:
+ print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
+ "IDLE GUI failed, exiting."
+ show_socket_error(err, address)
+ global exit_now
+ exit_now = True
+ return
+ server.handle_request() # A single request only
+
+def show_socket_error(err, address):
+ import Tkinter
+ import tkMessageBox
+ root = Tkinter.Tk()
+ root.withdraw()
+ if err.args[0] == 61: # connection refused
+ msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
+ "to your personal firewall configuration. It is safe to "\
+ "allow this internal connection because no data is visible on "\
+ "external ports." % address
+ tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
+ else:
+ tkMessageBox.showerror("IDLE Subprocess Error",
+ "Socket Error: %s" % err.args[1])
+ root.destroy()
+
+def print_exception():
+ import linecache
+ linecache.checkcache()
+ flush_stdout()
+ efile = sys.stderr
+ typ, val, tb = excinfo = sys.exc_info()
+ sys.last_type, sys.last_value, sys.last_traceback = excinfo
+ tbe = traceback.extract_tb(tb)
+ print>>efile, '\nTraceback (most recent call last):'
+ exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
+ "RemoteDebugger.py", "bdb.py")
+ cleanup_traceback(tbe, exclude)
+ traceback.print_list(tbe, file=efile)
+ lines = traceback.format_exception_only(typ, val)
+ for line in lines:
+ print>>efile, line,
+
+def cleanup_traceback(tb, exclude):
+ "Remove excluded traces from beginning/end of tb; get cached lines"
+ orig_tb = tb[:]
+ while tb:
+ for rpcfile in exclude:
+ if tb[0][0].count(rpcfile):
+ break # found an exclude, break for: and delete tb[0]
+ else:
+ break # no excludes, have left RPC code, break while:
+ del tb[0]
+ while tb:
+ for rpcfile in exclude:
+ if tb[-1][0].count(rpcfile):
+ break
+ else:
+ break
+ del tb[-1]
+ if len(tb) == 0:
+ # exception was in IDLE internals, don't prune!
+ tb[:] = orig_tb[:]
+ print>>sys.stderr, "** IDLE Internal Exception: "
+ rpchandler = rpc.objecttable['exec'].rpchandler
+ for i in range(len(tb)):
+ fn, ln, nm, line = tb[i]
+ if nm == '?':
+ nm = "-toplevel-"
+ if not line and fn.startswith("<pyshell#"):
+ line = rpchandler.remotecall('linecache', 'getline',
+ (fn, ln), {})
+ tb[i] = fn, ln, nm, line
+
+def flush_stdout():
+ try:
+ if sys.stdout.softspace:
+ sys.stdout.softspace = 0
+ sys.stdout.write("\n")
+ except (AttributeError, EOFError):
+ pass
+
+def exit():
+ """Exit subprocess, possibly after first deleting sys.exitfunc
+
+ If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
+ sys.exitfunc will be removed before exiting. (VPython support)
+
+ """
+ if no_exitfunc:
+ try:
+ del sys.exitfunc
+ except AttributeError:
+ pass
+ sys.exit(0)
+
+class MyRPCServer(rpc.RPCServer):
+
+ def handle_error(self, request, client_address):
+ """Override RPCServer method for IDLE
+
+ Interrupt the MainThread and exit server if link is dropped.
+
+ """
+ global quitting
+ try:
+ raise
+ except SystemExit:
+ raise
+ except EOFError:
+ global exit_now
+ exit_now = True
+ thread.interrupt_main()
+ except:
+ erf = sys.__stderr__
+ print>>erf, '\n' + '-'*40
+ print>>erf, 'Unhandled server exception!'
+ print>>erf, 'Thread: %s' % threading.currentThread().getName()
+ print>>erf, 'Client Address: ', client_address
+ print>>erf, 'Request: ', repr(request)
+ traceback.print_exc(file=erf)
+ print>>erf, '\n*** Unrecoverable, server exiting!'
+ print>>erf, '-'*40
+ quitting = True
+ thread.interrupt_main()
+
+class MyHandler(rpc.RPCHandler):
+
+ def handle(self):
+ """Override base method"""
+ executive = Executive(self)
+ self.register("exec", executive)
+ self.console = self.get_remote_proxy("console")
+ sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
+ IOBinding.encoding)
+ sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
+ IOBinding.encoding)
+ sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
+ IOBinding.encoding)
+
+ # Keep a reference to stdin so that it won't try to exit IDLE if
+ # sys.stdin gets changed from within IDLE's shell. See issue17838.
+ self._keep_stdin = sys.stdin
+
+ self.interp = self.get_remote_proxy("interp")
+ rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
+
+ def exithook(self):
+ "override SocketIO method - wait for MainThread to shut us down"
+ time.sleep(10)
+
+ def EOFhook(self):
+ "Override SocketIO method - terminate wait on callback and exit thread"
+ global quitting
+ quitting = True
+ thread.interrupt_main()
+
+ def decode_interrupthook(self):
+ "interrupt awakened thread"
+ global quitting
+ quitting = True
+ thread.interrupt_main()
+
+
+class Executive(object):
+
+ def __init__(self, rpchandler):
+ self.rpchandler = rpchandler
+ self.locals = __main__.__dict__
+ self.calltip = CallTips.CallTips()
+ self.autocomplete = AutoComplete.AutoComplete()
+
+ def runcode(self, code):
+ global interruptable
+ try:
+ self.usr_exc_info = None
+ interruptable = True
+ try:
+ exec code in self.locals
+ finally:
+ interruptable = False
+ except SystemExit:
+ # Scripts that raise SystemExit should just
+ # return to the interactive prompt
+ pass
+ except:
+ self.usr_exc_info = sys.exc_info()
+ if quitting:
+ exit()
+ print_exception()
+ jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
+ if jit:
+ self.rpchandler.interp.open_remote_stack_viewer()
+ else:
+ flush_stdout()
+
+ def interrupt_the_server(self):
+ if interruptable:
+ thread.interrupt_main()
+
+ def start_the_debugger(self, gui_adap_oid):
+ return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
+
+ def stop_the_debugger(self, idb_adap_oid):
+ "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
+ self.rpchandler.unregister(idb_adap_oid)
+
+ def get_the_calltip(self, name):
+ return self.calltip.fetch_tip(name)
+
+ def get_the_completion_list(self, what, mode):
+ return self.autocomplete.fetch_completions(what, mode)
+
+ def stackviewer(self, flist_oid=None):
+ if self.usr_exc_info:
+ typ, val, tb = self.usr_exc_info
+ else:
+ return None
+ flist = None
+ if flist_oid is not None:
+ flist = self.rpchandler.get_remote_proxy(flist_oid)
+ while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
+ tb = tb.tb_next
+ sys.last_type = typ
+ sys.last_value = val
+ item = StackViewer.StackTreeItem(flist, tb)
+ return RemoteObjectBrowser.remote_object_tree_item(item)