Replace long with twodigits, to avoid depending
[python.git] / Lib / idlelib / run.py
blobabe94abc8b9c44e9ba6ea1a25d484b8e209954bb
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 port = 8833
71 #time.sleep(15) # test subprocess not responding
72 if sys.argv[1:]:
73 port = int(sys.argv[1])
74 sys.argv[:] = [""]
75 sockthread = threading.Thread(target=manage_socket,
76 name='SockThread',
77 args=((LOCALHOST, port),))
78 sockthread.setDaemon(True)
79 sockthread.start()
80 while 1:
81 try:
82 if exit_now:
83 try:
84 exit()
85 except KeyboardInterrupt:
86 # exiting but got an extra KBI? Try again!
87 continue
88 try:
89 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
90 except Queue.Empty:
91 continue
92 method, args, kwargs = request
93 ret = method(*args, **kwargs)
94 rpc.response_queue.put((seq, ret))
95 except KeyboardInterrupt:
96 if quitting:
97 exit_now = True
98 continue
99 except SystemExit:
100 raise
101 except:
102 type, value, tb = sys.exc_info()
103 try:
104 print_exception()
105 rpc.response_queue.put((seq, None))
106 except:
107 # Link didn't work, print same exception to __stderr__
108 traceback.print_exception(type, value, tb, file=sys.__stderr__)
109 exit()
110 else:
111 continue
113 def manage_socket(address):
114 for i in range(3):
115 time.sleep(i)
116 try:
117 server = MyRPCServer(address, MyHandler)
118 break
119 except socket.error, err:
120 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
121 + err[1] + ", retrying...."
122 else:
123 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
124 "IDLE GUI failed, exiting."
125 show_socket_error(err, address)
126 global exit_now
127 exit_now = True
128 return
129 server.handle_request() # A single request only
131 def show_socket_error(err, address):
132 import Tkinter
133 import tkMessageBox
134 root = Tkinter.Tk()
135 root.withdraw()
136 if err[0] == 61: # connection refused
137 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
138 "to your personal firewall configuration. It is safe to "\
139 "allow this internal connection because no data is visible on "\
140 "external ports." % address
141 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
142 else:
143 tkMessageBox.showerror("IDLE Subprocess Error", "Socket Error: %s" % err[1])
144 root.destroy()
146 def print_exception():
147 import linecache
148 linecache.checkcache()
149 flush_stdout()
150 efile = sys.stderr
151 typ, val, tb = excinfo = sys.exc_info()
152 sys.last_type, sys.last_value, sys.last_traceback = excinfo
153 tbe = traceback.extract_tb(tb)
154 print>>efile, '\nTraceback (most recent call last):'
155 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
156 "RemoteDebugger.py", "bdb.py")
157 cleanup_traceback(tbe, exclude)
158 traceback.print_list(tbe, file=efile)
159 lines = traceback.format_exception_only(typ, val)
160 for line in lines:
161 print>>efile, line,
163 def cleanup_traceback(tb, exclude):
164 "Remove excluded traces from beginning/end of tb; get cached lines"
165 orig_tb = tb[:]
166 while tb:
167 for rpcfile in exclude:
168 if tb[0][0].count(rpcfile):
169 break # found an exclude, break for: and delete tb[0]
170 else:
171 break # no excludes, have left RPC code, break while:
172 del tb[0]
173 while tb:
174 for rpcfile in exclude:
175 if tb[-1][0].count(rpcfile):
176 break
177 else:
178 break
179 del tb[-1]
180 if len(tb) == 0:
181 # exception was in IDLE internals, don't prune!
182 tb[:] = orig_tb[:]
183 print>>sys.stderr, "** IDLE Internal Exception: "
184 rpchandler = rpc.objecttable['exec'].rpchandler
185 for i in range(len(tb)):
186 fn, ln, nm, line = tb[i]
187 if nm == '?':
188 nm = "-toplevel-"
189 if not line and fn.startswith("<pyshell#"):
190 line = rpchandler.remotecall('linecache', 'getline',
191 (fn, ln), {})
192 tb[i] = fn, ln, nm, line
194 def flush_stdout():
195 try:
196 if sys.stdout.softspace:
197 sys.stdout.softspace = 0
198 sys.stdout.write("\n")
199 except (AttributeError, EOFError):
200 pass
202 def exit():
203 """Exit subprocess, possibly after first deleting sys.exitfunc
205 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
206 sys.exitfunc will be removed before exiting. (VPython support)
209 if no_exitfunc:
210 try:
211 del sys.exitfunc
212 except AttributeError:
213 pass
214 sys.exit(0)
216 class MyRPCServer(rpc.RPCServer):
218 def handle_error(self, request, client_address):
219 """Override RPCServer method for IDLE
221 Interrupt the MainThread and exit server if link is dropped.
224 global quitting
225 try:
226 raise
227 except SystemExit:
228 raise
229 except EOFError:
230 global exit_now
231 exit_now = True
232 thread.interrupt_main()
233 except:
234 erf = sys.__stderr__
235 print>>erf, '\n' + '-'*40
236 print>>erf, 'Unhandled server exception!'
237 print>>erf, 'Thread: %s' % threading.currentThread().getName()
238 print>>erf, 'Client Address: ', client_address
239 print>>erf, 'Request: ', repr(request)
240 traceback.print_exc(file=erf)
241 print>>erf, '\n*** Unrecoverable, server exiting!'
242 print>>erf, '-'*40
243 quitting = True
244 thread.interrupt_main()
247 class MyHandler(rpc.RPCHandler):
249 def handle(self):
250 """Override base method"""
251 executive = Executive(self)
252 self.register("exec", executive)
253 sys.stdin = self.console = self.get_remote_proxy("stdin")
254 sys.stdout = self.get_remote_proxy("stdout")
255 sys.stderr = self.get_remote_proxy("stderr")
256 import IOBinding
257 sys.stdin.encoding = sys.stdout.encoding = \
258 sys.stderr.encoding = IOBinding.encoding
259 self.interp = self.get_remote_proxy("interp")
260 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
262 def exithook(self):
263 "override SocketIO method - wait for MainThread to shut us down"
264 time.sleep(10)
266 def EOFhook(self):
267 "Override SocketIO method - terminate wait on callback and exit thread"
268 global quitting
269 quitting = True
270 thread.interrupt_main()
272 def decode_interrupthook(self):
273 "interrupt awakened thread"
274 global quitting
275 quitting = True
276 thread.interrupt_main()
279 class Executive(object):
281 def __init__(self, rpchandler):
282 self.rpchandler = rpchandler
283 self.locals = __main__.__dict__
284 self.calltip = CallTips.CallTips()
285 self.autocomplete = AutoComplete.AutoComplete()
287 def runcode(self, code):
288 global interruptable
289 try:
290 self.usr_exc_info = None
291 interruptable = True
292 try:
293 exec code in self.locals
294 finally:
295 interruptable = False
296 except:
297 self.usr_exc_info = sys.exc_info()
298 if quitting:
299 exit()
300 # even print a user code SystemExit exception, continue
301 print_exception()
302 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
303 if jit:
304 self.rpchandler.interp.open_remote_stack_viewer()
305 else:
306 flush_stdout()
308 def interrupt_the_server(self):
309 if interruptable:
310 thread.interrupt_main()
312 def start_the_debugger(self, gui_adap_oid):
313 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
315 def stop_the_debugger(self, idb_adap_oid):
316 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
317 self.rpchandler.unregister(idb_adap_oid)
319 def get_the_calltip(self, name):
320 return self.calltip.fetch_tip(name)
322 def get_the_completion_list(self, what, mode):
323 return self.autocomplete.fetch_completions(what, mode)
325 def stackviewer(self, flist_oid=None):
326 if self.usr_exc_info:
327 typ, val, tb = self.usr_exc_info
328 else:
329 return None
330 flist = None
331 if flist_oid is not None:
332 flist = self.rpchandler.get_remote_proxy(flist_oid)
333 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
334 tb = tb.tb_next
335 sys.last_type = typ
336 sys.last_value = val
337 item = StackViewer.StackTreeItem(flist, tb)
338 return RemoteObjectBrowser.remote_object_tree_item(item)