blob: 604c5cd54e1e68dd1671ec859cee5c002f876f51 [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Martin v. Löwise8e4e142012-07-09 21:01:49 +02002import io
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +00003import linecache
Kurt B. Kaiserb4179362002-07-26 00:06:42 +00004import time
5import socket
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +00006import traceback
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +00007import thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00008import threading
Georg Brandla6168f92008-05-25 07:20:14 +00009import Queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000010
Florent Xiclunad630c042010-04-02 07:24:52 +000011from idlelib import CallTips
12from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000013
Florent Xiclunad630c042010-04-02 07:24:52 +000014from idlelib import RemoteDebugger
15from idlelib import RemoteObjectBrowser
16from idlelib import StackViewer
17from idlelib import rpc
Serhiy Storchaka9abc8302013-01-25 15:30:35 +020018from idlelib import PyShell
19from idlelib import IOBinding
Chui Tey5d2af632002-05-26 13:36:41 +000020
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000021import __main__
22
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000023LOCALHOST = '127.0.0.1'
24
Terry Jan Reedy8eab0082013-06-28 23:51:34 -040025import warnings
26
27def idle_showwarning_subproc(
28 message, category, filename, lineno, file=None, line=None):
29 """Show Idle-format warning after replacing warnings.showwarning.
30
31 The only difference is the formatter called.
32 """
33 if file is None:
34 file = sys.stderr
35 try:
36 file.write(PyShell.idle_formatwarning(
37 message, category, filename, lineno, line))
38 except IOError:
39 pass # the file (probably stderr) is invalid - this warning gets lost.
40
41_warnings_showwarning = None
42
43def capture_warnings(capture):
44 "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
45
46 global _warnings_showwarning
47 if capture:
48 if _warnings_showwarning is None:
49 _warnings_showwarning = warnings.showwarning
50 warnings.showwarning = idle_showwarning_subproc
51 else:
52 if _warnings_showwarning is not None:
53 warnings.showwarning = _warnings_showwarning
54 _warnings_showwarning = None
55
56capture_warnings(True)
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000057
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000058# Thread shared globals: Establish a queue between a subthread (which handles
59# the socket) and the main thread (which runs user code), plus global
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000060# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000061
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000062exit_now = False
63quitting = False
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000064interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000065
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000066def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000067 """Start the Python execution server in a subprocess
68
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000069 In the Python subprocess, RPCServer is instantiated with handlerclass
70 MyHandler, which inherits register/unregister methods from RPCHandler via
71 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000072
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000073 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000074 creates an instance of run.MyHandler and calls its handle() method.
75 handle() instantiates a run.Executive object, passing it a reference to the
76 MyHandler object. That reference is saved as attribute rpchandler of the
77 Executive instance. The Executive methods have access to the reference and
78 can pass it on to entities that they command
79 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
80 call MyHandler(SocketIO) register/unregister methods via the reference to
81 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000082
83 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000084 global exit_now
85 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000086 global no_exitfunc
87 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000088 #time.sleep(15) # test subprocess not responding
Kurt B. Kaiser4724f402009-04-02 02:44:54 +000089 try:
90 assert(len(sys.argv) > 1)
91 port = int(sys.argv[-1])
92 except:
93 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
94 return
Terry Jan Reedy8eab0082013-06-28 23:51:34 -040095
96 capture_warnings(True)
Chui Tey5d2af632002-05-26 13:36:41 +000097 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000098 sockthread = threading.Thread(target=manage_socket,
99 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +0000100 args=((LOCALHOST, port),))
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000101 sockthread.setDaemon(True)
102 sockthread.start()
103 while 1:
104 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000105 if exit_now:
106 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000107 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000108 except KeyboardInterrupt:
109 # exiting but got an extra KBI? Try again!
110 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000111 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +0000112 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Georg Brandla6168f92008-05-25 07:20:14 +0000113 except Queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000114 continue
115 method, args, kwargs = request
116 ret = method(*args, **kwargs)
117 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000118 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000119 if quitting:
120 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000121 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000122 except SystemExit:
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400123 capture_warnings(False)
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000124 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000125 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000126 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000127 try:
128 print_exception()
129 rpc.response_queue.put((seq, None))
130 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000131 # Link didn't work, print same exception to __stderr__
132 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000133 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000134 else:
135 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000136
137def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000138 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000139 time.sleep(i)
140 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000141 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000142 break
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400143 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000144 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
Florent Xiclunad630c042010-04-02 07:24:52 +0000145 + err.args[1] + ", retrying...."
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000146 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000147 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
148 "IDLE GUI failed, exiting."
149 show_socket_error(err, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000150 global exit_now
151 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000152 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000153 server.handle_request() # A single request only
154
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000155def show_socket_error(err, address):
Georg Brandl6634bf22008-05-20 07:13:37 +0000156 import Tkinter
157 import tkMessageBox
158 root = Tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000159 root.withdraw()
Florent Xiclunad630c042010-04-02 07:24:52 +0000160 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000161 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
162 "to your personal firewall configuration. It is safe to "\
163 "allow this internal connection because no data is visible on "\
164 "external ports." % address
165 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
166 else:
Florent Xiclunad630c042010-04-02 07:24:52 +0000167 tkMessageBox.showerror("IDLE Subprocess Error",
168 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000169 root.destroy()
170
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000171def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000172 import linecache
173 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000174 flush_stdout()
175 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000176 typ, val, tb = excinfo = sys.exc_info()
177 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000178 tbe = traceback.extract_tb(tb)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000179 print>>efile, '\nTraceback (most recent call last):'
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000180 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
181 "RemoteDebugger.py", "bdb.py")
182 cleanup_traceback(tbe, exclude)
183 traceback.print_list(tbe, file=efile)
184 lines = traceback.format_exception_only(typ, val)
185 for line in lines:
186 print>>efile, line,
187
188def cleanup_traceback(tb, exclude):
189 "Remove excluded traces from beginning/end of tb; get cached lines"
190 orig_tb = tb[:]
191 while tb:
192 for rpcfile in exclude:
193 if tb[0][0].count(rpcfile):
194 break # found an exclude, break for: and delete tb[0]
195 else:
196 break # no excludes, have left RPC code, break while:
197 del tb[0]
198 while tb:
199 for rpcfile in exclude:
200 if tb[-1][0].count(rpcfile):
201 break
202 else:
203 break
204 del tb[-1]
205 if len(tb) == 0:
206 # exception was in IDLE internals, don't prune!
207 tb[:] = orig_tb[:]
208 print>>sys.stderr, "** IDLE Internal Exception: "
209 rpchandler = rpc.objecttable['exec'].rpchandler
210 for i in range(len(tb)):
211 fn, ln, nm, line = tb[i]
212 if nm == '?':
213 nm = "-toplevel-"
214 if not line and fn.startswith("<pyshell#"):
215 line = rpchandler.remotecall('linecache', 'getline',
216 (fn, ln), {})
217 tb[i] = fn, ln, nm, line
218
219def flush_stdout():
220 try:
221 if sys.stdout.softspace:
222 sys.stdout.softspace = 0
223 sys.stdout.write("\n")
224 except (AttributeError, EOFError):
225 pass
226
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000227def exit():
228 """Exit subprocess, possibly after first deleting sys.exitfunc
229
230 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
231 sys.exitfunc will be removed before exiting. (VPython support)
232
233 """
234 if no_exitfunc:
Kurt B. Kaiserf30ba3d2008-01-23 22:55:26 +0000235 try:
236 del sys.exitfunc
237 except AttributeError:
238 pass
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400239 capture_warnings(False)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000240 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000241
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000242class MyRPCServer(rpc.RPCServer):
243
244 def handle_error(self, request, client_address):
245 """Override RPCServer method for IDLE
246
247 Interrupt the MainThread and exit server if link is dropped.
248
249 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000250 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000251 try:
252 raise
253 except SystemExit:
254 raise
255 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000256 global exit_now
257 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000258 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000259 except:
260 erf = sys.__stderr__
261 print>>erf, '\n' + '-'*40
262 print>>erf, 'Unhandled server exception!'
263 print>>erf, 'Thread: %s' % threading.currentThread().getName()
264 print>>erf, 'Client Address: ', client_address
265 print>>erf, 'Request: ', repr(request)
266 traceback.print_exc(file=erf)
267 print>>erf, '\n*** Unrecoverable, server exiting!'
268 print>>erf, '-'*40
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000269 quitting = True
270 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000271
Chui Tey5d2af632002-05-26 13:36:41 +0000272class MyHandler(rpc.RPCHandler):
273
274 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000275 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000276 executive = Executive(self)
277 self.register("exec", executive)
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200278 self.console = self.get_remote_proxy("console")
279 sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
280 IOBinding.encoding)
281 sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
282 IOBinding.encoding)
283 sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
284 IOBinding.encoding)
Benjamin Peterson5a271682013-05-11 22:24:28 -0500285
286 # Keep a reference to stdin so that it won't try to exit IDLE if
287 # sys.stdin gets changed from within IDLE's shell. See issue17838.
288 self._keep_stdin = sys.stdin
289
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000290 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000291 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
292
293 def exithook(self):
294 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000295 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000296
297 def EOFhook(self):
298 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000299 global quitting
300 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000301 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000302
303 def decode_interrupthook(self):
304 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000305 global quitting
306 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000307 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000308
Chui Tey5d2af632002-05-26 13:36:41 +0000309
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000310class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000311
312 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000313 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000314 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000315 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000316 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000317
318 def runcode(self, code):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000319 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000320 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000321 self.usr_exc_info = None
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000322 interruptable = True
323 try:
324 exec code in self.locals
325 finally:
326 interruptable = False
Raymond Hettinger42349922013-02-09 14:20:55 -0500327 except SystemExit:
328 # Scripts that raise SystemExit should just
329 # return to the interactive prompt
330 pass
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000331 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000332 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000333 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000334 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000335 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000336 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
337 if jit:
338 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000339 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000340 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000341
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000342 def interrupt_the_server(self):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000343 if interruptable:
344 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000345
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000346 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000347 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
348
349 def stop_the_debugger(self, idb_adap_oid):
350 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
351 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000352
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000353 def get_the_calltip(self, name):
354 return self.calltip.fetch_tip(name)
355
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000356 def get_the_completion_list(self, what, mode):
357 return self.autocomplete.fetch_completions(what, mode)
358
Chui Tey5d2af632002-05-26 13:36:41 +0000359 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000360 if self.usr_exc_info:
361 typ, val, tb = self.usr_exc_info
362 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000363 return None
364 flist = None
365 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000366 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000367 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
368 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000369 sys.last_type = typ
370 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000371 item = StackViewer.StackTreeItem(flist, tb)
372 return RemoteObjectBrowser.remote_object_tree_item(item)
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400373
374capture_warnings(False) # Make sure turned off; see issue 18081