return locals and cells in get_locals() not bound globals, though
[python.git] / Lib / idlelib / run.py
blob2d5c5edaaa7de51d32d86a94253d2ef4f02459f8
1 import sys
2 import linecache
3 import time
4 import socket
5 import traceback
6 import thread
7 import threading
8 import Queue
10 import CallTips
11 import AutoComplete
13 import RemoteDebugger
14 import RemoteObjectBrowser
15 import StackViewer
16 import rpc
18 import __main__
20 LOCALHOST = '127.0.0.1'
22 try:
23 import warnings
24 except ImportError:
25 pass
26 else:
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
34 if line:
35 s += " %s\n" % line
36 s += "%s: %s\n" % (category.__name__, message)
37 return s
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:
44 exit_now = False
45 quitting = False
46 interruptable = False
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.
65 """
66 global exit_now
67 global quitting
68 global no_exitfunc
69 no_exitfunc = del_exitfunc
70 #time.sleep(15) # test subprocess not responding
71 try:
72 assert(len(sys.argv) > 1)
73 port = int(sys.argv[-1])
74 except:
75 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
76 return
77 sys.argv[:] = [""]
78 sockthread = threading.Thread(target=manage_socket,
79 name='SockThread',
80 args=((LOCALHOST, port),))
81 sockthread.setDaemon(True)
82 sockthread.start()
83 while 1:
84 try:
85 if exit_now:
86 try:
87 exit()
88 except KeyboardInterrupt:
89 # exiting but got an extra KBI? Try again!
90 continue
91 try:
92 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
93 except Queue.Empty:
94 continue
95 method, args, kwargs = request
96 ret = method(*args, **kwargs)
97 rpc.response_queue.put((seq, ret))
98 except KeyboardInterrupt:
99 if quitting:
100 exit_now = True
101 continue
102 except SystemExit:
103 raise
104 except:
105 type, value, tb = sys.exc_info()
106 try:
107 print_exception()
108 rpc.response_queue.put((seq, None))
109 except:
110 # Link didn't work, print same exception to __stderr__
111 traceback.print_exception(type, value, tb, file=sys.__stderr__)
112 exit()
113 else:
114 continue
116 def manage_socket(address):
117 for i in range(3):
118 time.sleep(i)
119 try:
120 server = MyRPCServer(address, MyHandler)
121 break
122 except socket.error, err:
123 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
124 + err[1] + ", retrying...."
125 else:
126 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
127 "IDLE GUI failed, exiting."
128 show_socket_error(err, address)
129 global exit_now
130 exit_now = True
131 return
132 server.handle_request() # A single request only
134 def show_socket_error(err, address):
135 import Tkinter
136 import tkMessageBox
137 root = Tkinter.Tk()
138 root.withdraw()
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)
145 else:
146 tkMessageBox.showerror("IDLE Subprocess Error", "Socket Error: %s" % err[1])
147 root.destroy()
149 def print_exception():
150 import linecache
151 linecache.checkcache()
152 flush_stdout()
153 efile = sys.stderr
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)
163 for line in lines:
164 print>>efile, line,
166 def cleanup_traceback(tb, exclude):
167 "Remove excluded traces from beginning/end of tb; get cached lines"
168 orig_tb = tb[:]
169 while tb:
170 for rpcfile in exclude:
171 if tb[0][0].count(rpcfile):
172 break # found an exclude, break for: and delete tb[0]
173 else:
174 break # no excludes, have left RPC code, break while:
175 del tb[0]
176 while tb:
177 for rpcfile in exclude:
178 if tb[-1][0].count(rpcfile):
179 break
180 else:
181 break
182 del tb[-1]
183 if len(tb) == 0:
184 # exception was in IDLE internals, don't prune!
185 tb[:] = orig_tb[:]
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]
190 if nm == '?':
191 nm = "-toplevel-"
192 if not line and fn.startswith("<pyshell#"):
193 line = rpchandler.remotecall('linecache', 'getline',
194 (fn, ln), {})
195 tb[i] = fn, ln, nm, line
197 def flush_stdout():
198 try:
199 if sys.stdout.softspace:
200 sys.stdout.softspace = 0
201 sys.stdout.write("\n")
202 except (AttributeError, EOFError):
203 pass
205 def exit():
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)
212 if no_exitfunc:
213 try:
214 del sys.exitfunc
215 except AttributeError:
216 pass
217 sys.exit(0)
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.
227 global quitting
228 try:
229 raise
230 except SystemExit:
231 raise
232 except EOFError:
233 global exit_now
234 exit_now = True
235 thread.interrupt_main()
236 except:
237 erf = sys.__stderr__
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!'
245 print>>erf, '-'*40
246 quitting = True
247 thread.interrupt_main()
250 class MyHandler(rpc.RPCHandler):
252 def handle(self):
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")
259 import IOBinding
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)
265 def exithook(self):
266 "override SocketIO method - wait for MainThread to shut us down"
267 time.sleep(10)
269 def EOFhook(self):
270 "Override SocketIO method - terminate wait on callback and exit thread"
271 global quitting
272 quitting = True
273 thread.interrupt_main()
275 def decode_interrupthook(self):
276 "interrupt awakened thread"
277 global quitting
278 quitting = True
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):
291 global interruptable
292 try:
293 self.usr_exc_info = None
294 interruptable = True
295 try:
296 exec code in self.locals
297 finally:
298 interruptable = False
299 except:
300 self.usr_exc_info = sys.exc_info()
301 if quitting:
302 exit()
303 # even print a user code SystemExit exception, continue
304 print_exception()
305 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
306 if jit:
307 self.rpchandler.interp.open_remote_stack_viewer()
308 else:
309 flush_stdout()
311 def interrupt_the_server(self):
312 if interruptable:
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
331 else:
332 return None
333 flist = None
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"]:
337 tb = tb.tb_next
338 sys.last_type = typ
339 sys.last_value = val
340 item = StackViewer.StackTreeItem(flist, tb)
341 return RemoteObjectBrowser.remote_object_tree_item(item)