blob: 5c9c38197a1c31ab58b229d51814b7f5abf7e953 [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +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
Georg Brandl2067bfd2008-05-25 13:05:15 +00007import _thread as thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00008import threading
Alexandre Vassalottif260e442008-05-11 19:59:59 +00009import queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000010
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000011from idlelib import CallTips
12from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000013
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +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 Peterson206e3072008-10-19 14:07:49 +000028 def idle_formatwarning_subproc(message, category, filename, lineno,
Guilherme Polo1fff0082009-08-14 15:05:30 +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 Polo1fff0082009-08-14 15:05:30 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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. Kaisere67842a2009-04-04 20:13:23 +000073 try:
74 assert(len(sys.argv) > 1)
75 port = int(sys.argv[-1])
76 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +000077 print("IDLE Subprocess: no IP port passed in sys.argv.",
78 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000079 return
Chui Tey5d2af632002-05-26 13:36:41 +000080 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000081 sockthread = threading.Thread(target=manage_socket,
82 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000083 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000084 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000085 sockthread.start()
86 while 1:
87 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000088 if exit_now:
89 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000090 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000091 except KeyboardInterrupt:
92 # exiting but got an extra KBI? Try again!
93 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000094 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000095 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +000096 except queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000097 continue
98 method, args, kwargs = request
99 ret = method(*args, **kwargs)
100 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000101 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000102 if quitting:
103 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000104 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000105 except SystemExit:
106 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000107 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000108 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000109 try:
110 print_exception()
111 rpc.response_queue.put((seq, None))
112 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000113 # Link didn't work, print same exception to __stderr__
114 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000115 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000116 else:
117 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000118
119def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000120 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000121 time.sleep(i)
122 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000123 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000124 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000125 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000126 print("IDLE Subprocess: socket error: " + err.args[1] +
127 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000128 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000129 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000130 print("IDLE Subprocess: Connection to "
131 "IDLE GUI failed, exiting.", file=sys.__stderr__)
132 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000133 global exit_now
134 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000135 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000136 server.handle_request() # A single request only
137
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000138def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000139 import tkinter
140 import tkinter.messagebox as tkMessageBox
141 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000142 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000143 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000144 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
145 "to your personal firewall configuration. It is safe to "\
146 "allow this internal connection because no data is visible on "\
147 "external ports." % address
148 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
149 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000150 tkMessageBox.showerror("IDLE Subprocess Error",
151 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000152 root.destroy()
153
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000154def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000155 import linecache
156 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000157 flush_stdout()
158 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000159 typ, val, tb = excinfo = sys.exc_info()
160 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000161 tbe = traceback.extract_tb(tb)
Guido van Rossum33d26892007-08-05 15:29:28 +0000162 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000163 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000164 "RemoteDebugger.py", "bdb.py")
165 cleanup_traceback(tbe, exclude)
166 traceback.print_list(tbe, file=efile)
167 lines = traceback.format_exception_only(typ, val)
168 for line in lines:
Guido van Rossum33d26892007-08-05 15:29:28 +0000169 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000170
171def cleanup_traceback(tb, exclude):
172 "Remove excluded traces from beginning/end of tb; get cached lines"
173 orig_tb = tb[:]
174 while tb:
175 for rpcfile in exclude:
176 if tb[0][0].count(rpcfile):
177 break # found an exclude, break for: and delete tb[0]
178 else:
179 break # no excludes, have left RPC code, break while:
180 del tb[0]
181 while tb:
182 for rpcfile in exclude:
183 if tb[-1][0].count(rpcfile):
184 break
185 else:
186 break
187 del tb[-1]
188 if len(tb) == 0:
189 # exception was in IDLE internals, don't prune!
190 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000191 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000192 rpchandler = rpc.objecttable['exec'].rpchandler
193 for i in range(len(tb)):
194 fn, ln, nm, line = tb[i]
195 if nm == '?':
196 nm = "-toplevel-"
197 if not line and fn.startswith("<pyshell#"):
198 line = rpchandler.remotecall('linecache', 'getline',
199 (fn, ln), {})
200 tb[i] = fn, ln, nm, line
201
202def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000203 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000204
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000205def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000206 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000207
208 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000209 functions registered with atexit will be removed before exiting.
210 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000211
212 """
213 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000214 import atexit
215 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000216 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000217
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000218class MyRPCServer(rpc.RPCServer):
219
220 def handle_error(self, request, client_address):
221 """Override RPCServer method for IDLE
222
223 Interrupt the MainThread and exit server if link is dropped.
224
225 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000226 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000227 try:
228 raise
229 except SystemExit:
230 raise
231 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000232 global exit_now
233 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000234 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000235 except:
236 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000237 print('\n' + '-'*40, file=erf)
238 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000239 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000240 print('Client Address: ', client_address, file=erf)
241 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000242 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000243 print('\n*** Unrecoverable, server exiting!', file=erf)
244 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000245 quitting = True
246 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000247
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200248class _RPCFile(io.TextIOBase):
Martin v. Löwis1d0f6dd2012-07-09 20:52:40 +0200249 """Wrapper class for the RPC proxy to typecheck arguments
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200250 that may not support pickling."""
251
252 def __init__(self, rpc):
253 super.__setattr__(self, 'rpc', rpc)
254
255 def __getattr__(self, name):
256 return getattr(self.rpc, name)
257
258 def __setattr__(self, name, value):
259 return setattr(self.rpc, name, value)
260
261 def write(self, s):
262 if not isinstance(s, str):
263 raise TypeError('must be str, not ' + type(s).__name__)
264 return self.rpc.write(s)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000265
Chui Tey5d2af632002-05-26 13:36:41 +0000266class MyHandler(rpc.RPCHandler):
267
268 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000269 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000270 executive = Executive(self)
271 self.register("exec", executive)
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200272 sys.stdin = self.console = _RPCFile(self.get_remote_proxy("stdin"))
273 sys.stdout = _RPCFile(self.get_remote_proxy("stdout"))
274 sys.stderr = _RPCFile(self.get_remote_proxy("stderr"))
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000275 # page help() text to shell.
276 import pydoc # import must be done here to capture i/o binding
277 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000278 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000279 sys.stdin.encoding = sys.stdout.encoding = \
280 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000281 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000282 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
283
284 def exithook(self):
285 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000286 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000287
288 def EOFhook(self):
289 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000290 global quitting
291 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000292 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000293
294 def decode_interrupthook(self):
295 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000296 global quitting
297 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000298 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000299
Chui Tey5d2af632002-05-26 13:36:41 +0000300
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000301class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000302
303 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000304 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000305 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000306 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000307 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000308
309 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000310 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000311 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000312 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000313 interruptable = True
314 try:
315 exec(code, self.locals)
316 finally:
317 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000318 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000319 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000320 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000321 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000322 # even print a user code SystemExit exception, continue
323 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000324 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
325 if jit:
326 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000327 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000328 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000329
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000330 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000331 if interruptable:
332 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000333
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000334 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000335 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
336
337 def stop_the_debugger(self, idb_adap_oid):
338 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
339 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000340
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000341 def get_the_calltip(self, name):
342 return self.calltip.fetch_tip(name)
343
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000344 def get_the_completion_list(self, what, mode):
345 return self.autocomplete.fetch_completions(what, mode)
346
Chui Tey5d2af632002-05-26 13:36:41 +0000347 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000348 if self.usr_exc_info:
349 typ, val, tb = self.usr_exc_info
350 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000351 return None
352 flist = None
353 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000354 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000355 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
356 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000357 sys.last_type = typ
358 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000359 item = StackViewer.StackTreeItem(flist, tb)
360 return RemoteObjectBrowser.remote_object_tree_item(item)