blob: 7124c72a639118f15066d769de61f16044098a1e [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
Andrew Svetlov753445a2012-03-26 21:56:44 +03009import tkinter
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
Andrew Svetlova2251aa2012-03-13 18:36:13 -070042
Andrew Svetlov753445a2012-03-26 21:56:44 +030043tcl = tkinter.Tcl()
44
45
46def handle_tk_events(tcl=tcl):
Andrew Svetlova2251aa2012-03-13 18:36:13 -070047 """Process any tk events that are ready to be dispatched if tkinter
48 has been imported, a tcl interpreter has been created and tk has been
49 loaded."""
Andrew Svetlov753445a2012-03-26 21:56:44 +030050 tcl.eval("update")
Andrew Svetlova2251aa2012-03-13 18:36:13 -070051
52
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000053# Thread shared globals: Establish a queue between a subthread (which handles
54# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000055# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000056
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000057exit_now = False
58quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +000059interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000060
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000061def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000062 """Start the Python execution server in a subprocess
63
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000064 In the Python subprocess, RPCServer is instantiated with handlerclass
65 MyHandler, which inherits register/unregister methods from RPCHandler via
66 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000067
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000068 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000069 creates an instance of run.MyHandler and calls its handle() method.
70 handle() instantiates a run.Executive object, passing it a reference to the
71 MyHandler object. That reference is saved as attribute rpchandler of the
72 Executive instance. The Executive methods have access to the reference and
73 can pass it on to entities that they command
74 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
75 call MyHandler(SocketIO) register/unregister methods via the reference to
76 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000077
78 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000079 global exit_now
80 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000081 global no_exitfunc
82 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000083 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000084 try:
85 assert(len(sys.argv) > 1)
86 port = int(sys.argv[-1])
87 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +000088 print("IDLE Subprocess: no IP port passed in sys.argv.",
89 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000090 return
Chui Tey5d2af632002-05-26 13:36:41 +000091 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000092 sockthread = threading.Thread(target=manage_socket,
93 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000094 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000095 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000096 sockthread.start()
97 while 1:
98 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000099 if exit_now:
100 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000101 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000102 except KeyboardInterrupt:
103 # exiting but got an extra KBI? Try again!
104 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000105 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +0000106 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +0000107 except queue.Empty:
Andrew Svetlova2251aa2012-03-13 18:36:13 -0700108 handle_tk_events()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000109 continue
110 method, args, kwargs = request
111 ret = method(*args, **kwargs)
112 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000113 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000114 if quitting:
115 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000116 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000117 except SystemExit:
118 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000119 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000120 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000121 try:
122 print_exception()
123 rpc.response_queue.put((seq, None))
124 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000125 # Link didn't work, print same exception to __stderr__
126 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000127 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000128 else:
129 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000130
131def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000132 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000133 time.sleep(i)
134 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000135 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000136 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000137 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000138 print("IDLE Subprocess: socket error: " + err.args[1] +
139 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000140 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000141 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000142 print("IDLE Subprocess: Connection to "
143 "IDLE GUI failed, exiting.", file=sys.__stderr__)
144 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000145 global exit_now
146 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000147 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000148 server.handle_request() # A single request only
149
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000150def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000151 import tkinter
152 import tkinter.messagebox as tkMessageBox
153 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000154 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000155 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000156 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
157 "to your personal firewall configuration. It is safe to "\
158 "allow this internal connection because no data is visible on "\
159 "external ports." % address
160 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
161 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000162 tkMessageBox.showerror("IDLE Subprocess Error",
163 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000164 root.destroy()
165
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000166def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000167 import linecache
168 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000169 flush_stdout()
170 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000171 typ, val, tb = excinfo = sys.exc_info()
172 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000173 tbe = traceback.extract_tb(tb)
Guido van Rossum33d26892007-08-05 15:29:28 +0000174 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000175 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000176 "RemoteDebugger.py", "bdb.py")
177 cleanup_traceback(tbe, exclude)
178 traceback.print_list(tbe, file=efile)
179 lines = traceback.format_exception_only(typ, val)
180 for line in lines:
Guido van Rossum33d26892007-08-05 15:29:28 +0000181 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000182
183def cleanup_traceback(tb, exclude):
184 "Remove excluded traces from beginning/end of tb; get cached lines"
185 orig_tb = tb[:]
186 while tb:
187 for rpcfile in exclude:
188 if tb[0][0].count(rpcfile):
189 break # found an exclude, break for: and delete tb[0]
190 else:
191 break # no excludes, have left RPC code, break while:
192 del tb[0]
193 while tb:
194 for rpcfile in exclude:
195 if tb[-1][0].count(rpcfile):
196 break
197 else:
198 break
199 del tb[-1]
200 if len(tb) == 0:
201 # exception was in IDLE internals, don't prune!
202 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000203 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000204 rpchandler = rpc.objecttable['exec'].rpchandler
205 for i in range(len(tb)):
206 fn, ln, nm, line = tb[i]
207 if nm == '?':
208 nm = "-toplevel-"
209 if not line and fn.startswith("<pyshell#"):
210 line = rpchandler.remotecall('linecache', 'getline',
211 (fn, ln), {})
212 tb[i] = fn, ln, nm, line
213
214def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000215 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000216
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000217def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000218 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000219
220 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000221 functions registered with atexit will be removed before exiting.
222 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000223
224 """
225 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000226 import atexit
227 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000228 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000229
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000230class MyRPCServer(rpc.RPCServer):
231
232 def handle_error(self, request, client_address):
233 """Override RPCServer method for IDLE
234
235 Interrupt the MainThread and exit server if link is dropped.
236
237 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000238 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000239 try:
240 raise
241 except SystemExit:
242 raise
243 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000244 global exit_now
245 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000246 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000247 except:
248 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000249 print('\n' + '-'*40, file=erf)
250 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000251 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000252 print('Client Address: ', client_address, file=erf)
253 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000254 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000255 print('\n*** Unrecoverable, server exiting!', file=erf)
256 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000257 quitting = True
258 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000259
260
Chui Tey5d2af632002-05-26 13:36:41 +0000261class MyHandler(rpc.RPCHandler):
262
263 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000264 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000265 executive = Executive(self)
266 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000267 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000268 sys.stdout = self.get_remote_proxy("stdout")
269 sys.stderr = self.get_remote_proxy("stderr")
Andrew Svetlovcd49d532012-03-25 11:43:02 +0300270 sys.displayhook = rpc.displayhook
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000271 # page help() text to shell.
272 import pydoc # import must be done here to capture i/o binding
273 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000274 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000275 sys.stdin.encoding = sys.stdout.encoding = \
276 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000277 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000278 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
279
280 def exithook(self):
281 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000282 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000283
284 def EOFhook(self):
285 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000286 global quitting
287 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000288 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000289
290 def decode_interrupthook(self):
291 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000292 global quitting
293 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000294 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000295
Chui Tey5d2af632002-05-26 13:36:41 +0000296
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000297class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000298
299 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000300 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000301 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000302 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000303 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000304
305 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000306 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000307 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000308 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000309 interruptable = True
310 try:
311 exec(code, self.locals)
312 finally:
313 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000314 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000315 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000316 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000317 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000318 # even print a user code SystemExit exception, continue
319 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000320 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
321 if jit:
322 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000323 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000324 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000325
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000326 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000327 if interruptable:
328 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000329
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000330 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000331 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
332
333 def stop_the_debugger(self, idb_adap_oid):
334 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
335 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000336
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000337 def get_the_calltip(self, name):
338 return self.calltip.fetch_tip(name)
339
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000340 def get_the_completion_list(self, what, mode):
341 return self.autocomplete.fetch_completions(what, mode)
342
Chui Tey5d2af632002-05-26 13:36:41 +0000343 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000344 if self.usr_exc_info:
345 typ, val, tb = self.usr_exc_info
346 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000347 return None
348 flist = None
349 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000350 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000351 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
352 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000353 sys.last_type = typ
354 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000355 item = StackViewer.StackTreeItem(flist, tb)
356 return RemoteObjectBrowser.remote_object_tree_item(item)