blob: 6659ee725d1a27ebbafc930b5b977777d39573c1 [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
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000070 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000071 try:
72 assert(len(sys.argv) > 1)
73 port = int(sys.argv[-1])
74 except:
75 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
76 return
Chui Tey5d2af632002-05-26 13:36:41 +000077 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000078 sockthread = threading.Thread(target=manage_socket,
79 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000080 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000081 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000082 sockthread.start()
83 while 1:
84 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000085 if exit_now:
86 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000087 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000088 except KeyboardInterrupt:
89 # exiting but got an extra KBI? Try again!
90 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000091 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000092 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +000093 except queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000094 continue
95 method, args, kwargs = request
96 ret = method(*args, **kwargs)
97 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000098 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000099 if quitting:
100 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000101 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000102 except SystemExit:
103 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000104 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000105 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000106 try:
107 print_exception()
108 rpc.response_queue.put((seq, None))
109 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000110 # Link didn't work, print same exception to __stderr__
111 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000112 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000113 else:
114 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000115
116def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000117 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000118 time.sleep(i)
119 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000120 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000121 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000122 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000123 print("IDLE Subprocess: socket error: " + err.args[1] +
124 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000125 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000126 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000127 print("IDLE Subprocess: Connection to "
128 "IDLE GUI failed, exiting.", file=sys.__stderr__)
129 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000130 global exit_now
131 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000132 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000133 server.handle_request() # A single request only
134
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000135def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000136 import tkinter
137 import tkinter.messagebox as tkMessageBox
138 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000139 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000140 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000141 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
142 "to your personal firewall configuration. It is safe to "\
143 "allow this internal connection because no data is visible on "\
144 "external ports." % address
145 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
146 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000147 tkMessageBox.showerror("IDLE Subprocess Error",
148 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000149 root.destroy()
150
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000151def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000152 import linecache
153 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000154 flush_stdout()
155 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000156 typ, val, tb = excinfo = sys.exc_info()
157 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000158 tbe = traceback.extract_tb(tb)
Guido van Rossum33d26892007-08-05 15:29:28 +0000159 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000160 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000161 "RemoteDebugger.py", "bdb.py")
162 cleanup_traceback(tbe, exclude)
163 traceback.print_list(tbe, file=efile)
164 lines = traceback.format_exception_only(typ, val)
165 for line in lines:
Guido van Rossum33d26892007-08-05 15:29:28 +0000166 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000167
168def cleanup_traceback(tb, exclude):
169 "Remove excluded traces from beginning/end of tb; get cached lines"
170 orig_tb = tb[:]
171 while tb:
172 for rpcfile in exclude:
173 if tb[0][0].count(rpcfile):
174 break # found an exclude, break for: and delete tb[0]
175 else:
176 break # no excludes, have left RPC code, break while:
177 del tb[0]
178 while tb:
179 for rpcfile in exclude:
180 if tb[-1][0].count(rpcfile):
181 break
182 else:
183 break
184 del tb[-1]
185 if len(tb) == 0:
186 # exception was in IDLE internals, don't prune!
187 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000188 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000189 rpchandler = rpc.objecttable['exec'].rpchandler
190 for i in range(len(tb)):
191 fn, ln, nm, line = tb[i]
192 if nm == '?':
193 nm = "-toplevel-"
194 if not line and fn.startswith("<pyshell#"):
195 line = rpchandler.remotecall('linecache', 'getline',
196 (fn, ln), {})
197 tb[i] = fn, ln, nm, line
198
199def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000200 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000201
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000202def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000203 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000204
205 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000206 functions registered with atexit will be removed before exiting.
207 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000208
209 """
210 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000211 import atexit
212 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000213 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000214
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000215class MyRPCServer(rpc.RPCServer):
216
217 def handle_error(self, request, client_address):
218 """Override RPCServer method for IDLE
219
220 Interrupt the MainThread and exit server if link is dropped.
221
222 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000223 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000224 try:
225 raise
226 except SystemExit:
227 raise
228 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000229 global exit_now
230 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000231 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000232 except:
233 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000234 print('\n' + '-'*40, file=erf)
235 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000236 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000237 print('Client Address: ', client_address, file=erf)
238 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000239 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000240 print('\n*** Unrecoverable, server exiting!', file=erf)
241 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000242 quitting = True
243 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000244
245
Chui Tey5d2af632002-05-26 13:36:41 +0000246class MyHandler(rpc.RPCHandler):
247
248 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000249 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000250 executive = Executive(self)
251 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000252 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000253 sys.stdout = self.get_remote_proxy("stdout")
254 sys.stderr = self.get_remote_proxy("stderr")
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000255 # page help() text to shell.
256 import pydoc # import must be done here to capture i/o binding
257 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000258 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000259 sys.stdin.encoding = sys.stdout.encoding = \
260 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000261 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000262 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
263
264 def exithook(self):
265 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000266 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000267
268 def EOFhook(self):
269 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000270 global quitting
271 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000272 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000273
274 def decode_interrupthook(self):
275 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000276 global quitting
277 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000278 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000279
Chui Tey5d2af632002-05-26 13:36:41 +0000280
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000281class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000282
283 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000284 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000285 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000286 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000287 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000288
289 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000290 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000291 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000292 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000293 interruptable = True
294 try:
295 exec(code, self.locals)
296 finally:
297 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000298 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000299 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000300 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000301 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000302 # even print a user code SystemExit exception, continue
303 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000304 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
305 if jit:
306 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000307 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000308 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000309
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000310 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000311 if interruptable:
312 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000313
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000314 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000315 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
316
317 def stop_the_debugger(self, idb_adap_oid):
318 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
319 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000320
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000321 def get_the_calltip(self, name):
322 return self.calltip.fetch_tip(name)
323
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000324 def get_the_completion_list(self, what, mode):
325 return self.autocomplete.fetch_completions(what, mode)
326
Chui Tey5d2af632002-05-26 13:36:41 +0000327 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000328 if self.usr_exc_info:
329 typ, val, tb = self.usr_exc_info
330 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000331 return None
332 flist = None
333 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000334 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000335 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
336 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000337 sys.last_type = typ
338 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000339 item = StackViewer.StackTreeItem(flist, tb)
340 return RemoteObjectBrowser.remote_object_tree_item(item)