0001 import sys 0002 import os 0003 import linecache 0004 import time 0005 import socket 0006 import traceback 0007 import thread 0008 import threading 0009 import Queue 0010 0011 import CallTips 0012 import RemoteDebugger 0013 import RemoteObjectBrowser 0014 import StackViewer 0015 import rpc 0016 0017 import __main__ 0018 0019 LOCALHOST = '127.0.0.1' 0020 0021 try: 0022 import warnings 0023 except ImportError: 0024 pass 0025 else: 0026 def idle_formatwarning_subproc(message, category, filename, lineno): 0027 """Format warnings the IDLE way""" 0028 s = "\nWarning (from warnings module):\n" 0029 s += ' File \"%s\", line %s\n' % (filename, lineno) 0030 line = linecache.getline(filename, lineno).strip() 0031 if line: 0032 s += " %s\n" % line 0033 s += "%s: %s\n" % (category.__name__, message) 0034 return s 0035 warnings.formatwarning = idle_formatwarning_subproc 0036 0037 # Thread shared globals: Establish a queue between a subthread (which handles 0038 # the socket) and the main thread (which runs user code), plus global 0039 # completion and exit flags: 0040 0041 exit_now = False 0042 quitting = False 0043 0044 def main(del_exitfunc=False): 0045 """Start the Python execution server in a subprocess 0046 0047 In the Python subprocess, RPCServer is instantiated with handlerclass 0048 MyHandler, which inherits register/unregister methods from RPCHandler via 0049 the mix-in class SocketIO. 0050 0051 When the RPCServer 'server' is instantiated, the TCPServer initialization 0052 creates an instance of run.MyHandler and calls its handle() method. 0053 handle() instantiates a run.Executive object, passing it a reference to the 0054 MyHandler object. That reference is saved as attribute rpchandler of the 0055 Executive instance. The Executive methods have access to the reference and 0056 can pass it on to entities that they command 0057 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can 0058 call MyHandler(SocketIO) register/unregister methods via the reference to 0059 register and unregister themselves. 0060 0061 """ 0062 global exit_now 0063 global quitting 0064 global no_exitfunc 0065 no_exitfunc = del_exitfunc 0066 port = 8833 0067 #time.sleep(15) # test subprocess not responding 0068 if sys.argv[1:]: 0069 port = int(sys.argv[1]) 0070 sys.argv[:] = [""] 0071 sockthread = threading.Thread(target=manage_socket, 0072 name='SockThread', 0073 args=((LOCALHOST, port),)) 0074 sockthread.setDaemon(True) 0075 sockthread.start() 0076 while 1: 0077 try: 0078 if exit_now: 0079 try: 0080 exit() 0081 except KeyboardInterrupt: 0082 # exiting but got an extra KBI? Try again! 0083 continue 0084 try: 0085 seq, request = rpc.request_queue.get(0) 0086 except Queue.Empty: 0087 time.sleep(0.05) 0088 continue 0089 method, args, kwargs = request 0090 ret = method(*args, **kwargs) 0091 rpc.response_queue.put((seq, ret)) 0092 except KeyboardInterrupt: 0093 if quitting: 0094 exit_now = True 0095 continue 0096 except SystemExit: 0097 raise 0098 except: 0099 type, value, tb = sys.exc_info() 0100 try: 0101 print_exception() 0102 rpc.response_queue.put((seq, None)) 0103 except: 0104 # Link didn't work, print same exception to __stderr__ 0105 traceback.print_exception(type, value, tb, file=sys.__stderr__) 0106 exit() 0107 else: 0108 continue 0109 0110 def manage_socket(address): 0111 for i in range(3): 0112 time.sleep(i) 0113 try: 0114 server = MyRPCServer(address, MyHandler) 0115 break 0116 except socket.error, err: 0117 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\ 0118 + err[1] + ", retrying...." 0119 else: 0120 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\ 0121 "IDLE GUI failed, exiting." 0122 show_socket_error(err, address) 0123 global exit_now 0124 exit_now = True 0125 return 0126 server.handle_request() # A single request only 0127 0128 def show_socket_error(err, address): 0129 import Tkinter 0130 import tkMessageBox 0131 root = Tkinter.Tk() 0132 root.withdraw() 0133 if err[0] == 61: # connection refused 0134 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\ 0135 "to your personal firewall configuration. It is safe to "\ 0136 "allow this internal connection because no data is visible on "\ 0137 "external ports." % address 0138 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root) 0139 else: 0140 tkMessageBox.showerror("IDLE Subprocess Error", "Socket Error: %s" % err[1]) 0141 root.destroy() 0142 0143 def print_exception(): 0144 import linecache 0145 linecache.checkcache() 0146 flush_stdout() 0147 efile = sys.stderr 0148 typ, val, tb = excinfo = sys.exc_info() 0149 sys.last_type, sys.last_value, sys.last_traceback = excinfo 0150 tbe = traceback.extract_tb(tb) 0151 print>>efile, '\nTraceback (most recent call last):' 0152 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py", 0153 "RemoteDebugger.py", "bdb.py") 0154 cleanup_traceback(tbe, exclude) 0155 traceback.print_list(tbe, file=efile) 0156 lines = traceback.format_exception_only(typ, val) 0157 for line in lines: 0158 print>>efile, line, 0159 0160 def cleanup_traceback(tb, exclude): 0161 "Remove excluded traces from beginning/end of tb; get cached lines" 0162 orig_tb = tb[:] 0163 while tb: 0164 for rpcfile in exclude: 0165 if tb[0][0].count(rpcfile): 0166 break # found an exclude, break for: and delete tb[0] 0167 else: 0168 break # no excludes, have left RPC code, break while: 0169 del tb[0] 0170 while tb: 0171 for rpcfile in exclude: 0172 if tb[-1][0].count(rpcfile): 0173 break 0174 else: 0175 break 0176 del tb[-1] 0177 if len(tb) == 0: 0178 # exception was in IDLE internals, don't prune! 0179 tb[:] = orig_tb[:] 0180 print>>sys.stderr, "** IDLE Internal Exception: " 0181 rpchandler = rpc.objecttable['exec'].rpchandler 0182 for i in range(len(tb)): 0183 fn, ln, nm, line = tb[i] 0184 if nm == '?': 0185 nm = "-toplevel-" 0186 if not line and fn.startswith("<pyshell#"): 0187 line = rpchandler.remotecall('linecache', 'getline', 0188 (fn, ln), {}) 0189 tb[i] = fn, ln, nm, line 0190 0191 def flush_stdout(): 0192 try: 0193 if sys.stdout.softspace: 0194 sys.stdout.softspace = 0 0195 sys.stdout.write("\n") 0196 except (AttributeError, EOFError): 0197 pass 0198 0199 def exit(): 0200 """Exit subprocess, possibly after first deleting sys.exitfunc 0201 0202 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any 0203 sys.exitfunc will be removed before exiting. (VPython support) 0204 0205 """ 0206 if no_exitfunc: 0207 del sys.exitfunc 0208 sys.exit(0) 0209 0210 class MyRPCServer(rpc.RPCServer): 0211 0212 def handle_error(self, request, client_address): 0213 """Override RPCServer method for IDLE 0214 0215 Interrupt the MainThread and exit server if link is dropped. 0216 0217 """ 0218 try: 0219 raise 0220 except SystemExit: 0221 raise 0222 except EOFError: 0223 global exit_now 0224 exit_now = True 0225 thread.interrupt_main() 0226 except: 0227 erf = sys.__stderr__ 0228 print>>erf, '\n' + '-'*40 0229 print>>erf, 'Unhandled server exception!' 0230 print>>erf, 'Thread: %s' % threading.currentThread().getName() 0231 print>>erf, 'Client Address: ', client_address 0232 print>>erf, 'Request: ', repr(request) 0233 traceback.print_exc(file=erf) 0234 print>>erf, '\n*** Unrecoverable, server exiting!' 0235 print>>erf, '-'*40 0236 exit() 0237 0238 0239 class MyHandler(rpc.RPCHandler): 0240 0241 def handle(self): 0242 """Override base method""" 0243 executive = Executive(self) 0244 self.register("exec", executive) 0245 sys.stdin = self.console = self.get_remote_proxy("stdin") 0246 sys.stdout = self.get_remote_proxy("stdout") 0247 sys.stderr = self.get_remote_proxy("stderr") 0248 import IOBinding 0249 sys.stdin.encoding = sys.stdout.encoding = \ 0250 sys.stderr.encoding = IOBinding.encoding 0251 self.interp = self.get_remote_proxy("interp") 0252 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05) 0253 0254 def exithook(self): 0255 "override SocketIO method - wait for MainThread to shut us down" 0256 time.sleep(10) 0257 0258 def EOFhook(self): 0259 "Override SocketIO method - terminate wait on callback and exit thread" 0260 global quitting 0261 quitting = True 0262 thread.interrupt_main() 0263 0264 def decode_interrupthook(self): 0265 "interrupt awakened thread" 0266 global quitting 0267 quitting = True 0268 thread.interrupt_main() 0269 0270 0271 class Executive: 0272 0273 def __init__(self, rpchandler): 0274 self.rpchandler = rpchandler 0275 self.locals = __main__.__dict__ 0276 self.calltip = CallTips.CallTips() 0277 0278 def runcode(self, code): 0279 try: 0280 self.usr_exc_info = None 0281 exec code in self.locals 0282 except: 0283 self.usr_exc_info = sys.exc_info() 0284 if quitting: 0285 exit() 0286 # even print a user code SystemExit exception, continue 0287 print_exception() 0288 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>") 0289 if jit: 0290 self.rpchandler.interp.open_remote_stack_viewer() 0291 else: 0292 flush_stdout() 0293 0294 def interrupt_the_server(self): 0295 thread.interrupt_main() 0296 0297 def start_the_debugger(self, gui_adap_oid): 0298 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid) 0299 0300 def stop_the_debugger(self, idb_adap_oid): 0301 "Unregister the Idb Adapter. Link objects and Idb then subject to GC" 0302 self.rpchandler.unregister(idb_adap_oid) 0303 0304 def get_the_calltip(self, name): 0305 return self.calltip.fetch_tip(name) 0306 0307 def stackviewer(self, flist_oid=None): 0308 if self.usr_exc_info: 0309 typ, val, tb = self.usr_exc_info 0310 else: 0311 return None 0312 flist = None 0313 if flist_oid is not None: 0314 flist = self.rpchandler.get_remote_proxy(flist_oid) 0315 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: 0316 tb = tb.tb_next 0317 sys.last_type = typ 0318 sys.last_value = val 0319 item = StackViewer.StackTreeItem(flist, tb) 0320 return RemoteObjectBrowser.remote_object_tree_item(item) 0321
Generated by PyXR 0.9.4