blob: 5e12f7eeb1ef07209e70225676bdc95c8b55206a [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
Georg Brandl2067bfd2008-05-25 13:05:15 +00006import _thread as thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00007import threading
Alexandre Vassalottif260e442008-05-11 19:59:59 +00008import queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +00009
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000010from idlelib import CallTips
11from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000012
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +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 Peterson206e3072008-10-19 14:07:49 +000027 def idle_formatwarning_subproc(message, category, filename, lineno,
Guilherme Polo1fff0082009-08-14 15:05:30 +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 Polo1fff0082009-08-14 15:05:30 +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
Andrew Svetlova2251aa2012-03-13 18:36:13 -070041
42def handle_tk_events():
43 """Process any tk events that are ready to be dispatched if tkinter
44 has been imported, a tcl interpreter has been created and tk has been
45 loaded."""
46 tkinter = sys.modules.get('tkinter')
47 if tkinter and tkinter._default_root:
48 # tkinter has been imported, an Tcl interpreter was created and
49 # tk has been loaded.
50 root = tkinter._default_root
51 while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT):
52 # Process pending events.
53 pass
54
55
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000056# Thread shared globals: Establish a queue between a subthread (which handles
57# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000058# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000059
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000060exit_now = False
61quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +000062interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000063
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000064def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000065 """Start the Python execution server in a subprocess
66
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000067 In the Python subprocess, RPCServer is instantiated with handlerclass
68 MyHandler, which inherits register/unregister methods from RPCHandler via
69 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000070
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000071 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000072 creates an instance of run.MyHandler and calls its handle() method.
73 handle() instantiates a run.Executive object, passing it a reference to the
74 MyHandler object. That reference is saved as attribute rpchandler of the
75 Executive instance. The Executive methods have access to the reference and
76 can pass it on to entities that they command
77 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
78 call MyHandler(SocketIO) register/unregister methods via the reference to
79 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000080
81 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000082 global exit_now
83 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000084 global no_exitfunc
85 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000086 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000087 try:
88 assert(len(sys.argv) > 1)
89 port = int(sys.argv[-1])
90 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +000091 print("IDLE Subprocess: no IP port passed in sys.argv.",
92 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000093 return
Chui Tey5d2af632002-05-26 13:36:41 +000094 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000095 sockthread = threading.Thread(target=manage_socket,
96 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000097 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000098 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000099 sockthread.start()
100 while 1:
101 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000102 if exit_now:
103 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000104 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000105 except KeyboardInterrupt:
106 # exiting but got an extra KBI? Try again!
107 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000108 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +0000109 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +0000110 except queue.Empty:
Andrew Svetlova2251aa2012-03-13 18:36:13 -0700111 handle_tk_events()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000112 continue
113 method, args, kwargs = request
114 ret = method(*args, **kwargs)
115 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000116 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000117 if quitting:
118 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000119 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000120 except SystemExit:
121 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000122 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000123 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000124 try:
125 print_exception()
126 rpc.response_queue.put((seq, None))
127 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000128 # Link didn't work, print same exception to __stderr__
129 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000130 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000131 else:
132 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000133
134def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000135 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000136 time.sleep(i)
137 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000138 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000139 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000140 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000141 print("IDLE Subprocess: socket error: " + err.args[1] +
142 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000143 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000144 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000145 print("IDLE Subprocess: Connection to "
146 "IDLE GUI failed, exiting.", file=sys.__stderr__)
147 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000148 global exit_now
149 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000150 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000151 server.handle_request() # A single request only
152
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000153def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000154 import tkinter
155 import tkinter.messagebox as tkMessageBox
156 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000157 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000158 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000159 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
160 "to your personal firewall configuration. It is safe to "\
161 "allow this internal connection because no data is visible on "\
162 "external ports." % address
163 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
164 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000165 tkMessageBox.showerror("IDLE Subprocess Error",
166 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000167 root.destroy()
168
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000169def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000170 import linecache
171 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000172 flush_stdout()
173 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000174 typ, val, tb = excinfo = sys.exc_info()
175 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000176 tbe = traceback.extract_tb(tb)
Guido van Rossum33d26892007-08-05 15:29:28 +0000177 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000178 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000179 "RemoteDebugger.py", "bdb.py")
180 cleanup_traceback(tbe, exclude)
181 traceback.print_list(tbe, file=efile)
182 lines = traceback.format_exception_only(typ, val)
183 for line in lines:
Guido van Rossum33d26892007-08-05 15:29:28 +0000184 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000185
186def cleanup_traceback(tb, exclude):
187 "Remove excluded traces from beginning/end of tb; get cached lines"
188 orig_tb = tb[:]
189 while tb:
190 for rpcfile in exclude:
191 if tb[0][0].count(rpcfile):
192 break # found an exclude, break for: and delete tb[0]
193 else:
194 break # no excludes, have left RPC code, break while:
195 del tb[0]
196 while tb:
197 for rpcfile in exclude:
198 if tb[-1][0].count(rpcfile):
199 break
200 else:
201 break
202 del tb[-1]
203 if len(tb) == 0:
204 # exception was in IDLE internals, don't prune!
205 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000206 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000207 rpchandler = rpc.objecttable['exec'].rpchandler
208 for i in range(len(tb)):
209 fn, ln, nm, line = tb[i]
210 if nm == '?':
211 nm = "-toplevel-"
212 if not line and fn.startswith("<pyshell#"):
213 line = rpchandler.remotecall('linecache', 'getline',
214 (fn, ln), {})
215 tb[i] = fn, ln, nm, line
216
217def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000218 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000219
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000220def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000221 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000222
223 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000224 functions registered with atexit will be removed before exiting.
225 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000226
227 """
228 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000229 import atexit
230 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000231 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000232
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000233class MyRPCServer(rpc.RPCServer):
234
235 def handle_error(self, request, client_address):
236 """Override RPCServer method for IDLE
237
238 Interrupt the MainThread and exit server if link is dropped.
239
240 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000241 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000242 try:
243 raise
244 except SystemExit:
245 raise
246 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000247 global exit_now
248 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000249 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000250 except:
251 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000252 print('\n' + '-'*40, file=erf)
253 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000254 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000255 print('Client Address: ', client_address, file=erf)
256 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000257 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000258 print('\n*** Unrecoverable, server exiting!', file=erf)
259 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000260 quitting = True
261 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000262
263
Chui Tey5d2af632002-05-26 13:36:41 +0000264class MyHandler(rpc.RPCHandler):
265
266 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000267 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000268 executive = Executive(self)
269 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000270 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000271 sys.stdout = self.get_remote_proxy("stdout")
272 sys.stderr = self.get_remote_proxy("stderr")
Andrew Svetlovcd49d532012-03-25 11:43:02 +0300273 sys.displayhook = rpc.displayhook
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000274 # page help() text to shell.
275 import pydoc # import must be done here to capture i/o binding
276 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000277 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000278 sys.stdin.encoding = sys.stdout.encoding = \
279 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000280 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000281 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
282
283 def exithook(self):
284 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000285 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000286
287 def EOFhook(self):
288 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000289 global quitting
290 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000291 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000292
293 def decode_interrupthook(self):
294 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000295 global quitting
296 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000297 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000298
Chui Tey5d2af632002-05-26 13:36:41 +0000299
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000300class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000301
302 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000303 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000304 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000305 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000306 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000307
308 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000309 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000310 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000311 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000312 interruptable = True
313 try:
314 exec(code, self.locals)
315 finally:
316 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000317 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000318 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000319 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000320 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000321 # even print a user code SystemExit exception, continue
322 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000323 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
324 if jit:
325 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000326 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000327 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000328
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000329 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000330 if interruptable:
331 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000332
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000333 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000334 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
335
336 def stop_the_debugger(self, idb_adap_oid):
337 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
338 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000339
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000340 def get_the_calltip(self, name):
341 return self.calltip.fetch_tip(name)
342
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000343 def get_the_completion_list(self, what, mode):
344 return self.autocomplete.fetch_completions(what, mode)
345
Chui Tey5d2af632002-05-26 13:36:41 +0000346 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000347 if self.usr_exc_info:
348 typ, val, tb = self.usr_exc_info
349 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000350 return None
351 flist = None
352 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000353 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000354 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
355 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000356 sys.last_type = typ
357 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000358 item = StackViewer.StackTreeItem(flist, tb)
359 return RemoteObjectBrowser.remote_object_tree_item(item)