source: python/vendor/Python-2.7.6/Lib/idlelib/run.py

Last change on this file was 388, checked in by dmik, 11 years ago

python: Update vendor to 2.7.6.

  • Property svn:eol-style set to native
File size: 12.1 KB
Line 
1import sys
2import io
3import linecache
4import time
5import socket
6import traceback
7import thread
8import threading
9import Queue
10
11from idlelib import CallTips
12from idlelib import AutoComplete
13
14from idlelib import RemoteDebugger
15from idlelib import RemoteObjectBrowser
16from idlelib import StackViewer
17from idlelib import rpc
18from idlelib import PyShell
19from idlelib import IOBinding
20
21import __main__
22
23LOCALHOST = '127.0.0.1'
24
25import warnings
26
27def idle_showwarning_subproc(
28 message, category, filename, lineno, file=None, line=None):
29 """Show Idle-format warning after replacing warnings.showwarning.
30
31 The only difference is the formatter called.
32 """
33 if file is None:
34 file = sys.stderr
35 try:
36 file.write(PyShell.idle_formatwarning(
37 message, category, filename, lineno, line))
38 except IOError:
39 pass # the file (probably stderr) is invalid - this warning gets lost.
40
41_warnings_showwarning = None
42
43def capture_warnings(capture):
44 "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
45
46 global _warnings_showwarning
47 if capture:
48 if _warnings_showwarning is None:
49 _warnings_showwarning = warnings.showwarning
50 warnings.showwarning = idle_showwarning_subproc
51 else:
52 if _warnings_showwarning is not None:
53 warnings.showwarning = _warnings_showwarning
54 _warnings_showwarning = None
55
56capture_warnings(True)
57
58# Thread shared globals: Establish a queue between a subthread (which handles
59# the socket) and the main thread (which runs user code), plus global
60# completion, exit and interruptable (the main thread) flags:
61
62exit_now = False
63quitting = False
64interruptable = False
65
66def main(del_exitfunc=False):
67 """Start the Python execution server in a subprocess
68
69 In the Python subprocess, RPCServer is instantiated with handlerclass
70 MyHandler, which inherits register/unregister methods from RPCHandler via
71 the mix-in class SocketIO.
72
73 When the RPCServer 'server' is instantiated, the TCPServer initialization
74 creates an instance of run.MyHandler and calls its handle() method.
75 handle() instantiates a run.Executive object, passing it a reference to the
76 MyHandler object. That reference is saved as attribute rpchandler of the
77 Executive instance. The Executive methods have access to the reference and
78 can pass it on to entities that they command
79 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
80 call MyHandler(SocketIO) register/unregister methods via the reference to
81 register and unregister themselves.
82
83 """
84 global exit_now
85 global quitting
86 global no_exitfunc
87 no_exitfunc = del_exitfunc
88 #time.sleep(15) # test subprocess not responding
89 try:
90 assert(len(sys.argv) > 1)
91 port = int(sys.argv[-1])
92 except:
93 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
94 return
95
96 capture_warnings(True)
97 sys.argv[:] = [""]
98 sockthread = threading.Thread(target=manage_socket,
99 name='SockThread',
100 args=((LOCALHOST, port),))
101 sockthread.setDaemon(True)
102 sockthread.start()
103 while 1:
104 try:
105 if exit_now:
106 try:
107 exit()
108 except KeyboardInterrupt:
109 # exiting but got an extra KBI? Try again!
110 continue
111 try:
112 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
113 except Queue.Empty:
114 continue
115 method, args, kwargs = request
116 ret = method(*args, **kwargs)
117 rpc.response_queue.put((seq, ret))
118 except KeyboardInterrupt:
119 if quitting:
120 exit_now = True
121 continue
122 except SystemExit:
123 capture_warnings(False)
124 raise
125 except:
126 type, value, tb = sys.exc_info()
127 try:
128 print_exception()
129 rpc.response_queue.put((seq, None))
130 except:
131 # Link didn't work, print same exception to __stderr__
132 traceback.print_exception(type, value, tb, file=sys.__stderr__)
133 exit()
134 else:
135 continue
136
137def manage_socket(address):
138 for i in range(3):
139 time.sleep(i)
140 try:
141 server = MyRPCServer(address, MyHandler)
142 break
143 except socket.error as err:
144 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
145 + err.args[1] + ", retrying...."
146 else:
147 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
148 "IDLE GUI failed, exiting."
149 show_socket_error(err, address)
150 global exit_now
151 exit_now = True
152 return
153 server.handle_request() # A single request only
154
155def show_socket_error(err, address):
156 import Tkinter
157 import tkMessageBox
158 root = Tkinter.Tk()
159 root.withdraw()
160 if err.args[0] == 61: # connection refused
161 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
162 "to your personal firewall configuration. It is safe to "\
163 "allow this internal connection because no data is visible on "\
164 "external ports." % address
165 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
166 else:
167 tkMessageBox.showerror("IDLE Subprocess Error",
168 "Socket Error: %s" % err.args[1])
169 root.destroy()
170
171def print_exception():
172 import linecache
173 linecache.checkcache()
174 flush_stdout()
175 efile = sys.stderr
176 typ, val, tb = excinfo = sys.exc_info()
177 sys.last_type, sys.last_value, sys.last_traceback = excinfo
178 tbe = traceback.extract_tb(tb)
179 print>>efile, '\nTraceback (most recent call last):'
180 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
181 "RemoteDebugger.py", "bdb.py")
182 cleanup_traceback(tbe, exclude)
183 traceback.print_list(tbe, file=efile)
184 lines = traceback.format_exception_only(typ, val)
185 for line in lines:
186 print>>efile, line,
187
188def cleanup_traceback(tb, exclude):
189 "Remove excluded traces from beginning/end of tb; get cached lines"
190 orig_tb = tb[:]
191 while tb:
192 for rpcfile in exclude:
193 if tb[0][0].count(rpcfile):
194 break # found an exclude, break for: and delete tb[0]
195 else:
196 break # no excludes, have left RPC code, break while:
197 del tb[0]
198 while tb:
199 for rpcfile in exclude:
200 if tb[-1][0].count(rpcfile):
201 break
202 else:
203 break
204 del tb[-1]
205 if len(tb) == 0:
206 # exception was in IDLE internals, don't prune!
207 tb[:] = orig_tb[:]
208 print>>sys.stderr, "** IDLE Internal Exception: "
209 rpchandler = rpc.objecttable['exec'].rpchandler
210 for i in range(len(tb)):
211 fn, ln, nm, line = tb[i]
212 if nm == '?':
213 nm = "-toplevel-"
214 if not line and fn.startswith("<pyshell#"):
215 line = rpchandler.remotecall('linecache', 'getline',
216 (fn, ln), {})
217 tb[i] = fn, ln, nm, line
218
219def flush_stdout():
220 try:
221 if sys.stdout.softspace:
222 sys.stdout.softspace = 0
223 sys.stdout.write("\n")
224 except (AttributeError, EOFError):
225 pass
226
227def exit():
228 """Exit subprocess, possibly after first deleting sys.exitfunc
229
230 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
231 sys.exitfunc will be removed before exiting. (VPython support)
232
233 """
234 if no_exitfunc:
235 try:
236 del sys.exitfunc
237 except AttributeError:
238 pass
239 capture_warnings(False)
240 sys.exit(0)
241
242class MyRPCServer(rpc.RPCServer):
243
244 def handle_error(self, request, client_address):
245 """Override RPCServer method for IDLE
246
247 Interrupt the MainThread and exit server if link is dropped.
248
249 """
250 global quitting
251 try:
252 raise
253 except SystemExit:
254 raise
255 except EOFError:
256 global exit_now
257 exit_now = True
258 thread.interrupt_main()
259 except:
260 erf = sys.__stderr__
261 print>>erf, '\n' + '-'*40
262 print>>erf, 'Unhandled server exception!'
263 print>>erf, 'Thread: %s' % threading.currentThread().getName()
264 print>>erf, 'Client Address: ', client_address
265 print>>erf, 'Request: ', repr(request)
266 traceback.print_exc(file=erf)
267 print>>erf, '\n*** Unrecoverable, server exiting!'
268 print>>erf, '-'*40
269 quitting = True
270 thread.interrupt_main()
271
272class MyHandler(rpc.RPCHandler):
273
274 def handle(self):
275 """Override base method"""
276 executive = Executive(self)
277 self.register("exec", executive)
278 self.console = self.get_remote_proxy("console")
279 sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
280 IOBinding.encoding)
281 sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
282 IOBinding.encoding)
283 sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
284 IOBinding.encoding)
285
286 # Keep a reference to stdin so that it won't try to exit IDLE if
287 # sys.stdin gets changed from within IDLE's shell. See issue17838.
288 self._keep_stdin = sys.stdin
289
290 self.interp = self.get_remote_proxy("interp")
291 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
292
293 def exithook(self):
294 "override SocketIO method - wait for MainThread to shut us down"
295 time.sleep(10)
296
297 def EOFhook(self):
298 "Override SocketIO method - terminate wait on callback and exit thread"
299 global quitting
300 quitting = True
301 thread.interrupt_main()
302
303 def decode_interrupthook(self):
304 "interrupt awakened thread"
305 global quitting
306 quitting = True
307 thread.interrupt_main()
308
309
310class Executive(object):
311
312 def __init__(self, rpchandler):
313 self.rpchandler = rpchandler
314 self.locals = __main__.__dict__
315 self.calltip = CallTips.CallTips()
316 self.autocomplete = AutoComplete.AutoComplete()
317
318 def runcode(self, code):
319 global interruptable
320 try:
321 self.usr_exc_info = None
322 interruptable = True
323 try:
324 exec code in self.locals
325 finally:
326 interruptable = False
327 except SystemExit:
328 # Scripts that raise SystemExit should just
329 # return to the interactive prompt
330 pass
331 except:
332 self.usr_exc_info = sys.exc_info()
333 if quitting:
334 exit()
335 print_exception()
336 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
337 if jit:
338 self.rpchandler.interp.open_remote_stack_viewer()
339 else:
340 flush_stdout()
341
342 def interrupt_the_server(self):
343 if interruptable:
344 thread.interrupt_main()
345
346 def start_the_debugger(self, gui_adap_oid):
347 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
348
349 def stop_the_debugger(self, idb_adap_oid):
350 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
351 self.rpchandler.unregister(idb_adap_oid)
352
353 def get_the_calltip(self, name):
354 return self.calltip.fetch_tip(name)
355
356 def get_the_completion_list(self, what, mode):
357 return self.autocomplete.fetch_completions(what, mode)
358
359 def stackviewer(self, flist_oid=None):
360 if self.usr_exc_info:
361 typ, val, tb = self.usr_exc_info
362 else:
363 return None
364 flist = None
365 if flist_oid is not None:
366 flist = self.rpchandler.get_remote_proxy(flist_oid)
367 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
368 tb = tb.tb_next
369 sys.last_type = typ
370 sys.last_value = val
371 item = StackViewer.StackTreeItem(flist, tb)
372 return RemoteObjectBrowser.remote_object_tree_item(item)
373
374capture_warnings(False) # Make sure turned off; see issue 18081
Note: See TracBrowser for help on using the repository browser.