14 import RemoteObjectBrowser
20 LOCALHOST
= '127.0.0.1'
27 def idle_formatwarning_subproc(message
, category
, filename
, lineno
,
28 file=None, line
=None):
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
is None else line
36 s
+= "%s: %s\n" % (category
.__name
__, message
)
38 warnings
.formatwarning
= idle_formatwarning_subproc
40 # Thread shared globals: Establish a queue between a subthread (which handles
41 # the socket) and the main thread (which runs user code), plus global
42 # completion, exit and interruptable (the main thread) flags:
48 def main(del_exitfunc
=False):
49 """Start the Python execution server in a subprocess
51 In the Python subprocess, RPCServer is instantiated with handlerclass
52 MyHandler, which inherits register/unregister methods from RPCHandler via
53 the mix-in class SocketIO.
55 When the RPCServer 'server' is instantiated, the TCPServer initialization
56 creates an instance of run.MyHandler and calls its handle() method.
57 handle() instantiates a run.Executive object, passing it a reference to the
58 MyHandler object. That reference is saved as attribute rpchandler of the
59 Executive instance. The Executive methods have access to the reference and
60 can pass it on to entities that they command
61 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
62 call MyHandler(SocketIO) register/unregister methods via the reference to
63 register and unregister themselves.
69 no_exitfunc
= del_exitfunc
70 #time.sleep(15) # test subprocess not responding
72 assert(len(sys
.argv
) > 1)
73 port
= int(sys
.argv
[-1])
75 print>>sys
.stderr
, "IDLE Subprocess: no IP port passed in sys.argv."
78 sockthread
= threading
.Thread(target
=manage_socket
,
80 args
=((LOCALHOST
, port
),))
81 sockthread
.setDaemon(True)
88 except KeyboardInterrupt:
89 # exiting but got an extra KBI? Try again!
92 seq
, request
= rpc
.request_queue
.get(block
=True, timeout
=0.05)
95 method
, args
, kwargs
= request
96 ret
= method(*args
, **kwargs
)
97 rpc
.response_queue
.put((seq
, ret
))
98 except KeyboardInterrupt:
105 type, value
, tb
= sys
.exc_info()
108 rpc
.response_queue
.put((seq
, None))
110 # Link didn't work, print same exception to __stderr__
111 traceback
.print_exception(type, value
, tb
, file=sys
.__stderr
__)
116 def manage_socket(address
):
120 server
= MyRPCServer(address
, MyHandler
)
122 except socket
.error
, err
:
123 print>>sys
.__stderr
__,"IDLE Subprocess: socket error: "\
124 + err
[1] + ", retrying...."
126 print>>sys
.__stderr
__, "IDLE Subprocess: Connection to "\
127 "IDLE GUI failed, exiting."
128 show_socket_error(err
, address
)
132 server
.handle_request() # A single request only
134 def show_socket_error(err
, address
):
139 if err
[0] == 61: # connection refused
140 msg
= "IDLE's subprocess can't connect to %s:%d. This may be due "\
141 "to your personal firewall configuration. It is safe to "\
142 "allow this internal connection because no data is visible on "\
143 "external ports." % address
144 tkMessageBox
.showerror("IDLE Subprocess Error", msg
, parent
=root
)
146 tkMessageBox
.showerror("IDLE Subprocess Error", "Socket Error: %s" % err
[1])
149 def print_exception():
151 linecache
.checkcache()
154 typ
, val
, tb
= excinfo
= sys
.exc_info()
155 sys
.last_type
, sys
.last_value
, sys
.last_traceback
= excinfo
156 tbe
= traceback
.extract_tb(tb
)
157 print>>efile
, '\nTraceback (most recent call last):'
158 exclude
= ("run.py", "rpc.py", "threading.py", "Queue.py",
159 "RemoteDebugger.py", "bdb.py")
160 cleanup_traceback(tbe
, exclude
)
161 traceback
.print_list(tbe
, file=efile
)
162 lines
= traceback
.format_exception_only(typ
, val
)
166 def cleanup_traceback(tb
, exclude
):
167 "Remove excluded traces from beginning/end of tb; get cached lines"
170 for rpcfile
in exclude
:
171 if tb
[0][0].count(rpcfile
):
172 break # found an exclude, break for: and delete tb[0]
174 break # no excludes, have left RPC code, break while:
177 for rpcfile
in exclude
:
178 if tb
[-1][0].count(rpcfile
):
184 # exception was in IDLE internals, don't prune!
186 print>>sys
.stderr
, "** IDLE Internal Exception: "
187 rpchandler
= rpc
.objecttable
['exec'].rpchandler
188 for i
in range(len(tb
)):
189 fn
, ln
, nm
, line
= tb
[i
]
192 if not line
and fn
.startswith("<pyshell#"):
193 line
= rpchandler
.remotecall('linecache', 'getline',
195 tb
[i
] = fn
, ln
, nm
, line
199 if sys
.stdout
.softspace
:
200 sys
.stdout
.softspace
= 0
201 sys
.stdout
.write("\n")
202 except (AttributeError, EOFError):
206 """Exit subprocess, possibly after first deleting sys.exitfunc
208 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
209 sys.exitfunc will be removed before exiting. (VPython support)
215 except AttributeError:
219 class MyRPCServer(rpc
.RPCServer
):
221 def handle_error(self
, request
, client_address
):
222 """Override RPCServer method for IDLE
224 Interrupt the MainThread and exit server if link is dropped.
235 thread
.interrupt_main()
238 print>>erf
, '\n' + '-'*40
239 print>>erf
, 'Unhandled server exception!'
240 print>>erf
, 'Thread: %s' % threading
.currentThread().getName()
241 print>>erf
, 'Client Address: ', client_address
242 print>>erf
, 'Request: ', repr(request
)
243 traceback
.print_exc(file=erf
)
244 print>>erf
, '\n*** Unrecoverable, server exiting!'
247 thread
.interrupt_main()
250 class MyHandler(rpc
.RPCHandler
):
253 """Override base method"""
254 executive
= Executive(self
)
255 self
.register("exec", executive
)
256 sys
.stdin
= self
.console
= self
.get_remote_proxy("stdin")
257 sys
.stdout
= self
.get_remote_proxy("stdout")
258 sys
.stderr
= self
.get_remote_proxy("stderr")
260 sys
.stdin
.encoding
= sys
.stdout
.encoding
= \
261 sys
.stderr
.encoding
= IOBinding
.encoding
262 self
.interp
= self
.get_remote_proxy("interp")
263 rpc
.RPCHandler
.getresponse(self
, myseq
=None, wait
=0.05)
266 "override SocketIO method - wait for MainThread to shut us down"
270 "Override SocketIO method - terminate wait on callback and exit thread"
273 thread
.interrupt_main()
275 def decode_interrupthook(self
):
276 "interrupt awakened thread"
279 thread
.interrupt_main()
282 class Executive(object):
284 def __init__(self
, rpchandler
):
285 self
.rpchandler
= rpchandler
286 self
.locals = __main__
.__dict
__
287 self
.calltip
= CallTips
.CallTips()
288 self
.autocomplete
= AutoComplete
.AutoComplete()
290 def runcode(self
, code
):
293 self
.usr_exc_info
= None
296 exec code
in self
.locals
298 interruptable
= False
300 self
.usr_exc_info
= sys
.exc_info()
303 # even print a user code SystemExit exception, continue
305 jit
= self
.rpchandler
.console
.getvar("<<toggle-jit-stack-viewer>>")
307 self
.rpchandler
.interp
.open_remote_stack_viewer()
311 def interrupt_the_server(self
):
313 thread
.interrupt_main()
315 def start_the_debugger(self
, gui_adap_oid
):
316 return RemoteDebugger
.start_debugger(self
.rpchandler
, gui_adap_oid
)
318 def stop_the_debugger(self
, idb_adap_oid
):
319 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
320 self
.rpchandler
.unregister(idb_adap_oid
)
322 def get_the_calltip(self
, name
):
323 return self
.calltip
.fetch_tip(name
)
325 def get_the_completion_list(self
, what
, mode
):
326 return self
.autocomplete
.fetch_completions(what
, mode
)
328 def stackviewer(self
, flist_oid
=None):
329 if self
.usr_exc_info
:
330 typ
, val
, tb
= self
.usr_exc_info
334 if flist_oid
is not None:
335 flist
= self
.rpchandler
.get_remote_proxy(flist_oid
)
336 while tb
and tb
.tb_frame
.f_globals
["__name__"] in ["rpc", "run"]:
340 item
= StackViewer
.StackTreeItem(flist
, tb
)
341 return RemoteObjectBrowser
.remote_object_tree_item(item
)