blob: 642b979d8b91c65eb4024ce5a0f2844037cf7adc [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
Florent Xiclunad630c042010-04-02 07:24:52 +000010from idlelib import CallTips
11from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000012
Florent Xiclunad630c042010-04-02 07:24:52 +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 Peterson9dc0a632008-10-15 21:05:55 +000027 def idle_formatwarning_subproc(message, category, filename, lineno,
Guilherme Polof198ac22009-08-14 14:03:07 +000028 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)
Guilherme Polof198ac22009-08-14 14:03:07 +000032 if line is None:
33 line = linecache.getline(filename, lineno)
34 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000035 if line:
36 s += " %s\n" % line
37 s += "%s: %s\n" % (category.__name__, message)
38 return s
39 warnings.formatwarning = idle_formatwarning_subproc
40
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000041# Thread shared globals: Establish a queue between a subthread (which handles
42# the socket) and the main thread (which runs user code), plus global
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000043# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000044
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000045exit_now = False
46quitting = False
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000047interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000048
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000049def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000050 """Start the Python execution server in a subprocess
51
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000052 In the Python subprocess, RPCServer is instantiated with handlerclass
53 MyHandler, which inherits register/unregister methods from RPCHandler via
54 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000055
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000056 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000057 creates an instance of run.MyHandler and calls its handle() method.
58 handle() instantiates a run.Executive object, passing it a reference to the
59 MyHandler object. That reference is saved as attribute rpchandler of the
60 Executive instance. The Executive methods have access to the reference and
61 can pass it on to entities that they command
62 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
63 call MyHandler(SocketIO) register/unregister methods via the reference to
64 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000065
66 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000067 global exit_now
68 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000069 global no_exitfunc
70 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000071 #time.sleep(15) # test subprocess not responding
Kurt B. Kaiser4724f402009-04-02 02:44:54 +000072 try:
73 assert(len(sys.argv) > 1)
74 port = int(sys.argv[-1])
75 except:
76 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
77 return
Chui Tey5d2af632002-05-26 13:36:41 +000078 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000079 sockthread = threading.Thread(target=manage_socket,
80 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000081 args=((LOCALHOST, port),))
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000082 sockthread.setDaemon(True)
83 sockthread.start()
84 while 1:
85 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000086 if exit_now:
87 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000088 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000089 except KeyboardInterrupt:
90 # exiting but got an extra KBI? Try again!
91 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000092 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000093 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Georg Brandla6168f92008-05-25 07:20:14 +000094 except Queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000095 continue
96 method, args, kwargs = request
97 ret = method(*args, **kwargs)
98 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000099 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000100 if quitting:
101 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000102 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000103 except SystemExit:
104 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000105 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000106 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000107 try:
108 print_exception()
109 rpc.response_queue.put((seq, None))
110 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000111 # Link didn't work, print same exception to __stderr__
112 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000113 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000114 else:
115 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000116
117def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000118 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000119 time.sleep(i)
120 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000121 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000122 break
123 except socket.error, err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000124 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
Florent Xiclunad630c042010-04-02 07:24:52 +0000125 + err.args[1] + ", retrying...."
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000126 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000127 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
128 "IDLE GUI failed, exiting."
129 show_socket_error(err, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000130 global exit_now
131 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000132 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000133 server.handle_request() # A single request only
134
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000135def show_socket_error(err, address):
Georg Brandl6634bf22008-05-20 07:13:37 +0000136 import Tkinter
137 import tkMessageBox
138 root = Tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000139 root.withdraw()
Florent Xiclunad630c042010-04-02 07:24:52 +0000140 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000141 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
142 "to your personal firewall configuration. It is safe to "\
143 "allow this internal connection because no data is visible on "\
144 "external ports." % address
145 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
146 else:
Florent Xiclunad630c042010-04-02 07:24:52 +0000147 tkMessageBox.showerror("IDLE Subprocess Error",
148 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000149 root.destroy()
150
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000151def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000152 import linecache
153 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000154 flush_stdout()
155 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000156 typ, val, tb = excinfo = sys.exc_info()
157 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000158 tbe = traceback.extract_tb(tb)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000159 print>>efile, '\nTraceback (most recent call last):'
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000160 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
161 "RemoteDebugger.py", "bdb.py")
162 cleanup_traceback(tbe, exclude)
163 traceback.print_list(tbe, file=efile)
164 lines = traceback.format_exception_only(typ, val)
165 for line in lines:
166 print>>efile, line,
167
168def cleanup_traceback(tb, exclude):
169 "Remove excluded traces from beginning/end of tb; get cached lines"
170 orig_tb = tb[:]
171 while tb:
172 for rpcfile in exclude:
173 if tb[0][0].count(rpcfile):
174 break # found an exclude, break for: and delete tb[0]
175 else:
176 break # no excludes, have left RPC code, break while:
177 del tb[0]
178 while tb:
179 for rpcfile in exclude:
180 if tb[-1][0].count(rpcfile):
181 break
182 else:
183 break
184 del tb[-1]
185 if len(tb) == 0:
186 # exception was in IDLE internals, don't prune!
187 tb[:] = orig_tb[:]
188 print>>sys.stderr, "** IDLE Internal Exception: "
189 rpchandler = rpc.objecttable['exec'].rpchandler
190 for i in range(len(tb)):
191 fn, ln, nm, line = tb[i]
192 if nm == '?':
193 nm = "-toplevel-"
194 if not line and fn.startswith("<pyshell#"):
195 line = rpchandler.remotecall('linecache', 'getline',
196 (fn, ln), {})
197 tb[i] = fn, ln, nm, line
198
199def flush_stdout():
200 try:
201 if sys.stdout.softspace:
202 sys.stdout.softspace = 0
203 sys.stdout.write("\n")
204 except (AttributeError, EOFError):
205 pass
206
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000207def exit():
208 """Exit subprocess, possibly after first deleting sys.exitfunc
209
210 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
211 sys.exitfunc will be removed before exiting. (VPython support)
212
213 """
214 if no_exitfunc:
Kurt B. Kaiserf30ba3d2008-01-23 22:55:26 +0000215 try:
216 del sys.exitfunc
217 except AttributeError:
218 pass
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000219 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000220
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000221class MyRPCServer(rpc.RPCServer):
222
223 def handle_error(self, request, client_address):
224 """Override RPCServer method for IDLE
225
226 Interrupt the MainThread and exit server if link is dropped.
227
228 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000229 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000230 try:
231 raise
232 except SystemExit:
233 raise
234 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000235 global exit_now
236 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000237 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000238 except:
239 erf = sys.__stderr__
240 print>>erf, '\n' + '-'*40
241 print>>erf, 'Unhandled server exception!'
242 print>>erf, 'Thread: %s' % threading.currentThread().getName()
243 print>>erf, 'Client Address: ', client_address
244 print>>erf, 'Request: ', repr(request)
245 traceback.print_exc(file=erf)
246 print>>erf, '\n*** Unrecoverable, server exiting!'
247 print>>erf, '-'*40
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000248 quitting = True
249 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000250
251
Chui Tey5d2af632002-05-26 13:36:41 +0000252class MyHandler(rpc.RPCHandler):
253
254 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000255 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000256 executive = Executive(self)
257 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000258 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000259 sys.stdout = self.get_remote_proxy("stdout")
260 sys.stderr = self.get_remote_proxy("stderr")
Florent Xiclunad630c042010-04-02 07:24:52 +0000261 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000262 sys.stdin.encoding = sys.stdout.encoding = \
263 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000264 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000265 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
266
267 def exithook(self):
268 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000269 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000270
271 def EOFhook(self):
272 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000273 global quitting
274 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000275 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000276
277 def decode_interrupthook(self):
278 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000279 global quitting
280 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000281 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000282
Chui Tey5d2af632002-05-26 13:36:41 +0000283
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000284class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000285
286 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000287 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000288 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000289 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000290 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000291
292 def runcode(self, code):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000293 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000294 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000295 self.usr_exc_info = None
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000296 interruptable = True
297 try:
298 exec code in self.locals
299 finally:
300 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000301 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000302 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000303 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000304 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000305 # even print a user code SystemExit exception, continue
306 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000307 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
308 if jit:
309 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000310 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000311 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000312
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000313 def interrupt_the_server(self):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000314 if interruptable:
315 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000316
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000317 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000318 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
319
320 def stop_the_debugger(self, idb_adap_oid):
321 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
322 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000323
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000324 def get_the_calltip(self, name):
325 return self.calltip.fetch_tip(name)
326
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000327 def get_the_completion_list(self, what, mode):
328 return self.autocomplete.fetch_completions(what, mode)
329
Chui Tey5d2af632002-05-26 13:36:41 +0000330 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000331 if self.usr_exc_info:
332 typ, val, tb = self.usr_exc_info
333 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000334 return None
335 flist = None
336 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000337 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000338 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
339 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000340 sys.last_type = typ
341 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000342 item = StackViewer.StackTreeItem(flist, tb)
343 return RemoteObjectBrowser.remote_object_tree_item(item)