python-2.5.2/win32/Lib/idlelib/run.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 import sys
       
     2 import os
       
     3 import linecache
       
     4 import time
       
     5 import socket
       
     6 import traceback
       
     7 import thread
       
     8 import threading
       
     9 import Queue
       
    10 
       
    11 import CallTips
       
    12 import AutoComplete
       
    13 
       
    14 import RemoteDebugger
       
    15 import RemoteObjectBrowser
       
    16 import StackViewer
       
    17 import rpc
       
    18 
       
    19 import __main__
       
    20 
       
    21 LOCALHOST = '127.0.0.1'
       
    22 
       
    23 try:
       
    24     import warnings
       
    25 except ImportError:
       
    26     pass
       
    27 else:
       
    28     def idle_formatwarning_subproc(message, category, filename, lineno):
       
    29         """Format warnings the IDLE way"""
       
    30         s = "\nWarning (from warnings module):\n"
       
    31         s += '  File \"%s\", line %s\n' % (filename, lineno)
       
    32         line = linecache.getline(filename, lineno).strip()
       
    33         if line:
       
    34             s += "    %s\n" % line
       
    35         s += "%s: %s\n" % (category.__name__, message)
       
    36         return s
       
    37     warnings.formatwarning = idle_formatwarning_subproc
       
    38 
       
    39 # Thread shared globals: Establish a queue between a subthread (which handles
       
    40 # the socket) and the main thread (which runs user code), plus global
       
    41 # completion and exit flags:
       
    42 
       
    43 exit_now = False
       
    44 quitting = False
       
    45 
       
    46 def main(del_exitfunc=False):
       
    47     """Start the Python execution server in a subprocess
       
    48 
       
    49     In the Python subprocess, RPCServer is instantiated with handlerclass
       
    50     MyHandler, which inherits register/unregister methods from RPCHandler via
       
    51     the mix-in class SocketIO.
       
    52 
       
    53     When the RPCServer 'server' is instantiated, the TCPServer initialization
       
    54     creates an instance of run.MyHandler and calls its handle() method.
       
    55     handle() instantiates a run.Executive object, passing it a reference to the
       
    56     MyHandler object.  That reference is saved as attribute rpchandler of the
       
    57     Executive instance.  The Executive methods have access to the reference and
       
    58     can pass it on to entities that they command
       
    59     (e.g. RemoteDebugger.Debugger.start_debugger()).  The latter, in turn, can
       
    60     call MyHandler(SocketIO) register/unregister methods via the reference to
       
    61     register and unregister themselves.
       
    62 
       
    63     """
       
    64     global exit_now
       
    65     global quitting
       
    66     global no_exitfunc
       
    67     no_exitfunc = del_exitfunc
       
    68     port = 8833
       
    69     #time.sleep(15) # test subprocess not responding
       
    70     if sys.argv[1:]:
       
    71         port = int(sys.argv[1])
       
    72     sys.argv[:] = [""]
       
    73     sockthread = threading.Thread(target=manage_socket,
       
    74                                   name='SockThread',
       
    75                                   args=((LOCALHOST, port),))
       
    76     sockthread.setDaemon(True)
       
    77     sockthread.start()
       
    78     while 1:
       
    79         try:
       
    80             if exit_now:
       
    81                 try:
       
    82                     exit()
       
    83                 except KeyboardInterrupt:
       
    84                     # exiting but got an extra KBI? Try again!
       
    85                     continue
       
    86             try:
       
    87                 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
       
    88             except Queue.Empty:
       
    89                 continue
       
    90             method, args, kwargs = request
       
    91             ret = method(*args, **kwargs)
       
    92             rpc.response_queue.put((seq, ret))
       
    93         except KeyboardInterrupt:
       
    94             if quitting:
       
    95                 exit_now = True
       
    96             continue
       
    97         except SystemExit:
       
    98             raise
       
    99         except:
       
   100             type, value, tb = sys.exc_info()
       
   101             try:
       
   102                 print_exception()
       
   103                 rpc.response_queue.put((seq, None))
       
   104             except:
       
   105                 # Link didn't work, print same exception to __stderr__
       
   106                 traceback.print_exception(type, value, tb, file=sys.__stderr__)
       
   107                 exit()
       
   108             else:
       
   109                 continue
       
   110 
       
   111 def manage_socket(address):
       
   112     for i in range(3):
       
   113         time.sleep(i)
       
   114         try:
       
   115             server = MyRPCServer(address, MyHandler)
       
   116             break
       
   117         except socket.error, err:
       
   118             print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
       
   119                                         + err[1] + ", retrying...."
       
   120     else:
       
   121         print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
       
   122                                "IDLE GUI failed, exiting."
       
   123         show_socket_error(err, address)
       
   124         global exit_now
       
   125         exit_now = True
       
   126         return
       
   127     server.handle_request() # A single request only
       
   128 
       
   129 def show_socket_error(err, address):
       
   130     import Tkinter
       
   131     import tkMessageBox
       
   132     root = Tkinter.Tk()
       
   133     root.withdraw()
       
   134     if err[0] == 61: # connection refused
       
   135         msg = "IDLE's subprocess can't connect to %s:%d.  This may be due "\
       
   136               "to your personal firewall configuration.  It is safe to "\
       
   137               "allow this internal connection because no data is visible on "\
       
   138               "external ports." % address
       
   139         tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
       
   140     else:
       
   141         tkMessageBox.showerror("IDLE Subprocess Error", "Socket Error: %s" % err[1])
       
   142     root.destroy()
       
   143 
       
   144 def print_exception():
       
   145     import linecache
       
   146     linecache.checkcache()
       
   147     flush_stdout()
       
   148     efile = sys.stderr
       
   149     typ, val, tb = excinfo = sys.exc_info()
       
   150     sys.last_type, sys.last_value, sys.last_traceback = excinfo
       
   151     tbe = traceback.extract_tb(tb)
       
   152     print>>efile, '\nTraceback (most recent call last):'
       
   153     exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
       
   154                "RemoteDebugger.py", "bdb.py")
       
   155     cleanup_traceback(tbe, exclude)
       
   156     traceback.print_list(tbe, file=efile)
       
   157     lines = traceback.format_exception_only(typ, val)
       
   158     for line in lines:
       
   159         print>>efile, line,
       
   160 
       
   161 def cleanup_traceback(tb, exclude):
       
   162     "Remove excluded traces from beginning/end of tb; get cached lines"
       
   163     orig_tb = tb[:]
       
   164     while tb:
       
   165         for rpcfile in exclude:
       
   166             if tb[0][0].count(rpcfile):
       
   167                 break    # found an exclude, break for: and delete tb[0]
       
   168         else:
       
   169             break        # no excludes, have left RPC code, break while:
       
   170         del tb[0]
       
   171     while tb:
       
   172         for rpcfile in exclude:
       
   173             if tb[-1][0].count(rpcfile):
       
   174                 break
       
   175         else:
       
   176             break
       
   177         del tb[-1]
       
   178     if len(tb) == 0:
       
   179         # exception was in IDLE internals, don't prune!
       
   180         tb[:] = orig_tb[:]
       
   181         print>>sys.stderr, "** IDLE Internal Exception: "
       
   182     rpchandler = rpc.objecttable['exec'].rpchandler
       
   183     for i in range(len(tb)):
       
   184         fn, ln, nm, line = tb[i]
       
   185         if nm == '?':
       
   186             nm = "-toplevel-"
       
   187         if not line and fn.startswith("<pyshell#"):
       
   188             line = rpchandler.remotecall('linecache', 'getline',
       
   189                                               (fn, ln), {})
       
   190         tb[i] = fn, ln, nm, line
       
   191 
       
   192 def flush_stdout():
       
   193     try:
       
   194         if sys.stdout.softspace:
       
   195             sys.stdout.softspace = 0
       
   196             sys.stdout.write("\n")
       
   197     except (AttributeError, EOFError):
       
   198         pass
       
   199 
       
   200 def exit():
       
   201     """Exit subprocess, possibly after first deleting sys.exitfunc
       
   202 
       
   203     If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
       
   204     sys.exitfunc will be removed before exiting.  (VPython support)
       
   205 
       
   206     """
       
   207     if no_exitfunc:
       
   208         try:
       
   209             del sys.exitfunc
       
   210         except AttributeError:
       
   211             pass
       
   212     sys.exit(0)
       
   213 
       
   214 class MyRPCServer(rpc.RPCServer):
       
   215 
       
   216     def handle_error(self, request, client_address):
       
   217         """Override RPCServer method for IDLE
       
   218 
       
   219         Interrupt the MainThread and exit server if link is dropped.
       
   220 
       
   221         """
       
   222         global quitting
       
   223         try:
       
   224             raise
       
   225         except SystemExit:
       
   226             raise
       
   227         except EOFError:
       
   228             global exit_now
       
   229             exit_now = True
       
   230             thread.interrupt_main()
       
   231         except:
       
   232             erf = sys.__stderr__
       
   233             print>>erf, '\n' + '-'*40
       
   234             print>>erf, 'Unhandled server exception!'
       
   235             print>>erf, 'Thread: %s' % threading.currentThread().getName()
       
   236             print>>erf, 'Client Address: ', client_address
       
   237             print>>erf, 'Request: ', repr(request)
       
   238             traceback.print_exc(file=erf)
       
   239             print>>erf, '\n*** Unrecoverable, server exiting!'
       
   240             print>>erf, '-'*40
       
   241             quitting = True
       
   242             thread.interrupt_main()
       
   243 
       
   244 
       
   245 class MyHandler(rpc.RPCHandler):
       
   246 
       
   247     def handle(self):
       
   248         """Override base method"""
       
   249         executive = Executive(self)
       
   250         self.register("exec", executive)
       
   251         sys.stdin = self.console = self.get_remote_proxy("stdin")
       
   252         sys.stdout = self.get_remote_proxy("stdout")
       
   253         sys.stderr = self.get_remote_proxy("stderr")
       
   254         import IOBinding
       
   255         sys.stdin.encoding = sys.stdout.encoding = \
       
   256                              sys.stderr.encoding = IOBinding.encoding
       
   257         self.interp = self.get_remote_proxy("interp")
       
   258         rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
       
   259 
       
   260     def exithook(self):
       
   261         "override SocketIO method - wait for MainThread to shut us down"
       
   262         time.sleep(10)
       
   263 
       
   264     def EOFhook(self):
       
   265         "Override SocketIO method - terminate wait on callback and exit thread"
       
   266         global quitting
       
   267         quitting = True
       
   268         thread.interrupt_main()
       
   269 
       
   270     def decode_interrupthook(self):
       
   271         "interrupt awakened thread"
       
   272         global quitting
       
   273         quitting = True
       
   274         thread.interrupt_main()
       
   275 
       
   276 
       
   277 class Executive(object):
       
   278 
       
   279     def __init__(self, rpchandler):
       
   280         self.rpchandler = rpchandler
       
   281         self.locals = __main__.__dict__
       
   282         self.calltip = CallTips.CallTips()
       
   283         self.autocomplete = AutoComplete.AutoComplete()
       
   284 
       
   285     def runcode(self, code):
       
   286         try:
       
   287             self.usr_exc_info = None
       
   288             exec code in self.locals
       
   289         except:
       
   290             self.usr_exc_info = sys.exc_info()
       
   291             if quitting:
       
   292                 exit()
       
   293             # even print a user code SystemExit exception, continue
       
   294             print_exception()
       
   295             jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
       
   296             if jit:
       
   297                 self.rpchandler.interp.open_remote_stack_viewer()
       
   298         else:
       
   299             flush_stdout()
       
   300 
       
   301     def interrupt_the_server(self):
       
   302         thread.interrupt_main()
       
   303 
       
   304     def start_the_debugger(self, gui_adap_oid):
       
   305         return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
       
   306 
       
   307     def stop_the_debugger(self, idb_adap_oid):
       
   308         "Unregister the Idb Adapter.  Link objects and Idb then subject to GC"
       
   309         self.rpchandler.unregister(idb_adap_oid)
       
   310 
       
   311     def get_the_calltip(self, name):
       
   312         return self.calltip.fetch_tip(name)
       
   313 
       
   314     def get_the_completion_list(self, what, mode):
       
   315         return self.autocomplete.fetch_completions(what, mode)
       
   316 
       
   317     def stackviewer(self, flist_oid=None):
       
   318         if self.usr_exc_info:
       
   319             typ, val, tb = self.usr_exc_info
       
   320         else:
       
   321             return None
       
   322         flist = None
       
   323         if flist_oid is not None:
       
   324             flist = self.rpchandler.get_remote_proxy(flist_oid)
       
   325         while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
       
   326             tb = tb.tb_next
       
   327         sys.last_type = typ
       
   328         sys.last_value = val
       
   329         item = StackViewer.StackTreeItem(flist, tb)
       
   330         return RemoteObjectBrowser.remote_object_tree_item(item)