blob: abc99697ef917dae4e9d21db84208152c6e151b3 [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Kurt B. Kaisera00050f2003-05-08 20:26:55 +00002import os
Kurt B. Kaiserb4179362002-07-26 00:06:42 +00003import time
4import socket
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +00005import traceback
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00006import threading
7import Queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +00008
Tony Lowndsf53dec22002-12-20 04:24:43 +00009import boolcheck
10
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000011import CallTips
12import RemoteDebugger
13import RemoteObjectBrowser
14import StackViewer
Chui Tey5d2af632002-05-26 13:36:41 +000015import rpc
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000016import interrupt
Chui Tey5d2af632002-05-26 13:36:41 +000017
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000018import __main__
19
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000020# Thread shared globals: Establish a queue between a subthread (which handles
21# the socket) and the main thread (which runs user code), plus global
22# completion and exit flags:
23
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000024exit_now = False
25quitting = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000026
Chui Tey5d2af632002-05-26 13:36:41 +000027def main():
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000028 """Start the Python execution server in a subprocess
29
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000030 In the Python subprocess, RPCServer is instantiated with handlerclass
31 MyHandler, which inherits register/unregister methods from RPCHandler via
32 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000033
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000034 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000035 creates an instance of run.MyHandler and calls its handle() method.
36 handle() instantiates a run.Executive object, passing it a reference to the
37 MyHandler object. That reference is saved as attribute rpchandler of the
38 Executive instance. The Executive methods have access to the reference and
39 can pass it on to entities that they command
40 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
41 call MyHandler(SocketIO) register/unregister methods via the reference to
42 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000043
44 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000045 global exit_now
46 global quitting
Chui Tey5d2af632002-05-26 13:36:41 +000047 port = 8833
48 if sys.argv[1:]:
49 port = int(sys.argv[1])
50 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000051 sockthread = threading.Thread(target=manage_socket,
52 name='SockThread',
53 args=(('localhost', port),))
54 sockthread.setDaemon(True)
55 sockthread.start()
56 while 1:
57 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000058 if exit_now:
59 try:
60 sys.exit(0)
61 except KeyboardInterrupt:
62 # exiting but got an extra KBI? Try again!
63 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000064 try:
65 seq, request = rpc.request_queue.get(0)
66 except Queue.Empty:
67 time.sleep(0.05)
68 continue
69 method, args, kwargs = request
70 ret = method(*args, **kwargs)
71 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000072 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000073 if quitting:
74 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000075 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +000076 except SystemExit:
77 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +000078 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000079 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +000080 try:
81 print_exception()
82 rpc.response_queue.put((seq, None))
83 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000084 # Link didn't work, print same exception to __stderr__
85 traceback.print_exception(type, value, tb, file=sys.__stderr__)
86 sys.exit(0)
87 else:
88 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000089
90def manage_socket(address):
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +000091 for i in range(6):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000092 time.sleep(i)
93 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000094 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000095 break
96 except socket.error, err:
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +000097 if i < 3:
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000098 print>>sys.__stderr__, ".. ",
99 else:
100 print>>sys.__stderr__,"\nPython subprocess socket error: "\
101 + err[1] + ", retrying...."
102 else:
103 print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000104 global exit_now
105 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000106 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000107 server.handle_request() # A single request only
108
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000109def print_exception():
110 flush_stdout()
111 efile = sys.stderr
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000112 typ, val, tb = sys.exc_info()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000113 tbe = traceback.extract_tb(tb)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000114 print >>efile, '\nTraceback (most recent call last):'
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000115 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
116 "RemoteDebugger.py", "bdb.py")
117 cleanup_traceback(tbe, exclude)
118 traceback.print_list(tbe, file=efile)
119 lines = traceback.format_exception_only(typ, val)
120 for line in lines:
121 print>>efile, line,
122
123def cleanup_traceback(tb, exclude):
124 "Remove excluded traces from beginning/end of tb; get cached lines"
125 orig_tb = tb[:]
126 while tb:
127 for rpcfile in exclude:
128 if tb[0][0].count(rpcfile):
129 break # found an exclude, break for: and delete tb[0]
130 else:
131 break # no excludes, have left RPC code, break while:
132 del tb[0]
133 while tb:
134 for rpcfile in exclude:
135 if tb[-1][0].count(rpcfile):
136 break
137 else:
138 break
139 del tb[-1]
140 if len(tb) == 0:
141 # exception was in IDLE internals, don't prune!
142 tb[:] = orig_tb[:]
143 print>>sys.stderr, "** IDLE Internal Exception: "
144 rpchandler = rpc.objecttable['exec'].rpchandler
145 for i in range(len(tb)):
146 fn, ln, nm, line = tb[i]
147 if nm == '?':
148 nm = "-toplevel-"
149 if not line and fn.startswith("<pyshell#"):
150 line = rpchandler.remotecall('linecache', 'getline',
151 (fn, ln), {})
152 tb[i] = fn, ln, nm, line
153
154def flush_stdout():
155 try:
156 if sys.stdout.softspace:
157 sys.stdout.softspace = 0
158 sys.stdout.write("\n")
159 except (AttributeError, EOFError):
160 pass
161
Chui Tey5d2af632002-05-26 13:36:41 +0000162
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000163class MyRPCServer(rpc.RPCServer):
164
165 def handle_error(self, request, client_address):
166 """Override RPCServer method for IDLE
167
168 Interrupt the MainThread and exit server if link is dropped.
169
170 """
171 try:
172 raise
173 except SystemExit:
174 raise
175 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000176 global exit_now
177 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000178 interrupt.interrupt_main()
179 except:
180 erf = sys.__stderr__
181 print>>erf, '\n' + '-'*40
182 print>>erf, 'Unhandled server exception!'
183 print>>erf, 'Thread: %s' % threading.currentThread().getName()
184 print>>erf, 'Client Address: ', client_address
185 print>>erf, 'Request: ', repr(request)
186 traceback.print_exc(file=erf)
187 print>>erf, '\n*** Unrecoverable, server exiting!'
188 print>>erf, '-'*40
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000189 sys.exit(0)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000190
191
Chui Tey5d2af632002-05-26 13:36:41 +0000192class MyHandler(rpc.RPCHandler):
193
194 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000195 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000196 executive = Executive(self)
197 self.register("exec", executive)
198 sys.stdin = self.get_remote_proxy("stdin")
199 sys.stdout = self.get_remote_proxy("stdout")
200 sys.stderr = self.get_remote_proxy("stderr")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000201 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
202
203 def exithook(self):
204 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000205 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000206
207 def EOFhook(self):
208 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000209 global quitting
210 quitting = True
211 interrupt.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000212
213 def decode_interrupthook(self):
214 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000215 global quitting
216 quitting = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000217 interrupt.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000218
Chui Tey5d2af632002-05-26 13:36:41 +0000219
220class Executive:
221
222 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000223 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000224 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000225 self.calltip = CallTips.CallTips()
Chui Tey5d2af632002-05-26 13:36:41 +0000226
227 def runcode(self, code):
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000228 try:
229 exec code in self.locals
230 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000231 if quitting:
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000232 sys.exit(0)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000233 # even print a user code SystemExit exception, continue
234 print_exception()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000235 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000236 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000237
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000238 def interrupt_the_server(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000239 interrupt.interrupt_main()
240
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000241 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000242 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
243
244 def stop_the_debugger(self, idb_adap_oid):
245 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
246 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000247
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000248 def get_the_calltip(self, name):
249 return self.calltip.fetch_tip(name)
250
Chui Tey5d2af632002-05-26 13:36:41 +0000251 def stackviewer(self, flist_oid=None):
252 if not hasattr(sys, "last_traceback"):
253 return None
254 flist = None
255 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000256 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000257 tb = sys.last_traceback
258 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
259 tb = tb.tb_next
260 item = StackViewer.StackTreeItem(flist, tb)
261 return RemoteObjectBrowser.remote_object_tree_item(item)