Advertisement
Guest User

Untitled

a guest
Jan 25th, 2013
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.38 KB | None | 0 0
  1. import sys
  2. import io
  3. import linecache
  4. import time
  5. import socket
  6. import traceback
  7. import _thread as thread
  8. import threading
  9. import queue
  10. import tkinter
  11.  
  12. from idlelib import CallTips
  13. from idlelib import AutoComplete
  14.  
  15. from idlelib import RemoteDebugger
  16. from idlelib import RemoteObjectBrowser
  17. from idlelib import StackViewer
  18. from idlelib import rpc
  19.  
  20. import __main__
  21.  
  22. LOCALHOST = '127.0.0.1'
  23.  
  24. try:
  25.     import warnings
  26. except ImportError:
  27.     pass
  28. else:
  29.     def idle_formatwarning_subproc(message, category, filename, lineno,
  30.                                    line=None):
  31.         """Format warnings the IDLE way"""
  32.         s = "\nWarning (from warnings module):\n"
  33.         s += '  File \"%s\", line %s\n' % (filename, lineno)
  34.         if line is None:
  35.             line = linecache.getline(filename, lineno)
  36.         line = line.strip()
  37.         if line:
  38.             s += "    %s\n" % line
  39.         s += "%s: %s\n" % (category.__name__, message)
  40.         return s
  41.     warnings.formatwarning = idle_formatwarning_subproc
  42.  
  43.  
  44. tcl = tkinter.Tcl()
  45.  
  46.  
  47. def handle_tk_events(tcl=tcl):
  48.     """Process any tk events that are ready to be dispatched if tkinter
  49.    has been imported, a tcl interpreter has been created and tk has been
  50.    loaded."""
  51.     tcl.eval("update")
  52.  
  53.  
  54. # Thread shared globals: Establish a queue between a subthread (which handles
  55. # the socket) and the main thread (which runs user code), plus global
  56. # completion, exit and interruptable (the main thread) flags:
  57.  
  58. exit_now = False
  59. quitting = False
  60. interruptable = False
  61.  
  62. def main(del_exitfunc=False):
  63.     """Start the Python execution server in a subprocess
  64.  
  65.    In the Python subprocess, RPCServer is instantiated with handlerclass
  66.    MyHandler, which inherits register/unregister methods from RPCHandler via
  67.    the mix-in class SocketIO.
  68.  
  69.    When the RPCServer 'server' is instantiated, the TCPServer initialization
  70.    creates an instance of run.MyHandler and calls its handle() method.
  71.    handle() instantiates a run.Executive object, passing it a reference to the
  72.    MyHandler object.  That reference is saved as attribute rpchandler of the
  73.    Executive instance.  The Executive methods have access to the reference and
  74.    can pass it on to entities that they command
  75.    (e.g. RemoteDebugger.Debugger.start_debugger()).  The latter, in turn, can
  76.    call MyHandler(SocketIO) register/unregister methods via the reference to
  77.    register and unregister themselves.
  78.  
  79.    """
  80.     global exit_now
  81.     global quitting
  82.     global no_exitfunc
  83.     no_exitfunc = del_exitfunc
  84.     #time.sleep(15) # test subprocess not responding
  85.     try:
  86.         assert(len(sys.argv) > 1)
  87.         port = int(sys.argv[-1])
  88.     except:
  89.         print("IDLE Subprocess: no IP port passed in sys.argv.",
  90.               file=sys.__stderr__)
  91.         return
  92.     sys.argv[:] = [""]
  93.     sockthread = threading.Thread(target=manage_socket,
  94.                                   name='SockThread',
  95.                                   args=((LOCALHOST, port),))
  96.     sockthread.daemon = True
  97.     sockthread.start()
  98.     while 1:
  99.         try:
  100.             if exit_now:
  101.                 try:
  102.                     exit()
  103.                 except KeyboardInterrupt:
  104.                     # exiting but got an extra KBI? Try again!
  105.                     continue
  106.             try:
  107.                 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
  108.             except queue.Empty:
  109.                 handle_tk_events()
  110.                 continue
  111.             method, args, kwargs = request
  112.             ret = method(*args, **kwargs)
  113.             rpc.response_queue.put((seq, ret))
  114.         except KeyboardInterrupt:
  115.             if quitting:
  116.                 exit_now = True
  117.             continue
  118.         except SystemExit:
  119.             raise
  120.         except:
  121.             type, value, tb = sys.exc_info()
  122.             try:
  123.                 print_exception()
  124.                 rpc.response_queue.put((seq, None))
  125.             except:
  126.                 # Link didn't work, print same exception to __stderr__
  127.                 traceback.print_exception(type, value, tb, file=sys.__stderr__)
  128.                 exit()
  129.             else:
  130.                 continue
  131.  
  132. def manage_socket(address):
  133.     for i in range(3):
  134.         time.sleep(i)
  135.         try:
  136.             server = MyRPCServer(address, MyHandler)
  137.             break
  138.         except socket.error as err:
  139.             print("IDLE Subprocess: socket error: " + err.args[1] +
  140.                   ", retrying....", file=sys.__stderr__)
  141.             socket_error = err
  142.     else:
  143.         print("IDLE Subprocess: Connection to "
  144.               "IDLE GUI failed, exiting.", file=sys.__stderr__)
  145.         show_socket_error(socket_error, address)
  146.         global exit_now
  147.         exit_now = True
  148.         return
  149.     server.handle_request() # A single request only
  150.  
  151. def show_socket_error(err, address):
  152.     import tkinter
  153.     import tkinter.messagebox as tkMessageBox
  154.     root = tkinter.Tk()
  155.     root.withdraw()
  156.     if err.args[0] == 61: # connection refused
  157.         msg = "IDLE's subprocess can't connect to %s:%d.  This may be due "\
  158.               "to your personal firewall configuration.  It is safe to "\
  159.               "allow this internal connection because no data is visible on "\
  160.               "external ports." % address
  161.         tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
  162.     else:
  163.         tkMessageBox.showerror("IDLE Subprocess Error",
  164.                                "Socket Error: %s" % err.args[1])
  165.     root.destroy()
  166.  
  167. def print_exception():
  168.     import linecache
  169.     linecache.checkcache()
  170.     flush_stdout()
  171.     efile = sys.stderr
  172.     typ, val, tb = excinfo = sys.exc_info()
  173.     sys.last_type, sys.last_value, sys.last_traceback = excinfo
  174.     tbe = traceback.extract_tb(tb)
  175.     print('Traceback (most recent call last):', file=efile)
  176.     exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
  177.                "RemoteDebugger.py", "bdb.py")
  178.     cleanup_traceback(tbe, exclude)
  179.     traceback.print_list(tbe, file=efile)
  180.     lines = traceback.format_exception_only(typ, val)
  181.     for line in lines:
  182.         print(line, end='', file=efile)
  183.  
  184. def cleanup_traceback(tb, exclude):
  185.     "Remove excluded traces from beginning/end of tb; get cached lines"
  186.     orig_tb = tb[:]
  187.     while tb:
  188.         for rpcfile in exclude:
  189.             if tb[0][0].count(rpcfile):
  190.                 break    # found an exclude, break for: and delete tb[0]
  191.         else:
  192.             break        # no excludes, have left RPC code, break while:
  193.         del tb[0]
  194.     while tb:
  195.         for rpcfile in exclude:
  196.             if tb[-1][0].count(rpcfile):
  197.                 break
  198.         else:
  199.             break
  200.         del tb[-1]
  201.     if len(tb) == 0:
  202.         # exception was in IDLE internals, don't prune!
  203.         tb[:] = orig_tb[:]
  204.         print("** IDLE Internal Exception: ", file=sys.stderr)
  205.     rpchandler = rpc.objecttable['exec'].rpchandler
  206.     for i in range(len(tb)):
  207.         fn, ln, nm, line = tb[i]
  208.         if nm == '?':
  209.             nm = "-toplevel-"
  210.         if not line and fn.startswith("<pyshell#"):
  211.             line = rpchandler.remotecall('linecache', 'getline',
  212.                                               (fn, ln), {})
  213.         tb[i] = fn, ln, nm, line
  214.  
  215. def flush_stdout():
  216.     """XXX How to do this now?"""
  217.  
  218. def exit():
  219.     """Exit subprocess, possibly after first clearing exit functions.
  220.  
  221.    If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
  222.    functions registered with atexit will be removed before exiting.
  223.    (VPython support)
  224.  
  225.    """
  226.     if no_exitfunc:
  227.         import atexit
  228.         atexit._clear()
  229.     sys.exit(0)
  230.  
  231. class MyRPCServer(rpc.RPCServer):
  232.  
  233.     def handle_error(self, request, client_address):
  234.         """Override RPCServer method for IDLE
  235.  
  236.        Interrupt the MainThread and exit server if link is dropped.
  237.  
  238.        """
  239.         global quitting
  240.         try:
  241.             raise
  242.         except SystemExit:
  243.             raise
  244.         except EOFError:
  245.             global exit_now
  246.             exit_now = True
  247.             thread.interrupt_main()
  248.         except:
  249.             erf = sys.__stderr__
  250.             print('\n' + '-'*40, file=erf)
  251.             print('Unhandled server exception!', file=erf)
  252.             print('Thread: %s' % threading.current_thread().name, file=erf)
  253.             print('Client Address: ', client_address, file=erf)
  254.             print('Request: ', repr(request), file=erf)
  255.             traceback.print_exc(file=erf)
  256.             print('\n*** Unrecoverable, server exiting!', file=erf)
  257.             print('-'*40, file=erf)
  258.             quitting = True
  259.             thread.interrupt_main()
  260.  
  261. class _RPCFile(io.TextIOBase):
  262.     """Wrapper class for the RPC proxy to typecheck arguments
  263.    that may not support pickling. The base class is there only
  264.    to support type tests; all implementations come from the remote
  265.    object."""
  266.  
  267.     def __init__(self, rpc):
  268.         super.__setattr__(self, 'rpc', rpc)
  269.  
  270.     def __getattribute__(self, name):
  271.         # When accessing the 'rpc' attribute, or 'write', use ours
  272.         if name in ('rpc', 'write', 'writelines'):
  273.             return io.TextIOBase.__getattribute__(self, name)
  274.         # Else only look into the remote object only
  275.         return getattr(self.rpc, name)
  276.  
  277.     def __setattr__(self, name, value):
  278.         return setattr(self.rpc, name, value)
  279.  
  280.     @staticmethod
  281.     def _ensure_string(func):
  282.         def f(self, s):
  283.             if not isinstance(s, str):
  284.                 raise TypeError('must be str, not ' + type(s).__name__)
  285.             return func(self, s)
  286.         return f
  287.  
  288. class _RPCOutputFile(_RPCFile):
  289.     @_RPCFile._ensure_string
  290.     def write(self, s):
  291.         if not isinstance(s, str):
  292.             raise TypeError('must be str, not ' + type(s).__name__)
  293.         return self.rpc.write(s)
  294.  
  295. class _RPCInputFile(_RPCFile):
  296.     @_RPCFile._ensure_string
  297.     def write(self, s):
  298.         raise io.UnsupportedOperation("not writable")
  299.     writelines = write
  300.  
  301. class MyHandler(rpc.RPCHandler):
  302.  
  303.     def handle(self):
  304.         """Override base method"""
  305.         executive = Executive(self)
  306.         self.register("exec", executive)
  307.         self.console = self.get_remote_proxy("stdin")
  308.         sys.stdin = _RPCInputFile(self.console)
  309.         sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout"))
  310.         sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr"))
  311.         sys.displayhook = rpc.displayhook
  312.         # page help() text to shell.
  313.         import pydoc # import must be done here to capture i/o binding
  314.         pydoc.pager = pydoc.plainpager
  315.         from idlelib import IOBinding
  316.         sys.stdin.encoding = sys.stdout.encoding = \
  317.                              sys.stderr.encoding = IOBinding.encoding
  318.         self.interp = self.get_remote_proxy("interp")
  319.         rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
  320.  
  321.     def exithook(self):
  322.         "override SocketIO method - wait for MainThread to shut us down"
  323.         time.sleep(10)
  324.  
  325.     def EOFhook(self):
  326.         "Override SocketIO method - terminate wait on callback and exit thread"
  327.         global quitting
  328.         quitting = True
  329.         thread.interrupt_main()
  330.  
  331.     def decode_interrupthook(self):
  332.         "interrupt awakened thread"
  333.         global quitting
  334.         quitting = True
  335.         thread.interrupt_main()
  336.  
  337.  
  338. class Executive(object):
  339.  
  340.     def __init__(self, rpchandler):
  341.         self.rpchandler = rpchandler
  342.         self.locals = __main__.__dict__
  343.         self.calltip = CallTips.CallTips()
  344.         self.autocomplete = AutoComplete.AutoComplete()
  345.  
  346.     def runcode(self, code):
  347.         global interruptable
  348.         try:
  349.             self.usr_exc_info = None
  350.             interruptable = True
  351.             try:
  352.                 exec(code, self.locals)
  353.             finally:
  354.                 interruptable = False
  355.         except:
  356.             self.usr_exc_info = sys.exc_info()
  357.             if quitting:
  358.                 exit()
  359.             # even print a user code SystemExit exception, continue
  360.             print_exception()
  361.             jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
  362.             if jit:
  363.                 self.rpchandler.interp.open_remote_stack_viewer()
  364.         else:
  365.             flush_stdout()
  366.  
  367.     def interrupt_the_server(self):
  368.         if interruptable:
  369.             thread.interrupt_main()
  370.  
  371.     def start_the_debugger(self, gui_adap_oid):
  372.         return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
  373.  
  374.     def stop_the_debugger(self, idb_adap_oid):
  375.         "Unregister the Idb Adapter.  Link objects and Idb then subject to GC"
  376.         self.rpchandler.unregister(idb_adap_oid)
  377.  
  378.     def get_the_calltip(self, name):
  379.         return self.calltip.fetch_tip(name)
  380.  
  381.     def get_the_completion_list(self, what, mode):
  382.         return self.autocomplete.fetch_completions(what, mode)
  383.  
  384.     def stackviewer(self, flist_oid=None):
  385.         if self.usr_exc_info:
  386.             typ, val, tb = self.usr_exc_info
  387.         else:
  388.             return None
  389.         flist = None
  390.         if flist_oid is not None:
  391.             flist = self.rpchandler.get_remote_proxy(flist_oid)
  392.         while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
  393.             tb = tb.tb_next
  394.         sys.last_type = typ
  395.         sys.last_value = val
  396.         item = StackViewer.StackTreeItem(flist, tb)
  397.         return RemoteObjectBrowser.remote_object_tree_item(item)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement