blob: ad23793c3d14b77e470f964ab450c8bcedfd73c3 [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. Kaiser11c53e22003-03-22 19:40:19 +000024exit_requested = False
25
Chui Tey5d2af632002-05-26 13:36:41 +000026def main():
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000027 """Start the Python execution server in a subprocess
28
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000029 In the Python subprocess, RPCServer is instantiated with handlerclass
30 MyHandler, which inherits register/unregister methods from RPCHandler via
31 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000032
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000033 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000034 creates an instance of run.MyHandler and calls its handle() method.
35 handle() instantiates a run.Executive object, passing it a reference to the
36 MyHandler object. That reference is saved as attribute rpchandler of the
37 Executive instance. The Executive methods have access to the reference and
38 can pass it on to entities that they command
39 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
40 call MyHandler(SocketIO) register/unregister methods via the reference to
41 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000042
43 """
Chui Tey5d2af632002-05-26 13:36:41 +000044 port = 8833
45 if sys.argv[1:]:
46 port = int(sys.argv[1])
47 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000048 sockthread = threading.Thread(target=manage_socket,
49 name='SockThread',
50 args=(('localhost', port),))
51 sockthread.setDaemon(True)
52 sockthread.start()
53 while 1:
54 try:
55 if exit_requested:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000056 os._exit(0)
57 try:
58 seq, request = rpc.request_queue.get(0)
59 except Queue.Empty:
60 time.sleep(0.05)
61 continue
62 method, args, kwargs = request
63 ret = method(*args, **kwargs)
64 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +000065 except KeyboardInterrupt:
66 continue
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +000067 except:
68 print_exception()
69 rpc.response_queue.put((seq, None))
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000070 continue
71
72def manage_socket(address):
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +000073 for i in range(6):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000074 time.sleep(i)
75 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000076 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000077 break
78 except socket.error, err:
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +000079 if i < 3:
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000080 print>>sys.__stderr__, ".. ",
81 else:
82 print>>sys.__stderr__,"\nPython subprocess socket error: "\
83 + err[1] + ", retrying...."
84 else:
85 print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000086 global exit_requested
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000087 exit_requested = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000088 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000089 server.handle_request() # A single request only
90
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +000091def print_exception():
92 flush_stdout()
93 efile = sys.stderr
94 typ, val, tb = info = sys.exc_info()
95 tbe = traceback.extract_tb(tb)
96 print >>efile, 'Traceback (most recent call last):'
97 exclude = ("run.py", "rpc.py", "threading.py", "Queue.py",
98 "RemoteDebugger.py", "bdb.py")
99 cleanup_traceback(tbe, exclude)
100 traceback.print_list(tbe, file=efile)
101 lines = traceback.format_exception_only(typ, val)
102 for line in lines:
103 print>>efile, line,
104
105def cleanup_traceback(tb, exclude):
106 "Remove excluded traces from beginning/end of tb; get cached lines"
107 orig_tb = tb[:]
108 while tb:
109 for rpcfile in exclude:
110 if tb[0][0].count(rpcfile):
111 break # found an exclude, break for: and delete tb[0]
112 else:
113 break # no excludes, have left RPC code, break while:
114 del tb[0]
115 while tb:
116 for rpcfile in exclude:
117 if tb[-1][0].count(rpcfile):
118 break
119 else:
120 break
121 del tb[-1]
122 if len(tb) == 0:
123 # exception was in IDLE internals, don't prune!
124 tb[:] = orig_tb[:]
125 print>>sys.stderr, "** IDLE Internal Exception: "
126 rpchandler = rpc.objecttable['exec'].rpchandler
127 for i in range(len(tb)):
128 fn, ln, nm, line = tb[i]
129 if nm == '?':
130 nm = "-toplevel-"
131 if not line and fn.startswith("<pyshell#"):
132 line = rpchandler.remotecall('linecache', 'getline',
133 (fn, ln), {})
134 tb[i] = fn, ln, nm, line
135
136def flush_stdout():
137 try:
138 if sys.stdout.softspace:
139 sys.stdout.softspace = 0
140 sys.stdout.write("\n")
141 except (AttributeError, EOFError):
142 pass
143
Chui Tey5d2af632002-05-26 13:36:41 +0000144
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000145class MyRPCServer(rpc.RPCServer):
146
147 def handle_error(self, request, client_address):
148 """Override RPCServer method for IDLE
149
150 Interrupt the MainThread and exit server if link is dropped.
151
152 """
153 try:
154 raise
155 except SystemExit:
156 raise
157 except EOFError:
158 global exit_requested
159 exit_requested = True
160 interrupt.interrupt_main()
161 except:
162 erf = sys.__stderr__
163 print>>erf, '\n' + '-'*40
164 print>>erf, 'Unhandled server exception!'
165 print>>erf, 'Thread: %s' % threading.currentThread().getName()
166 print>>erf, 'Client Address: ', client_address
167 print>>erf, 'Request: ', repr(request)
168 traceback.print_exc(file=erf)
169 print>>erf, '\n*** Unrecoverable, server exiting!'
170 print>>erf, '-'*40
171 os._exit(0)
172
173
Chui Tey5d2af632002-05-26 13:36:41 +0000174class MyHandler(rpc.RPCHandler):
175
176 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000177 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000178 executive = Executive(self)
179 self.register("exec", executive)
180 sys.stdin = self.get_remote_proxy("stdin")
181 sys.stdout = self.get_remote_proxy("stdout")
182 sys.stderr = self.get_remote_proxy("stderr")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000183 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
184
185 def exithook(self):
186 "override SocketIO method - wait for MainThread to shut us down"
187 while 1: pass
188
189 def EOFhook(self):
190 "Override SocketIO method - terminate wait on callback and exit thread"
191 global exit_requested
192 exit_requested = True
193
194 def decode_interrupthook(self):
195 "interrupt awakened thread"
196 interrupt.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000197
Chui Tey5d2af632002-05-26 13:36:41 +0000198
199class Executive:
200
201 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000202 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000203 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000204 self.calltip = CallTips.CallTips()
Chui Tey5d2af632002-05-26 13:36:41 +0000205
206 def runcode(self, code):
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000207 try:
208 exec code in self.locals
209 except:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000210 try:
211 if exit_requested:
212 os._exit(0)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000213 print_exception()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000214 except:
215 sys.stderr = sys.__stderr__
216 raise
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000217 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000218 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000219
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000220 def interrupt_the_server(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000221 interrupt.interrupt_main()
222
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000223 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000224 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
225
226 def stop_the_debugger(self, idb_adap_oid):
227 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
228 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000229
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000230 def get_the_calltip(self, name):
231 return self.calltip.fetch_tip(name)
232
Chui Tey5d2af632002-05-26 13:36:41 +0000233 def stackviewer(self, flist_oid=None):
234 if not hasattr(sys, "last_traceback"):
235 return None
236 flist = None
237 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000238 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000239 tb = sys.last_traceback
240 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
241 tb = tb.tb_next
242 item = StackViewer.StackTreeItem(flist, tb)
243 return RemoteObjectBrowser.remote_object_tree_item(item)