blob: 8e9037044fa25fb3968d789b1aef39ee320de4ba [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Martin v. Löwise8e4e142012-07-09 21:01:49 +02002import io
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +00003import linecache
Kurt B. Kaiserb4179362002-07-26 00:06:42 +00004import time
5import socket
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +00006import traceback
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +00007import thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00008import threading
Georg Brandla6168f92008-05-25 07:20:14 +00009import Queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000010
Florent Xiclunad630c042010-04-02 07:24:52 +000011from idlelib import CallTips
12from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000013
Florent Xiclunad630c042010-04-02 07:24:52 +000014from idlelib import RemoteDebugger
15from idlelib import RemoteObjectBrowser
16from idlelib import StackViewer
17from idlelib import rpc
Chui Tey5d2af632002-05-26 13:36:41 +000018
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000019import __main__
20
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000021LOCALHOST = '127.0.0.1'
22
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000023try:
24 import warnings
25except ImportError:
26 pass
27else:
Benjamin Peterson9dc0a632008-10-15 21:05:55 +000028 def idle_formatwarning_subproc(message, category, filename, lineno,
Guilherme Polof198ac22009-08-14 14:03:07 +000029 line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000030 """Format warnings the IDLE way"""
31 s = "\nWarning (from warnings module):\n"
32 s += ' File \"%s\", line %s\n' % (filename, lineno)
Guilherme Polof198ac22009-08-14 14:03:07 +000033 if line is None:
34 line = linecache.getline(filename, lineno)
35 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000036 if line:
37 s += " %s\n" % line
38 s += "%s: %s\n" % (category.__name__, message)
39 return s
40 warnings.formatwarning = idle_formatwarning_subproc
41
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000042# Thread shared globals: Establish a queue between a subthread (which handles
43# the socket) and the main thread (which runs user code), plus global
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000044# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000045
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000046exit_now = False
47quitting = False
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000048interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000049
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000050def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000051 """Start the Python execution server in a subprocess
52
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000053 In the Python subprocess, RPCServer is instantiated with handlerclass
54 MyHandler, which inherits register/unregister methods from RPCHandler via
55 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000056
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000057 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000058 creates an instance of run.MyHandler and calls its handle() method.
59 handle() instantiates a run.Executive object, passing it a reference to the
60 MyHandler object. That reference is saved as attribute rpchandler of the
61 Executive instance. The Executive methods have access to the reference and
62 can pass it on to entities that they command
63 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
64 call MyHandler(SocketIO) register/unregister methods via the reference to
65 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000066
67 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000068 global exit_now
69 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000070 global no_exitfunc
71 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000072 #time.sleep(15) # test subprocess not responding
Kurt B. Kaiser4724f402009-04-02 02:44:54 +000073 try:
74 assert(len(sys.argv) > 1)
75 port = int(sys.argv[-1])
76 except:
77 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
78 return
Chui Tey5d2af632002-05-26 13:36:41 +000079 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000080 sockthread = threading.Thread(target=manage_socket,
81 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000082 args=((LOCALHOST, port),))
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000083 sockthread.setDaemon(True)
84 sockthread.start()
85 while 1:
86 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000087 if exit_now:
88 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000089 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000090 except KeyboardInterrupt:
91 # exiting but got an extra KBI? Try again!
92 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000093 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000094 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Georg Brandla6168f92008-05-25 07:20:14 +000095 except Queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000096 continue
97 method, args, kwargs = request
98 ret = method(*args, **kwargs)
99 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000100 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000101 if quitting:
102 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000103 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000104 except SystemExit:
105 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000106 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000107 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000108 try:
109 print_exception()
110 rpc.response_queue.put((seq, None))
111 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000112 # Link didn't work, print same exception to __stderr__
113 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000114 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000115 else:
116 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000117
118def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000119 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000120 time.sleep(i)
121 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000122 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000123 break
124 except socket.error, err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000125 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
Florent Xiclunad630c042010-04-02 07:24:52 +0000126 + err.args[1] + ", retrying...."
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000127 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000128 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
129 "IDLE GUI failed, exiting."
130 show_socket_error(err, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000131 global exit_now
132 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000133 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000134 server.handle_request() # A single request only
135
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000136def show_socket_error(err, address):
Georg Brandl6634bf22008-05-20 07:13:37 +0000137 import Tkinter
138 import tkMessageBox
139 root = Tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000140 root.withdraw()
Florent Xiclunad630c042010-04-02 07:24:52 +0000141 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000142 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
143 "to your personal firewall configuration. It is safe to "\
144 "allow this internal connection because no data is visible on "\
145 "external ports." % address
146 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
147 else:
Florent Xiclunad630c042010-04-02 07:24:52 +0000148 tkMessageBox.showerror("IDLE Subprocess Error",
149 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000150 root.destroy()
151
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000152def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000153 import linecache
154 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000155 flush_stdout()
156 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000157 typ, val, tb = excinfo = sys.exc_info()
158 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000159 tbe = traceback.extract_tb(tb)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000160 print>>efile, '\nTraceback (most recent call last):'
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000161 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
162 "RemoteDebugger.py", "bdb.py")
163 cleanup_traceback(tbe, exclude)
164 traceback.print_list(tbe, file=efile)
165 lines = traceback.format_exception_only(typ, val)
166 for line in lines:
167 print>>efile, line,
168
169def cleanup_traceback(tb, exclude):
170 "Remove excluded traces from beginning/end of tb; get cached lines"
171 orig_tb = tb[:]
172 while tb:
173 for rpcfile in exclude:
174 if tb[0][0].count(rpcfile):
175 break # found an exclude, break for: and delete tb[0]
176 else:
177 break # no excludes, have left RPC code, break while:
178 del tb[0]
179 while tb:
180 for rpcfile in exclude:
181 if tb[-1][0].count(rpcfile):
182 break
183 else:
184 break
185 del tb[-1]
186 if len(tb) == 0:
187 # exception was in IDLE internals, don't prune!
188 tb[:] = orig_tb[:]
189 print>>sys.stderr, "** IDLE Internal Exception: "
190 rpchandler = rpc.objecttable['exec'].rpchandler
191 for i in range(len(tb)):
192 fn, ln, nm, line = tb[i]
193 if nm == '?':
194 nm = "-toplevel-"
195 if not line and fn.startswith("<pyshell#"):
196 line = rpchandler.remotecall('linecache', 'getline',
197 (fn, ln), {})
198 tb[i] = fn, ln, nm, line
199
200def flush_stdout():
201 try:
202 if sys.stdout.softspace:
203 sys.stdout.softspace = 0
204 sys.stdout.write("\n")
205 except (AttributeError, EOFError):
206 pass
207
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000208def exit():
209 """Exit subprocess, possibly after first deleting sys.exitfunc
210
211 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
212 sys.exitfunc will be removed before exiting. (VPython support)
213
214 """
215 if no_exitfunc:
Kurt B. Kaiserf30ba3d2008-01-23 22:55:26 +0000216 try:
217 del sys.exitfunc
218 except AttributeError:
219 pass
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000220 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000221
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000222class MyRPCServer(rpc.RPCServer):
223
224 def handle_error(self, request, client_address):
225 """Override RPCServer method for IDLE
226
227 Interrupt the MainThread and exit server if link is dropped.
228
229 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000230 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000231 try:
232 raise
233 except SystemExit:
234 raise
235 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000236 global exit_now
237 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000238 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000239 except:
240 erf = sys.__stderr__
241 print>>erf, '\n' + '-'*40
242 print>>erf, 'Unhandled server exception!'
243 print>>erf, 'Thread: %s' % threading.currentThread().getName()
244 print>>erf, 'Client Address: ', client_address
245 print>>erf, 'Request: ', repr(request)
246 traceback.print_exc(file=erf)
247 print>>erf, '\n*** Unrecoverable, server exiting!'
248 print>>erf, '-'*40
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000249 quitting = True
250 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000251
Martin v. Löwise8e4e142012-07-09 21:01:49 +0200252class _RPCFile(io.TextIOBase):
253 """Wrapper class for the RPC proxy to typecheck arguments
Martin v. Löwis1ba32182012-07-11 08:49:58 +0200254 that may not support pickling. The base class is there only
255 to support type tests; all implementations come from the remote
256 object."""
Martin v. Löwise8e4e142012-07-09 21:01:49 +0200257
258 def __init__(self, rpc):
259 super.__setattr__(self, 'rpc', rpc)
260
Martin v. Löwis1ba32182012-07-11 08:49:58 +0200261 def __getattribute__(self, name):
Martin v. Löwis3e0cc0f2012-07-11 09:19:16 +0200262 # When accessing the 'rpc' attribute, or 'write', use ours
Martin v. Löwise2b56242012-07-25 10:56:22 +0200263 if name in ('rpc', 'write', 'writelines'):
Martin v. Löwis1ba32182012-07-11 08:49:58 +0200264 return io.TextIOBase.__getattribute__(self, name)
265 # Else only look into the remote object only
Martin v. Löwise8e4e142012-07-09 21:01:49 +0200266 return getattr(self.rpc, name)
267
268 def __setattr__(self, name, value):
269 return setattr(self.rpc, name, value)
270
Martin v. Löwise2b56242012-07-25 10:56:22 +0200271 @staticmethod
272 def _ensure_string(func):
273 def f(self, s):
274 if not isinstance(s, basestring):
275 raise TypeError('must be str, not ' + type(s).__name__)
276 return func(self, s)
277 return f
278
279class _RPCOutputFile(_RPCFile):
280 @_RPCFile._ensure_string
Martin v. Löwise8e4e142012-07-09 21:01:49 +0200281 def write(self, s):
Martin v. Löwise8e4e142012-07-09 21:01:49 +0200282 return self.rpc.write(s)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000283
Martin v. Löwise2b56242012-07-25 10:56:22 +0200284class _RPCInputFile(_RPCFile):
285 @_RPCFile._ensure_string
286 def write(self, s):
287 raise io.UnsupportedOperation("not writable")
288 writelines = write
289
Chui Tey5d2af632002-05-26 13:36:41 +0000290class MyHandler(rpc.RPCHandler):
291
292 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000293 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000294 executive = Executive(self)
295 self.register("exec", executive)
Martin v. Löwise2b56242012-07-25 10:56:22 +0200296 self.console = self.get_remote_proxy("stdin")
297 sys.stdin = _RPCInputFile(self.console)
298 sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout"))
299 sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr"))
Florent Xiclunad630c042010-04-02 07:24:52 +0000300 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000301 sys.stdin.encoding = sys.stdout.encoding = \
302 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000303 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000304 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
305
306 def exithook(self):
307 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000308 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000309
310 def EOFhook(self):
311 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000312 global quitting
313 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000314 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000315
316 def decode_interrupthook(self):
317 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000318 global quitting
319 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000320 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000321
Chui Tey5d2af632002-05-26 13:36:41 +0000322
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000323class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000324
325 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000326 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000327 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000328 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000329 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000330
331 def runcode(self, code):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000332 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000333 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000334 self.usr_exc_info = None
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000335 interruptable = True
336 try:
337 exec code in self.locals
338 finally:
339 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000340 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000341 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000342 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000343 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000344 # even print a user code SystemExit exception, continue
345 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000346 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
347 if jit:
348 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000349 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000350 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000351
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000352 def interrupt_the_server(self):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000353 if interruptable:
354 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000355
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000356 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000357 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
358
359 def stop_the_debugger(self, idb_adap_oid):
360 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
361 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000362
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000363 def get_the_calltip(self, name):
364 return self.calltip.fetch_tip(name)
365
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000366 def get_the_completion_list(self, what, mode):
367 return self.autocomplete.fetch_completions(what, mode)
368
Chui Tey5d2af632002-05-26 13:36:41 +0000369 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000370 if self.usr_exc_info:
371 typ, val, tb = self.usr_exc_info
372 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000373 return None
374 flist = None
375 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000376 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000377 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
378 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000379 sys.last_type = typ
380 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000381 item = StackViewer.StackTreeItem(flist, tb)
382 return RemoteObjectBrowser.remote_object_tree_item(item)