blob: 270ea15d6db9bd1e6f23c9cb6a48059155e6b0b4 [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +00002import linecache
Kurt B. Kaiserb4179362002-07-26 00:06:42 +00003import time
4import socket
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +00005import traceback
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +00006import thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00007import threading
Georg Brandla6168f92008-05-25 07:20:14 +00008import Queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +00009
Ezio Melotti4c6daf12010-08-02 20:40:20 +000010from idlelib import CallTips
11from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000012
Ezio Melotti4c6daf12010-08-02 20:40:20 +000013from idlelib import RemoteDebugger
14from idlelib import RemoteObjectBrowser
15from idlelib import StackViewer
16from idlelib import rpc
Chui Tey5d2af632002-05-26 13:36:41 +000017
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000018import __main__
19
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000020LOCALHOST = '127.0.0.1'
21
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000022try:
23 import warnings
24except ImportError:
25 pass
26else:
Benjamin Peterson352ebae2008-10-16 19:46:25 +000027 def idle_formatwarning_subproc(message, category, filename, lineno,
28 file=None, line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000029 """Format warnings the IDLE way"""
30 s = "\nWarning (from warnings module):\n"
31 s += ' File \"%s\", line %s\n' % (filename, lineno)
Benjamin Peterson352ebae2008-10-16 19:46:25 +000032 line = linecache.getline(filename, lineno).strip() \
33 if line is None else line
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000034 if line:
35 s += " %s\n" % line
36 s += "%s: %s\n" % (category.__name__, message)
37 return s
38 warnings.formatwarning = idle_formatwarning_subproc
39
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000040# Thread shared globals: Establish a queue between a subthread (which handles
41# the socket) and the main thread (which runs user code), plus global
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000042# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000043
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000044exit_now = False
45quitting = False
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000046interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000047
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000048def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000049 """Start the Python execution server in a subprocess
50
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000051 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.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000054
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000055 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000056 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.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000064
65 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000066 global exit_now
67 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000068 global no_exitfunc
69 no_exitfunc = del_exitfunc
Chui Tey5d2af632002-05-26 13:36:41 +000070 port = 8833
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000071 #time.sleep(15) # test subprocess not responding
Chui Tey5d2af632002-05-26 13:36:41 +000072 if sys.argv[1:]:
73 port = int(sys.argv[1])
74 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000075 sockthread = threading.Thread(target=manage_socket,
76 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000077 args=((LOCALHOST, port),))
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000078 sockthread.setDaemon(True)
79 sockthread.start()
80 while 1:
81 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000082 if exit_now:
83 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000084 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000085 except KeyboardInterrupt:
86 # exiting but got an extra KBI? Try again!
87 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000088 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000089 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Georg Brandla6168f92008-05-25 07:20:14 +000090 except Queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000091 continue
92 method, args, kwargs = request
93 ret = method(*args, **kwargs)
94 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000095 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000096 if quitting:
97 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000098 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +000099 except SystemExit:
100 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000101 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000102 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000103 try:
104 print_exception()
105 rpc.response_queue.put((seq, None))
106 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000107 # Link didn't work, print same exception to __stderr__
108 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000109 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000110 else:
111 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000112
113def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000114 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000115 time.sleep(i)
116 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000117 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000118 break
119 except socket.error, err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000120 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
Ezio Melotti4c6daf12010-08-02 20:40:20 +0000121 + err.args[1] + ", retrying...."
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000122 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000123 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
124 "IDLE GUI failed, exiting."
125 show_socket_error(err, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000126 global exit_now
127 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000128 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000129 server.handle_request() # A single request only
130
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000131def show_socket_error(err, address):
Georg Brandl6634bf22008-05-20 07:13:37 +0000132 import Tkinter
133 import tkMessageBox
134 root = Tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000135 root.withdraw()
Ezio Melotti4c6daf12010-08-02 20:40:20 +0000136 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000137 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:
Ezio Melotti4c6daf12010-08-02 20:40:20 +0000143 tkMessageBox.showerror("IDLE Subprocess Error",
144 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000145 root.destroy()
146
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000147def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000148 import linecache
149 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000150 flush_stdout()
151 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000152 typ, val, tb = excinfo = sys.exc_info()
153 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000154 tbe = traceback.extract_tb(tb)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000155 print>>efile, '\nTraceback (most recent call last):'
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000156 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
157 "RemoteDebugger.py", "bdb.py")
158 cleanup_traceback(tbe, exclude)
159 traceback.print_list(tbe, file=efile)
160 lines = traceback.format_exception_only(typ, val)
161 for line in lines:
162 print>>efile, line,
163
164def cleanup_traceback(tb, exclude):
165 "Remove excluded traces from beginning/end of tb; get cached lines"
166 orig_tb = tb[:]
167 while tb:
168 for rpcfile in exclude:
169 if tb[0][0].count(rpcfile):
170 break # found an exclude, break for: and delete tb[0]
171 else:
172 break # no excludes, have left RPC code, break while:
173 del tb[0]
174 while tb:
175 for rpcfile in exclude:
176 if tb[-1][0].count(rpcfile):
177 break
178 else:
179 break
180 del tb[-1]
181 if len(tb) == 0:
182 # exception was in IDLE internals, don't prune!
183 tb[:] = orig_tb[:]
184 print>>sys.stderr, "** IDLE Internal Exception: "
185 rpchandler = rpc.objecttable['exec'].rpchandler
186 for i in range(len(tb)):
187 fn, ln, nm, line = tb[i]
188 if nm == '?':
189 nm = "-toplevel-"
190 if not line and fn.startswith("<pyshell#"):
191 line = rpchandler.remotecall('linecache', 'getline',
192 (fn, ln), {})
193 tb[i] = fn, ln, nm, line
194
195def flush_stdout():
196 try:
197 if sys.stdout.softspace:
198 sys.stdout.softspace = 0
199 sys.stdout.write("\n")
200 except (AttributeError, EOFError):
201 pass
202
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000203def exit():
204 """Exit subprocess, possibly after first deleting sys.exitfunc
205
206 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
207 sys.exitfunc will be removed before exiting. (VPython support)
208
209 """
210 if no_exitfunc:
Kurt B. Kaiserf30ba3d2008-01-23 22:55:26 +0000211 try:
212 del sys.exitfunc
213 except AttributeError:
214 pass
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000215 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000216
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000217class MyRPCServer(rpc.RPCServer):
218
219 def handle_error(self, request, client_address):
220 """Override RPCServer method for IDLE
221
222 Interrupt the MainThread and exit server if link is dropped.
223
224 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000225 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000226 try:
227 raise
228 except SystemExit:
229 raise
230 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000231 global exit_now
232 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000233 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000234 except:
235 erf = sys.__stderr__
236 print>>erf, '\n' + '-'*40
237 print>>erf, 'Unhandled server exception!'
238 print>>erf, 'Thread: %s' % threading.currentThread().getName()
239 print>>erf, 'Client Address: ', client_address
240 print>>erf, 'Request: ', repr(request)
241 traceback.print_exc(file=erf)
242 print>>erf, '\n*** Unrecoverable, server exiting!'
243 print>>erf, '-'*40
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000244 quitting = True
245 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000246
247
Chui Tey5d2af632002-05-26 13:36:41 +0000248class MyHandler(rpc.RPCHandler):
249
250 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000251 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000252 executive = Executive(self)
253 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000254 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000255 sys.stdout = self.get_remote_proxy("stdout")
256 sys.stderr = self.get_remote_proxy("stderr")
Ezio Melotti4c6daf12010-08-02 20:40:20 +0000257 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000258 sys.stdin.encoding = sys.stdout.encoding = \
259 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000260 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000261 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
262
263 def exithook(self):
264 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000265 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000266
267 def EOFhook(self):
268 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000269 global quitting
270 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000271 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000272
273 def decode_interrupthook(self):
274 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000275 global quitting
276 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000277 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000278
Chui Tey5d2af632002-05-26 13:36:41 +0000279
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000280class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000281
282 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000283 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000284 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000285 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000286 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000287
288 def runcode(self, code):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000289 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000290 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000291 self.usr_exc_info = None
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000292 interruptable = True
293 try:
294 exec code in self.locals
295 finally:
296 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000297 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000298 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000299 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000300 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000301 # even print a user code SystemExit exception, continue
302 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000303 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
304 if jit:
305 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000306 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000307 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000308
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000309 def interrupt_the_server(self):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000310 if interruptable:
311 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000312
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000313 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000314 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
315
316 def stop_the_debugger(self, idb_adap_oid):
317 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
318 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000319
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000320 def get_the_calltip(self, name):
321 return self.calltip.fetch_tip(name)
322
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000323 def get_the_completion_list(self, what, mode):
324 return self.autocomplete.fetch_completions(what, mode)
325
Chui Tey5d2af632002-05-26 13:36:41 +0000326 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000327 if self.usr_exc_info:
328 typ, val, tb = self.usr_exc_info
329 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000330 return None
331 flist = None
332 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000333 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000334 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
335 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000336 sys.last_type = typ
337 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000338 item = StackViewer.StackTreeItem(flist, tb)
339 return RemoteObjectBrowser.remote_object_tree_item(item)