blob: 7d0941e80b798c3f7c20173fda8342f3ab50c88f [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
Serhiy Storchaka39e70a42013-01-25 15:30:58 +020018from idlelib import PyShell
19from idlelib import IOBinding
Chui Tey5d2af632002-05-26 13:36:41 +000020
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000021import __main__
22
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000023LOCALHOST = '127.0.0.1'
24
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000025try:
26 import warnings
27except ImportError:
28 pass
29else:
Benjamin Peterson206e3072008-10-19 14:07:49 +000030 def idle_formatwarning_subproc(message, category, filename, lineno,
Guilherme Polo1fff0082009-08-14 15:05:30 +000031 line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000032 """Format warnings the IDLE way"""
33 s = "\nWarning (from warnings module):\n"
34 s += ' File \"%s\", line %s\n' % (filename, lineno)
Guilherme Polo1fff0082009-08-14 15:05:30 +000035 if line is None:
36 line = linecache.getline(filename, lineno)
37 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000038 if line:
39 s += " %s\n" % line
40 s += "%s: %s\n" % (category.__name__, message)
41 return s
42 warnings.formatwarning = idle_formatwarning_subproc
43
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000044# Thread shared globals: Establish a queue between a subthread (which handles
45# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000046# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000047
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000048exit_now = False
49quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +000050interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000051
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000052def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000053 """Start the Python execution server in a subprocess
54
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000055 In the Python subprocess, RPCServer is instantiated with handlerclass
56 MyHandler, which inherits register/unregister methods from RPCHandler via
57 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000058
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000059 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000060 creates an instance of run.MyHandler and calls its handle() method.
61 handle() instantiates a run.Executive object, passing it a reference to the
62 MyHandler object. That reference is saved as attribute rpchandler of the
63 Executive instance. The Executive methods have access to the reference and
64 can pass it on to entities that they command
65 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
66 call MyHandler(SocketIO) register/unregister methods via the reference to
67 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000068
69 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000070 global exit_now
71 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000072 global no_exitfunc
73 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000074 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000075 try:
76 assert(len(sys.argv) > 1)
77 port = int(sys.argv[-1])
78 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +000079 print("IDLE Subprocess: no IP port passed in sys.argv.",
80 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000081 return
Chui Tey5d2af632002-05-26 13:36:41 +000082 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000083 sockthread = threading.Thread(target=manage_socket,
84 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000085 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000086 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000087 sockthread.start()
88 while 1:
89 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000090 if exit_now:
91 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000092 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000093 except KeyboardInterrupt:
94 # exiting but got an extra KBI? Try again!
95 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000096 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000097 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +000098 except queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000099 continue
100 method, args, kwargs = request
101 ret = method(*args, **kwargs)
102 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000103 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000104 if quitting:
105 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000106 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000107 except SystemExit:
108 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000109 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000110 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000111 try:
112 print_exception()
113 rpc.response_queue.put((seq, None))
114 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000115 # Link didn't work, print same exception to __stderr__
116 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000117 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000118 else:
119 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000120
121def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000122 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000123 time.sleep(i)
124 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000125 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000126 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000127 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000128 print("IDLE Subprocess: socket error: " + err.args[1] +
129 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000130 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000131 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000132 print("IDLE Subprocess: Connection to "
133 "IDLE GUI failed, exiting.", file=sys.__stderr__)
134 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000135 global exit_now
136 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000137 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000138 server.handle_request() # A single request only
139
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000140def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000141 import tkinter
142 import tkinter.messagebox as tkMessageBox
143 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000144 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000145 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000146 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
147 "to your personal firewall configuration. It is safe to "\
148 "allow this internal connection because no data is visible on "\
149 "external ports." % address
150 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
151 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000152 tkMessageBox.showerror("IDLE Subprocess Error",
153 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000154 root.destroy()
155
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000156def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000157 import linecache
158 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000159 flush_stdout()
160 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000161 typ, val, tb = excinfo = sys.exc_info()
162 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200163 seen = set()
164
165 def print_exc(typ, exc, tb):
166 seen.add(exc)
167 context = exc.__context__
168 cause = exc.__cause__
169 if cause is not None and cause not in seen:
170 print_exc(type(cause), cause, cause.__traceback__)
171 print("\nThe above exception was the direct cause "
172 "of the following exception:\n", file=efile)
173 elif context is not None and context not in seen:
174 print_exc(type(context), context, context.__traceback__)
175 print("\nDuring handling of the above exception, "
176 "another exception occurred:\n", file=efile)
177 if tb:
178 tbe = traceback.extract_tb(tb)
179 print('Traceback (most recent call last):', file=efile)
180 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
181 "RemoteDebugger.py", "bdb.py")
182 cleanup_traceback(tbe, exclude)
183 traceback.print_list(tbe, file=efile)
184 lines = traceback.format_exception_only(typ, exc)
185 for line in lines:
186 print(line, end='', file=efile)
187
188 print_exc(typ, val, tb)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000189
190def cleanup_traceback(tb, exclude):
191 "Remove excluded traces from beginning/end of tb; get cached lines"
192 orig_tb = tb[:]
193 while tb:
194 for rpcfile in exclude:
195 if tb[0][0].count(rpcfile):
196 break # found an exclude, break for: and delete tb[0]
197 else:
198 break # no excludes, have left RPC code, break while:
199 del tb[0]
200 while tb:
201 for rpcfile in exclude:
202 if tb[-1][0].count(rpcfile):
203 break
204 else:
205 break
206 del tb[-1]
207 if len(tb) == 0:
208 # exception was in IDLE internals, don't prune!
209 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000210 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000211 rpchandler = rpc.objecttable['exec'].rpchandler
212 for i in range(len(tb)):
213 fn, ln, nm, line = tb[i]
214 if nm == '?':
215 nm = "-toplevel-"
216 if not line and fn.startswith("<pyshell#"):
217 line = rpchandler.remotecall('linecache', 'getline',
218 (fn, ln), {})
219 tb[i] = fn, ln, nm, line
220
221def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000222 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000223
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000224def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000225 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000226
227 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000228 functions registered with atexit will be removed before exiting.
229 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000230
231 """
232 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000233 import atexit
234 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000235 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000236
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000237class MyRPCServer(rpc.RPCServer):
238
239 def handle_error(self, request, client_address):
240 """Override RPCServer method for IDLE
241
242 Interrupt the MainThread and exit server if link is dropped.
243
244 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000245 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000246 try:
247 raise
248 except SystemExit:
249 raise
250 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000251 global exit_now
252 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000253 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000254 except:
255 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000256 print('\n' + '-'*40, file=erf)
257 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000258 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000259 print('Client Address: ', client_address, file=erf)
260 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000261 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000262 print('\n*** Unrecoverable, server exiting!', file=erf)
263 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000264 quitting = True
265 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000266
Chui Tey5d2af632002-05-26 13:36:41 +0000267class MyHandler(rpc.RPCHandler):
268
269 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000270 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000271 executive = Executive(self)
272 self.register("exec", executive)
Serhiy Storchaka39e70a42013-01-25 15:30:58 +0200273 self.console = self.get_remote_proxy("console")
274 sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
275 IOBinding.encoding)
276 sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
277 IOBinding.encoding)
278 sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
279 IOBinding.encoding)
280
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000281 # page help() text to shell.
282 import pydoc # import must be done here to capture i/o binding
283 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000284 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000285 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
286
287 def exithook(self):
288 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000289 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000290
291 def EOFhook(self):
292 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000293 global quitting
294 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000295 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000296
297 def decode_interrupthook(self):
298 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000299 global quitting
300 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000301 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000302
Chui Tey5d2af632002-05-26 13:36:41 +0000303
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000304class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000305
306 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000307 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000308 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000309 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000310 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000311
312 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000313 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000314 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000315 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000316 interruptable = True
317 try:
318 exec(code, self.locals)
319 finally:
320 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000321 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000322 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000323 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000324 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000325 # even print a user code SystemExit exception, continue
326 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000327 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
328 if jit:
329 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000330 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000331 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000332
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000333 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000334 if interruptable:
335 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000336
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000337 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000338 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
339
340 def stop_the_debugger(self, idb_adap_oid):
341 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
342 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000343
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000344 def get_the_calltip(self, name):
345 return self.calltip.fetch_tip(name)
346
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000347 def get_the_completion_list(self, what, mode):
348 return self.autocomplete.fetch_completions(what, mode)
349
Chui Tey5d2af632002-05-26 13:36:41 +0000350 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000351 if self.usr_exc_info:
352 typ, val, tb = self.usr_exc_info
353 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000354 return None
355 flist = None
356 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000357 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000358 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
359 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000360 sys.last_type = typ
361 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000362 item = StackViewer.StackTreeItem(flist, tb)
363 return RemoteObjectBrowser.remote_object_tree_item(item)