blob: 466c61ea341a73a621085bdef6fb7a5eb47c9c8a [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
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +00006import thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00007import threading
Georg Brandla6168f92008-05-25 07:20:14 +00008import Queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +00009
Florent Xiclunad630c042010-04-02 07:24:52 +000010from idlelib import CallTips
11from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000012
Florent Xiclunad630c042010-04-02 07:24:52 +000013from idlelib import RemoteDebugger
14from idlelib import RemoteObjectBrowser
15from idlelib import StackViewer
16from idlelib import rpc
Serhiy Storchaka9abc8302013-01-25 15:30:35 +020017from idlelib import PyShell
18from idlelib import IOBinding
Chui Tey5d2af632002-05-26 13:36:41 +000019
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000020import __main__
21
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000022LOCALHOST = '127.0.0.1'
23
Terry Jan Reedy8eab0082013-06-28 23:51:34 -040024import warnings
25
26def idle_showwarning_subproc(
27 message, category, filename, lineno, file=None, line=None):
28 """Show Idle-format warning after replacing warnings.showwarning.
29
30 The only difference is the formatter called.
31 """
32 if file is None:
33 file = sys.stderr
34 try:
35 file.write(PyShell.idle_formatwarning(
36 message, category, filename, lineno, line))
37 except IOError:
38 pass # the file (probably stderr) is invalid - this warning gets lost.
39
40_warnings_showwarning = None
41
42def capture_warnings(capture):
43 "Replace warning.showwarning with idle_showwarning_subproc, or reverse."
44
45 global _warnings_showwarning
46 if capture:
47 if _warnings_showwarning is None:
48 _warnings_showwarning = warnings.showwarning
49 warnings.showwarning = idle_showwarning_subproc
50 else:
51 if _warnings_showwarning is not None:
52 warnings.showwarning = _warnings_showwarning
53 _warnings_showwarning = None
54
55capture_warnings(True)
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000056
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000057# Thread shared globals: Establish a queue between a subthread (which handles
58# the socket) and the main thread (which runs user code), plus global
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000059# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000060
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000061exit_now = False
62quitting = False
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +000063interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000064
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000065def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000066 """Start the Python execution server in a subprocess
67
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000068 In the Python subprocess, RPCServer is instantiated with handlerclass
69 MyHandler, which inherits register/unregister methods from RPCHandler via
70 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000071
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000072 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000073 creates an instance of run.MyHandler and calls its handle() method.
74 handle() instantiates a run.Executive object, passing it a reference to the
75 MyHandler object. That reference is saved as attribute rpchandler of the
76 Executive instance. The Executive methods have access to the reference and
77 can pass it on to entities that they command
78 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
79 call MyHandler(SocketIO) register/unregister methods via the reference to
80 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000081
82 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000083 global exit_now
84 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000085 global no_exitfunc
86 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000087 #time.sleep(15) # test subprocess not responding
Kurt B. Kaiser4724f402009-04-02 02:44:54 +000088 try:
89 assert(len(sys.argv) > 1)
90 port = int(sys.argv[-1])
91 except:
92 print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
93 return
Terry Jan Reedy8eab0082013-06-28 23:51:34 -040094
95 capture_warnings(True)
Chui Tey5d2af632002-05-26 13:36:41 +000096 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000097 sockthread = threading.Thread(target=manage_socket,
98 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000099 args=((LOCALHOST, port),))
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000100 sockthread.setDaemon(True)
101 sockthread.start()
102 while 1:
103 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000104 if exit_now:
105 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000106 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000107 except KeyboardInterrupt:
108 # exiting but got an extra KBI? Try again!
109 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000110 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +0000111 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Georg Brandla6168f92008-05-25 07:20:14 +0000112 except Queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000113 continue
114 method, args, kwargs = request
115 ret = method(*args, **kwargs)
116 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000117 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000118 if quitting:
119 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000120 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000121 except SystemExit:
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400122 capture_warnings(False)
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000123 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000124 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000125 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000126 try:
127 print_exception()
128 rpc.response_queue.put((seq, None))
129 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000130 # Link didn't work, print same exception to __stderr__
131 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000132 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000133 else:
134 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000135
136def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000137 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000138 time.sleep(i)
139 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000140 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000141 break
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400142 except socket.error as err:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000143 print>>sys.__stderr__,"IDLE Subprocess: socket error: "\
Florent Xiclunad630c042010-04-02 07:24:52 +0000144 + err.args[1] + ", retrying...."
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000145 else:
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000146 print>>sys.__stderr__, "IDLE Subprocess: Connection to "\
147 "IDLE GUI failed, exiting."
148 show_socket_error(err, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000149 global exit_now
150 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000151 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000152 server.handle_request() # A single request only
153
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000154def show_socket_error(err, address):
Georg Brandl6634bf22008-05-20 07:13:37 +0000155 import Tkinter
156 import tkMessageBox
157 root = Tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000158 root.withdraw()
Florent Xiclunad630c042010-04-02 07:24:52 +0000159 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000160 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
161 "to your personal firewall configuration. It is safe to "\
162 "allow this internal connection because no data is visible on "\
163 "external ports." % address
164 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
165 else:
Florent Xiclunad630c042010-04-02 07:24:52 +0000166 tkMessageBox.showerror("IDLE Subprocess Error",
Terry Jan Reedy8bfacc72015-09-25 22:22:48 -0400167 "Socket Error: %s" % err.args[1], parent=root)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000168 root.destroy()
169
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000170def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000171 import linecache
172 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000173 flush_stdout()
174 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000175 typ, val, tb = excinfo = sys.exc_info()
176 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000177 tbe = traceback.extract_tb(tb)
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000178 print>>efile, '\nTraceback (most recent call last):'
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000179 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
180 "RemoteDebugger.py", "bdb.py")
181 cleanup_traceback(tbe, exclude)
182 traceback.print_list(tbe, file=efile)
183 lines = traceback.format_exception_only(typ, val)
184 for line in lines:
185 print>>efile, line,
186
187def cleanup_traceback(tb, exclude):
188 "Remove excluded traces from beginning/end of tb; get cached lines"
189 orig_tb = tb[:]
190 while tb:
191 for rpcfile in exclude:
192 if tb[0][0].count(rpcfile):
193 break # found an exclude, break for: and delete tb[0]
194 else:
195 break # no excludes, have left RPC code, break while:
196 del tb[0]
197 while tb:
198 for rpcfile in exclude:
199 if tb[-1][0].count(rpcfile):
200 break
201 else:
202 break
203 del tb[-1]
204 if len(tb) == 0:
205 # exception was in IDLE internals, don't prune!
206 tb[:] = orig_tb[:]
207 print>>sys.stderr, "** IDLE Internal Exception: "
208 rpchandler = rpc.objecttable['exec'].rpchandler
209 for i in range(len(tb)):
210 fn, ln, nm, line = tb[i]
211 if nm == '?':
212 nm = "-toplevel-"
Serhiy Storchaka4b2c4682015-05-17 13:53:54 +0300213 if fn.startswith("<pyshell#") and IOBinding.encoding != 'utf-8':
214 ln -= 1 # correction for coding cookie
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000215 if not line and fn.startswith("<pyshell#"):
216 line = rpchandler.remotecall('linecache', 'getline',
217 (fn, ln), {})
218 tb[i] = fn, ln, nm, line
219
220def flush_stdout():
221 try:
222 if sys.stdout.softspace:
223 sys.stdout.softspace = 0
224 sys.stdout.write("\n")
225 except (AttributeError, EOFError):
226 pass
227
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000228def exit():
229 """Exit subprocess, possibly after first deleting sys.exitfunc
230
231 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
232 sys.exitfunc will be removed before exiting. (VPython support)
233
234 """
235 if no_exitfunc:
Kurt B. Kaiserf30ba3d2008-01-23 22:55:26 +0000236 try:
237 del sys.exitfunc
238 except AttributeError:
239 pass
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400240 capture_warnings(False)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000241 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000242
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000243class MyRPCServer(rpc.RPCServer):
244
245 def handle_error(self, request, client_address):
246 """Override RPCServer method for IDLE
247
248 Interrupt the MainThread and exit server if link is dropped.
249
250 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000251 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000252 try:
253 raise
254 except SystemExit:
255 raise
256 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000257 global exit_now
258 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000259 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000260 except:
261 erf = sys.__stderr__
262 print>>erf, '\n' + '-'*40
263 print>>erf, 'Unhandled server exception!'
264 print>>erf, 'Thread: %s' % threading.currentThread().getName()
265 print>>erf, 'Client Address: ', client_address
266 print>>erf, 'Request: ', repr(request)
267 traceback.print_exc(file=erf)
268 print>>erf, '\n*** Unrecoverable, server exiting!'
269 print>>erf, '-'*40
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000270 quitting = True
271 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000272
Chui Tey5d2af632002-05-26 13:36:41 +0000273class MyHandler(rpc.RPCHandler):
274
275 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000276 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000277 executive = Executive(self)
278 self.register("exec", executive)
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200279 self.console = self.get_remote_proxy("console")
280 sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
281 IOBinding.encoding)
282 sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
283 IOBinding.encoding)
284 sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
285 IOBinding.encoding)
Benjamin Peterson5a271682013-05-11 22:24:28 -0500286
287 # Keep a reference to stdin so that it won't try to exit IDLE if
288 # sys.stdin gets changed from within IDLE's shell. See issue17838.
289 self._keep_stdin = sys.stdin
290
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000291 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000292 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
293
294 def exithook(self):
295 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000296 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000297
298 def EOFhook(self):
299 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000300 global quitting
301 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000302 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000303
304 def decode_interrupthook(self):
305 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000306 global quitting
307 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000308 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000309
Chui Tey5d2af632002-05-26 13:36:41 +0000310
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000311class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000312
313 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000314 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000315 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000316 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000317 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000318
319 def runcode(self, code):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000320 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000321 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000322 self.usr_exc_info = None
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000323 interruptable = True
324 try:
325 exec code in self.locals
326 finally:
327 interruptable = False
Raymond Hettinger42349922013-02-09 14:20:55 -0500328 except SystemExit:
329 # Scripts that raise SystemExit should just
330 # return to the interactive prompt
331 pass
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000332 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000333 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000334 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000335 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000336 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000337 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
338 if jit:
339 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000340 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000341 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000342
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000343 def interrupt_the_server(self):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000344 if interruptable:
345 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000346
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000347 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000348 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
349
350 def stop_the_debugger(self, idb_adap_oid):
351 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
352 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000353
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000354 def get_the_calltip(self, name):
355 return self.calltip.fetch_tip(name)
356
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000357 def get_the_completion_list(self, what, mode):
358 return self.autocomplete.fetch_completions(what, mode)
359
Chui Tey5d2af632002-05-26 13:36:41 +0000360 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000361 if self.usr_exc_info:
362 typ, val, tb = self.usr_exc_info
363 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000364 return None
365 flist = None
366 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000367 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000368 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
369 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000370 sys.last_type = typ
371 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000372 item = StackViewer.StackTreeItem(flist, tb)
373 return RemoteObjectBrowser.remote_object_tree_item(item)
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400374
375capture_warnings(False) # Make sure turned off; see issue 18081