15 import RemoteObjectBrowser
21 LOCALHOST
= '127.0.0.1'
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()
35 s
+= "%s: %s\n" % (category
.__name
__, message
)
37 warnings
.formatwarning
= idle_formatwarning_subproc
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:
46 def main(del_exitfunc
=False):
47 """Start the Python execution server in a subprocess
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.
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.
67 no_exitfunc
= del_exitfunc
69 #time.sleep(15) # test subprocess not responding
71 port
= int(sys
.argv
[1])
73 sockthread
= threading
.Thread(target
=manage_socket
,
75 args
=((LOCALHOST
, port
),))
76 sockthread
.setDaemon(True)
83 except KeyboardInterrupt:
84 # exiting but got an extra KBI? Try again!
87 seq
, request
= rpc
.request_queue
.get(block
=True, timeout
=0.05)
90 method
, args
, kwargs
= request
91 ret
= method(*args
, **kwargs
)
92 rpc
.response_queue
.put((seq
, ret
))
93 except KeyboardInterrupt:
100 type, value
, tb
= sys
.exc_info()
103 rpc
.response_queue
.put((seq
, None))
105 # Link didn't work, print same exception to __stderr__
106 traceback
.print_exception(type, value
, tb
, file=sys
.__stderr
__)
111 def manage_socket(address
):
115 server
= MyRPCServer(address
, MyHandler
)
117 except socket
.error
, err
:
118 print>>sys
.__stderr
__,"IDLE Subprocess: socket error: "\
119 + err
[1] + ", retrying...."
121 print>>sys
.__stderr
__, "IDLE Subprocess: Connection to "\
122 "IDLE GUI failed, exiting."
123 show_socket_error(err
, address
)
127 server
.handle_request() # A single request only
129 def show_socket_error(err
, address
):
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
)
141 tkMessageBox
.showerror("IDLE Subprocess Error", "Socket Error: %s" % err
[1])
144 def print_exception():
146 linecache
.checkcache()
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
)
161 def cleanup_traceback(tb
, exclude
):
162 "Remove excluded traces from beginning/end of tb; get cached lines"
165 for rpcfile
in exclude
:
166 if tb
[0][0].count(rpcfile
):
167 break # found an exclude, break for: and delete tb[0]
169 break # no excludes, have left RPC code, break while:
172 for rpcfile
in exclude
:
173 if tb
[-1][0].count(rpcfile
):
179 # exception was in IDLE internals, don't prune!
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
]
187 if not line
and fn
.startswith("<pyshell#"):
188 line
= rpchandler
.remotecall('linecache', 'getline',
190 tb
[i
] = fn
, ln
, nm
, line
194 if sys
.stdout
.softspace
:
195 sys
.stdout
.softspace
= 0
196 sys
.stdout
.write("\n")
197 except (AttributeError, EOFError):
201 """Exit subprocess, possibly after first deleting sys.exitfunc
203 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
204 sys.exitfunc will be removed before exiting. (VPython support)
211 class MyRPCServer(rpc
.RPCServer
):
213 def handle_error(self
, request
, client_address
):
214 """Override RPCServer method for IDLE
216 Interrupt the MainThread and exit server if link is dropped.
227 thread
.interrupt_main()
230 print>>erf
, '\n' + '-'*40
231 print>>erf
, 'Unhandled server exception!'
232 print>>erf
, 'Thread: %s' % threading
.currentThread().getName()
233 print>>erf
, 'Client Address: ', client_address
234 print>>erf
, 'Request: ', repr(request
)
235 traceback
.print_exc(file=erf
)
236 print>>erf
, '\n*** Unrecoverable, server exiting!'
239 thread
.interrupt_main()
242 class MyHandler(rpc
.RPCHandler
):
245 """Override base method"""
246 executive
= Executive(self
)
247 self
.register("exec", executive
)
248 sys
.stdin
= self
.console
= self
.get_remote_proxy("stdin")
249 sys
.stdout
= self
.get_remote_proxy("stdout")
250 sys
.stderr
= self
.get_remote_proxy("stderr")
252 sys
.stdin
.encoding
= sys
.stdout
.encoding
= \
253 sys
.stderr
.encoding
= IOBinding
.encoding
254 self
.interp
= self
.get_remote_proxy("interp")
255 rpc
.RPCHandler
.getresponse(self
, myseq
=None, wait
=0.05)
258 "override SocketIO method - wait for MainThread to shut us down"
262 "Override SocketIO method - terminate wait on callback and exit thread"
265 thread
.interrupt_main()
267 def decode_interrupthook(self
):
268 "interrupt awakened thread"
271 thread
.interrupt_main()
274 class Executive(object):
276 def __init__(self
, rpchandler
):
277 self
.rpchandler
= rpchandler
278 self
.locals = __main__
.__dict
__
279 self
.calltip
= CallTips
.CallTips()
280 self
.autocomplete
= AutoComplete
.AutoComplete()
282 def runcode(self
, code
):
284 self
.usr_exc_info
= None
285 exec code
in self
.locals
287 self
.usr_exc_info
= sys
.exc_info()
290 # even print a user code SystemExit exception, continue
292 jit
= self
.rpchandler
.console
.getvar("<<toggle-jit-stack-viewer>>")
294 self
.rpchandler
.interp
.open_remote_stack_viewer()
298 def interrupt_the_server(self
):
299 thread
.interrupt_main()
301 def start_the_debugger(self
, gui_adap_oid
):
302 return RemoteDebugger
.start_debugger(self
.rpchandler
, gui_adap_oid
)
304 def stop_the_debugger(self
, idb_adap_oid
):
305 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
306 self
.rpchandler
.unregister(idb_adap_oid
)
308 def get_the_calltip(self
, name
):
309 return self
.calltip
.fetch_tip(name
)
311 def get_the_completion_list(self
, what
, mode
):
312 return self
.autocomplete
.fetch_completions(what
, mode
)
314 def stackviewer(self
, flist_oid
=None):
315 if self
.usr_exc_info
:
316 typ
, val
, tb
= self
.usr_exc_info
320 if flist_oid
is not None:
321 flist
= self
.rpchandler
.get_remote_proxy(flist_oid
)
322 while tb
and tb
.tb_frame
.f_globals
["__name__"] in ["rpc", "run"]:
326 item
= StackViewer
.StackTreeItem(flist
, tb
)
327 return RemoteObjectBrowser
.remote_object_tree_item(item
)