blob: 6ffc1b92a07723fd9a9e351c5dd0871b2e8c864d [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",
167 "Socket Error: %s" % err.args[1])
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-"
213 if not line and fn.startswith("<pyshell#"):
214 line = rpchandler.remotecall('linecache', 'getline',
215 (fn, ln), {})
216 tb[i] = fn, ln, nm, line
217
218def flush_stdout():
219 try:
220 if sys.stdout.softspace:
221 sys.stdout.softspace = 0
222 sys.stdout.write("\n")
223 except (AttributeError, EOFError):
224 pass
225
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000226def exit():
227 """Exit subprocess, possibly after first deleting sys.exitfunc
228
229 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
230 sys.exitfunc will be removed before exiting. (VPython support)
231
232 """
233 if no_exitfunc:
Kurt B. Kaiserf30ba3d2008-01-23 22:55:26 +0000234 try:
235 del sys.exitfunc
236 except AttributeError:
237 pass
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400238 capture_warnings(False)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000239 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000240
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000241class MyRPCServer(rpc.RPCServer):
242
243 def handle_error(self, request, client_address):
244 """Override RPCServer method for IDLE
245
246 Interrupt the MainThread and exit server if link is dropped.
247
248 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000249 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000250 try:
251 raise
252 except SystemExit:
253 raise
254 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000255 global exit_now
256 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000257 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000258 except:
259 erf = sys.__stderr__
260 print>>erf, '\n' + '-'*40
261 print>>erf, 'Unhandled server exception!'
262 print>>erf, 'Thread: %s' % threading.currentThread().getName()
263 print>>erf, 'Client Address: ', client_address
264 print>>erf, 'Request: ', repr(request)
265 traceback.print_exc(file=erf)
266 print>>erf, '\n*** Unrecoverable, server exiting!'
267 print>>erf, '-'*40
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000268 quitting = True
269 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000270
Chui Tey5d2af632002-05-26 13:36:41 +0000271class MyHandler(rpc.RPCHandler):
272
273 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000274 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000275 executive = Executive(self)
276 self.register("exec", executive)
Serhiy Storchaka9abc8302013-01-25 15:30:35 +0200277 self.console = self.get_remote_proxy("console")
278 sys.stdin = PyShell.PseudoInputFile(self.console, "stdin",
279 IOBinding.encoding)
280 sys.stdout = PyShell.PseudoOutputFile(self.console, "stdout",
281 IOBinding.encoding)
282 sys.stderr = PyShell.PseudoOutputFile(self.console, "stderr",
283 IOBinding.encoding)
Benjamin Peterson5a271682013-05-11 22:24:28 -0500284
285 # Keep a reference to stdin so that it won't try to exit IDLE if
286 # sys.stdin gets changed from within IDLE's shell. See issue17838.
287 self._keep_stdin = sys.stdin
288
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000289 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000290 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
291
292 def exithook(self):
293 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000294 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000295
296 def EOFhook(self):
297 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000298 global quitting
299 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000300 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000301
302 def decode_interrupthook(self):
303 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000304 global quitting
305 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000306 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000307
Chui Tey5d2af632002-05-26 13:36:41 +0000308
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000309class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000310
311 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000312 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000313 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000314 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000315 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000316
317 def runcode(self, code):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000318 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000319 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000320 self.usr_exc_info = None
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000321 interruptable = True
322 try:
323 exec code in self.locals
324 finally:
325 interruptable = False
Raymond Hettinger42349922013-02-09 14:20:55 -0500326 except SystemExit:
327 # Scripts that raise SystemExit should just
328 # return to the interactive prompt
329 pass
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000330 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000331 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000332 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000333 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000334 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000335 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
336 if jit:
337 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000338 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000339 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000340
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000341 def interrupt_the_server(self):
Kurt B. Kaiserc8f65e62007-10-09 19:31:30 +0000342 if interruptable:
343 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000344
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000345 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000346 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
347
348 def stop_the_debugger(self, idb_adap_oid):
349 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
350 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000351
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000352 def get_the_calltip(self, name):
353 return self.calltip.fetch_tip(name)
354
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000355 def get_the_completion_list(self, what, mode):
356 return self.autocomplete.fetch_completions(what, mode)
357
Chui Tey5d2af632002-05-26 13:36:41 +0000358 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000359 if self.usr_exc_info:
360 typ, val, tb = self.usr_exc_info
361 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000362 return None
363 flist = None
364 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000365 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000366 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
367 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000368 sys.last_type = typ
369 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000370 item = StackViewer.StackTreeItem(flist, tb)
371 return RemoteObjectBrowser.remote_object_tree_item(item)
Terry Jan Reedy8eab0082013-06-28 23:51:34 -0400372
373capture_warnings(False) # Make sure turned off; see issue 18081