blob: 806456a3a84ca86cfecb2d32f2eb6c8d0c12092c [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,
28 file=None, 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)
Benjamin Peterson206e3072008-10-19 14:07:49 +000032 line = linecache.getline(filename, lineno).strip() \
33 if line is None else line
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000034 if line:
35 s += " %s\n" % line
36 s += "%s: %s\n" % (category.__name__, message)
37 return s
38 warnings.formatwarning = idle_formatwarning_subproc
39
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000040# Thread shared globals: Establish a queue between a subthread (which handles
41# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000042# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000043
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000044exit_now = False
45quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +000046interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000047
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000048def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000049 """Start the Python execution server in a subprocess
50
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000051 In the Python subprocess, RPCServer is instantiated with handlerclass
52 MyHandler, which inherits register/unregister methods from RPCHandler via
53 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000054
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000055 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000056 creates an instance of run.MyHandler and calls its handle() method.
57 handle() instantiates a run.Executive object, passing it a reference to the
58 MyHandler object. That reference is saved as attribute rpchandler of the
59 Executive instance. The Executive methods have access to the reference and
60 can pass it on to entities that they command
61 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
62 call MyHandler(SocketIO) register/unregister methods via the reference to
63 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000064
65 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000066 global exit_now
67 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000068 global no_exitfunc
69 no_exitfunc = del_exitfunc
Chui Tey5d2af632002-05-26 13:36:41 +000070 port = 8833
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000071 #time.sleep(15) # test subprocess not responding
Chui Tey5d2af632002-05-26 13:36:41 +000072 if sys.argv[1:]:
73 port = int(sys.argv[1])
74 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000075 sockthread = threading.Thread(target=manage_socket,
76 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000077 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000078 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000079 sockthread.start()
80 while 1:
81 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000082 if exit_now:
83 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000084 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000085 except KeyboardInterrupt:
86 # exiting but got an extra KBI? Try again!
87 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000088 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000089 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +000090 except queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000091 continue
92 method, args, kwargs = request
93 ret = method(*args, **kwargs)
94 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000095 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000096 if quitting:
97 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000098 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +000099 except SystemExit:
100 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000101 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000102 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000103 try:
104 print_exception()
105 rpc.response_queue.put((seq, None))
106 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000107 # Link didn't work, print same exception to __stderr__
108 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000109 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000110 else:
111 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000112
113def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000114 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000115 time.sleep(i)
116 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000117 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000118 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000119 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000120 print("IDLE Subprocess: socket error: " + err.args[1] +
121 ", retrying....", file=sys.__stderr__)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000122 else:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000123 print("IDLE Subprocess: Connection to "\
124 "IDLE GUI failed, exiting.", file=sys.__stderr__)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000125 show_socket_error(err, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000126 global exit_now
127 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000128 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000129 server.handle_request() # A single request only
130
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000131def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000132 import tkinter
133 import tkinter.messagebox as tkMessageBox
134 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000135 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000136 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000137 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
138 "to your personal firewall configuration. It is safe to "\
139 "allow this internal connection because no data is visible on "\
140 "external ports." % address
141 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
142 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000143 tkMessageBox.showerror("IDLE Subprocess Error",
144 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000145 root.destroy()
146
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000147def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000148 import linecache
149 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000150 flush_stdout()
151 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000152 typ, val, tb = excinfo = sys.exc_info()
153 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000154 tbe = traceback.extract_tb(tb)
Guido van Rossum33d26892007-08-05 15:29:28 +0000155 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000156 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000157 "RemoteDebugger.py", "bdb.py")
158 cleanup_traceback(tbe, exclude)
159 traceback.print_list(tbe, file=efile)
160 lines = traceback.format_exception_only(typ, val)
161 for line in lines:
Guido van Rossum33d26892007-08-05 15:29:28 +0000162 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000163
164def cleanup_traceback(tb, exclude):
165 "Remove excluded traces from beginning/end of tb; get cached lines"
166 orig_tb = tb[:]
167 while tb:
168 for rpcfile in exclude:
169 if tb[0][0].count(rpcfile):
170 break # found an exclude, break for: and delete tb[0]
171 else:
172 break # no excludes, have left RPC code, break while:
173 del tb[0]
174 while tb:
175 for rpcfile in exclude:
176 if tb[-1][0].count(rpcfile):
177 break
178 else:
179 break
180 del tb[-1]
181 if len(tb) == 0:
182 # exception was in IDLE internals, don't prune!
183 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000184 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000185 rpchandler = rpc.objecttable['exec'].rpchandler
186 for i in range(len(tb)):
187 fn, ln, nm, line = tb[i]
188 if nm == '?':
189 nm = "-toplevel-"
190 if not line and fn.startswith("<pyshell#"):
191 line = rpchandler.remotecall('linecache', 'getline',
192 (fn, ln), {})
193 tb[i] = fn, ln, nm, line
194
195def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000196 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000197
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000198def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000199 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000200
201 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000202 functions registered with atexit will be removed before exiting.
203 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000204
205 """
206 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000207 import atexit
208 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000209 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000210
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000211class MyRPCServer(rpc.RPCServer):
212
213 def handle_error(self, request, client_address):
214 """Override RPCServer method for IDLE
215
216 Interrupt the MainThread and exit server if link is dropped.
217
218 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000219 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000220 try:
221 raise
222 except SystemExit:
223 raise
224 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000225 global exit_now
226 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000227 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000228 except:
229 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000230 print('\n' + '-'*40, file=erf)
231 print('Unhandled server exception!', file=erf)
Benjamin Petersonb03ca4b2008-06-13 02:00:47 +0000232 print('Thread: %s' % threading.current_thread().get_name(), file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000233 print('Client Address: ', client_address, file=erf)
234 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000235 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000236 print('\n*** Unrecoverable, server exiting!', file=erf)
237 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000238 quitting = True
239 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000240
241
Chui Tey5d2af632002-05-26 13:36:41 +0000242class MyHandler(rpc.RPCHandler):
243
244 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000245 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000246 executive = Executive(self)
247 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000248 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000249 sys.stdout = self.get_remote_proxy("stdout")
250 sys.stderr = self.get_remote_proxy("stderr")
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000251 # page help() text to shell.
252 import pydoc # import must be done here to capture i/o binding
253 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000254 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000255 sys.stdin.encoding = sys.stdout.encoding = \
256 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000257 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000258 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
259
260 def exithook(self):
261 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000262 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000263
264 def EOFhook(self):
265 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000266 global quitting
267 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000268 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000269
270 def decode_interrupthook(self):
271 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000272 global quitting
273 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000274 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000275
Chui Tey5d2af632002-05-26 13:36:41 +0000276
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000277class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000278
279 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000280 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000281 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000282 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000283 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000284
285 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000286 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000287 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000288 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000289 interruptable = True
290 try:
291 exec(code, self.locals)
292 finally:
293 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000294 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000295 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000296 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000297 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000298 # even print a user code SystemExit exception, continue
299 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000300 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
301 if jit:
302 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000303 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000304 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000305
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000306 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000307 if interruptable:
308 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000309
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000310 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000311 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
312
313 def stop_the_debugger(self, idb_adap_oid):
314 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
315 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000316
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000317 def get_the_calltip(self, name):
318 return self.calltip.fetch_tip(name)
319
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000320 def get_the_completion_list(self, what, mode):
321 return self.autocomplete.fetch_completions(what, mode)
322
Chui Tey5d2af632002-05-26 13:36:41 +0000323 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000324 if self.usr_exc_info:
325 typ, val, tb = self.usr_exc_info
326 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000327 return None
328 flist = None
329 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000330 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000331 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
332 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000333 sys.last_type = typ
334 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000335 item = StackViewer.StackTreeItem(flist, tb)
336 return RemoteObjectBrowser.remote_object_tree_item(item)