blob: 28b7bc0bca231ee88254ba70d820375a2445a711 [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__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000122 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000123 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000124 print("IDLE Subprocess: Connection to "
125 "IDLE GUI failed, exiting.", file=sys.__stderr__)
126 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000127 global exit_now
128 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000129 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000130 server.handle_request() # A single request only
131
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000132def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000133 import tkinter
134 import tkinter.messagebox as tkMessageBox
135 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000136 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000137 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000138 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
139 "to your personal firewall configuration. It is safe to "\
140 "allow this internal connection because no data is visible on "\
141 "external ports." % address
142 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
143 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000144 tkMessageBox.showerror("IDLE Subprocess Error",
145 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000146 root.destroy()
147
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000148def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000149 import linecache
150 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000151 flush_stdout()
152 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000153 typ, val, tb = excinfo = sys.exc_info()
154 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000155 tbe = traceback.extract_tb(tb)
Guido van Rossum33d26892007-08-05 15:29:28 +0000156 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000157 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000158 "RemoteDebugger.py", "bdb.py")
159 cleanup_traceback(tbe, exclude)
160 traceback.print_list(tbe, file=efile)
161 lines = traceback.format_exception_only(typ, val)
162 for line in lines:
Guido van Rossum33d26892007-08-05 15:29:28 +0000163 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000164
165def cleanup_traceback(tb, exclude):
166 "Remove excluded traces from beginning/end of tb; get cached lines"
167 orig_tb = tb[:]
168 while tb:
169 for rpcfile in exclude:
170 if tb[0][0].count(rpcfile):
171 break # found an exclude, break for: and delete tb[0]
172 else:
173 break # no excludes, have left RPC code, break while:
174 del tb[0]
175 while tb:
176 for rpcfile in exclude:
177 if tb[-1][0].count(rpcfile):
178 break
179 else:
180 break
181 del tb[-1]
182 if len(tb) == 0:
183 # exception was in IDLE internals, don't prune!
184 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000185 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000186 rpchandler = rpc.objecttable['exec'].rpchandler
187 for i in range(len(tb)):
188 fn, ln, nm, line = tb[i]
189 if nm == '?':
190 nm = "-toplevel-"
191 if not line and fn.startswith("<pyshell#"):
192 line = rpchandler.remotecall('linecache', 'getline',
193 (fn, ln), {})
194 tb[i] = fn, ln, nm, line
195
196def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000197 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000198
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000199def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000200 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000201
202 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000203 functions registered with atexit will be removed before exiting.
204 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000205
206 """
207 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000208 import atexit
209 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000210 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000211
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000212class MyRPCServer(rpc.RPCServer):
213
214 def handle_error(self, request, client_address):
215 """Override RPCServer method for IDLE
216
217 Interrupt the MainThread and exit server if link is dropped.
218
219 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000220 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000221 try:
222 raise
223 except SystemExit:
224 raise
225 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000226 global exit_now
227 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000228 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000229 except:
230 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000231 print('\n' + '-'*40, file=erf)
232 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000233 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000234 print('Client Address: ', client_address, file=erf)
235 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000236 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000237 print('\n*** Unrecoverable, server exiting!', file=erf)
238 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000239 quitting = True
240 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000241
242
Chui Tey5d2af632002-05-26 13:36:41 +0000243class MyHandler(rpc.RPCHandler):
244
245 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000246 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000247 executive = Executive(self)
248 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000249 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000250 sys.stdout = self.get_remote_proxy("stdout")
251 sys.stderr = self.get_remote_proxy("stderr")
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000252 # page help() text to shell.
253 import pydoc # import must be done here to capture i/o binding
254 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000255 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000256 sys.stdin.encoding = sys.stdout.encoding = \
257 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000258 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000259 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
260
261 def exithook(self):
262 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000263 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000264
265 def EOFhook(self):
266 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000267 global quitting
268 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000269 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000270
271 def decode_interrupthook(self):
272 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000273 global quitting
274 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000275 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000276
Chui Tey5d2af632002-05-26 13:36:41 +0000277
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000278class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000279
280 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000281 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000282 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000283 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000284 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000285
286 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000287 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000288 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000289 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000290 interruptable = True
291 try:
292 exec(code, self.locals)
293 finally:
294 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000295 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000296 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000297 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000298 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000299 # even print a user code SystemExit exception, continue
300 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000301 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
302 if jit:
303 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000304 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000305 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000306
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000307 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000308 if interruptable:
309 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000310
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000311 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000312 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
313
314 def stop_the_debugger(self, idb_adap_oid):
315 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
316 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000317
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000318 def get_the_calltip(self, name):
319 return self.calltip.fetch_tip(name)
320
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000321 def get_the_completion_list(self, what, mode):
322 return self.autocomplete.fetch_completions(what, mode)
323
Chui Tey5d2af632002-05-26 13:36:41 +0000324 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000325 if self.usr_exc_info:
326 typ, val, tb = self.usr_exc_info
327 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000328 return None
329 flist = None
330 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000331 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000332 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
333 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000334 sys.last_type = typ
335 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000336 item = StackViewer.StackTreeItem(flist, tb)
337 return RemoteObjectBrowser.remote_object_tree_item(item)