Update functools section
[python.git] / Lib / idlelib / run.py
blobae810c4ecc7c6b39d5ab590a6b5c3bbc8f171077
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
11 import CallTips
12 import AutoComplete
14 import RemoteDebugger
15 import RemoteObjectBrowser
16 import StackViewer
17 import rpc
19 import __main__
21 LOCALHOST = '127.0.0.1'
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
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:
43 exit_now = False
44 quitting = False
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.
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
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
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()
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,
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
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
200 def exit():
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)
207 if no_exitfunc:
208 del sys.exitfunc
209 sys.exit(0)
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.
219 global quitting
220 try:
221 raise
222 except SystemExit:
223 raise
224 except EOFError:
225 global exit_now
226 exit_now = True
227 thread.interrupt_main()
228 except:
229 erf = sys.__stderr__
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!'
237 print>>erf, '-'*40
238 quitting = True
239 thread.interrupt_main()
242 class MyHandler(rpc.RPCHandler):
244 def handle(self):
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")
251 import IOBinding
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)
257 def exithook(self):
258 "override SocketIO method - wait for MainThread to shut us down"
259 time.sleep(10)
261 def EOFhook(self):
262 "Override SocketIO method - terminate wait on callback and exit thread"
263 global quitting
264 quitting = True
265 thread.interrupt_main()
267 def decode_interrupthook(self):
268 "interrupt awakened thread"
269 global quitting
270 quitting = True
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):
283 try:
284 self.usr_exc_info = None
285 exec code in self.locals
286 except:
287 self.usr_exc_info = sys.exc_info()
288 if quitting:
289 exit()
290 # even print a user code SystemExit exception, continue
291 print_exception()
292 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
293 if jit:
294 self.rpchandler.interp.open_remote_stack_viewer()
295 else:
296 flush_stdout()
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
317 else:
318 return None
319 flist = None
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"]:
323 tb = tb.tb_next
324 sys.last_type = typ
325 sys.last_value = val
326 item = StackViewer.StackTreeItem(flist, tb)
327 return RemoteObjectBrowser.remote_object_tree_item(item)