| import sys | 
 | import linecache | 
 | import time | 
 | import socket | 
 | import traceback | 
 | import thread | 
 | import threading | 
 | import Queue | 
 |  | 
 | import CallTips | 
 | import AutoComplete | 
 |  | 
 | import RemoteDebugger | 
 | import RemoteObjectBrowser | 
 | import StackViewer | 
 | import rpc | 
 |  | 
 | import __main__ | 
 |  | 
 | LOCALHOST = '127.0.0.1' | 
 |  | 
 | try: | 
 |     import warnings | 
 | except ImportError: | 
 |     pass | 
 | else: | 
 |     def idle_formatwarning_subproc(message, category, filename, lineno, | 
 |                                    file=None, line=None): | 
 |         """Format warnings the IDLE way""" | 
 |         s = "\nWarning (from warnings module):\n" | 
 |         s += '  File \"%s\", line %s\n' % (filename, lineno) | 
 |         line = linecache.getline(filename, lineno).strip() \ | 
 |             if line is None else line | 
 |         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 | 
 |     port = 8833 | 
 |     #time.sleep(15) # test subprocess not responding | 
 |     if sys.argv[1:]: | 
 |         port = int(sys.argv[1]) | 
 |     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[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[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[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) | 
 |         sys.stdin = self.console = self.get_remote_proxy("stdin") | 
 |         sys.stdout = self.get_remote_proxy("stdout") | 
 |         sys.stderr = self.get_remote_proxy("stderr") | 
 |         import IOBinding | 
 |         sys.stdin.encoding = sys.stdout.encoding = \ | 
 |                              sys.stderr.encoding = IOBinding.encoding | 
 |         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: | 
 |             self.usr_exc_info = sys.exc_info() | 
 |             if quitting: | 
 |                 exit() | 
 |             # even print a user code SystemExit exception, continue | 
 |             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) |