blob: 497cbbd622be457311293f05c27483f423b6b2dc [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Kurt B. Kaiserb4179362002-07-26 00:06:42 +00002import time
3import socket
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +00004import traceback
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00005import threading
6import Queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +00007
Tony Lowndsf53dec22002-12-20 04:24:43 +00008import boolcheck
9
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000010import CallTips
11import RemoteDebugger
12import RemoteObjectBrowser
13import StackViewer
Chui Tey5d2af632002-05-26 13:36:41 +000014import rpc
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000015import interrupt
Chui Tey5d2af632002-05-26 13:36:41 +000016
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000017import __main__
18
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000019# Thread shared globals: Establish a queue between a subthread (which handles
20# the socket) and the main thread (which runs user code), plus global
21# completion and exit flags:
22
23server = None # RPCServer instance
24queue = Queue.Queue(0)
25execution_finished = False
26exit_requested = False
27
28
Chui Tey5d2af632002-05-26 13:36:41 +000029def main():
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000030 """Start the Python execution server in a subprocess
31
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000032 In the Python subprocess, RPCServer is instantiated with handlerclass
33 MyHandler, which inherits register/unregister methods from RPCHandler via
34 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000035
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000036 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000037 creates an instance of run.MyHandler and calls its handle() method.
38 handle() instantiates a run.Executive object, passing it a reference to the
39 MyHandler object. That reference is saved as attribute rpchandler of the
40 Executive instance. The Executive methods have access to the reference and
41 can pass it on to entities that they command
42 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
43 call MyHandler(SocketIO) register/unregister methods via the reference to
44 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000045
46 """
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000047 global queue, execution_finished, exit_requested
48
Chui Tey5d2af632002-05-26 13:36:41 +000049 port = 8833
50 if sys.argv[1:]:
51 port = int(sys.argv[1])
52 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000053 sockthread = threading.Thread(target=manage_socket,
54 name='SockThread',
55 args=(('localhost', port),))
56 sockthread.setDaemon(True)
57 sockthread.start()
58 while 1:
59 try:
60 if exit_requested:
61 sys.exit()
62 # XXX KBK 22Mar03 eventually check queue here!
63 pass
64 time.sleep(0.05)
65 except KeyboardInterrupt:
66 ##execution_finished = True
67 continue
68
69def manage_socket(address):
70 global server, exit_requested
71
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +000072 for i in range(6):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000073 time.sleep(i)
74 try:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000075 server = rpc.RPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000076 break
77 except socket.error, err:
Kurt B. Kaiser8dcdb772002-08-05 03:52:10 +000078 if i < 3:
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000079 print>>sys.__stderr__, ".. ",
80 else:
81 print>>sys.__stderr__,"\nPython subprocess socket error: "\
82 + err[1] + ", retrying...."
83 else:
84 print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000085 exit_requested = True
86 server.handle_request() # A single request only
87
Chui Tey5d2af632002-05-26 13:36:41 +000088
89class MyHandler(rpc.RPCHandler):
90
91 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000092 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +000093 executive = Executive(self)
94 self.register("exec", executive)
95 sys.stdin = self.get_remote_proxy("stdin")
96 sys.stdout = self.get_remote_proxy("stdout")
97 sys.stderr = self.get_remote_proxy("stderr")
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000098 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.5)
99
Chui Tey5d2af632002-05-26 13:36:41 +0000100
101class Executive:
102
103 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000104 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000105 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000106 self.calltip = CallTips.CallTips()
Chui Tey5d2af632002-05-26 13:36:41 +0000107
108 def runcode(self, code):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000109 global queue, execution_finished
110
111 execution_finished = False
112 queue.put(code)
113 # dequeue and run in subthread
114 self.runcode_from_queue()
115 while not execution_finished:
116 time.sleep(0.05)
117
118 def runcode_from_queue(self):
119 global queue, execution_finished
120
121 # poll until queue has code object, using threads, just block?
122 while True:
123 try:
124 code = queue.get(0)
125 break
126 except Queue.Empty:
127 time.sleep(0.05)
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000128 try:
129 exec code in self.locals
130 except:
Kurt B. Kaiserb6aff152003-03-03 20:06:48 +0000131 self.flush_stdout()
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000132 efile = sys.stderr
133 typ, val, tb = info = sys.exc_info()
134 sys.last_type, sys.last_value, sys.last_traceback = info
135 tbe = traceback.extract_tb(tb)
Kurt B. Kaiserb6aff152003-03-03 20:06:48 +0000136 print >>efile, 'Traceback (most recent call last):'
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000137 exclude = ("run.py", "rpc.py", "RemoteDebugger.py", "bdb.py")
138 self.cleanup_traceback(tbe, exclude)
139 traceback.print_list(tbe, file=efile)
140 lines = traceback.format_exception_only(typ, val)
141 for line in lines:
142 print>>efile, line,
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000143 execution_finished = True
144 else:
145 self.flush_stdout()
146 execution_finished = True
Kurt B. Kaiserb6aff152003-03-03 20:06:48 +0000147
148 def flush_stdout(self):
149 try:
150 if sys.stdout.softspace:
151 sys.stdout.softspace = 0
152 sys.stdout.write("\n")
Kurt B. Kaiser7c221322003-03-11 22:55:56 +0000153 except (AttributeError, EOFError):
Kurt B. Kaiserb6aff152003-03-03 20:06:48 +0000154 pass
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000155
156 def cleanup_traceback(self, tb, exclude):
157 "Remove excluded traces from beginning/end of tb; get cached lines"
158 orig_tb = tb[:]
159 while tb:
160 for rpcfile in exclude:
161 if tb[0][0].count(rpcfile):
162 break # found an exclude, break for: and delete tb[0]
163 else:
164 break # no excludes, have left RPC code, break while:
165 del tb[0]
166 while tb:
167 for rpcfile in exclude:
168 if tb[-1][0].count(rpcfile):
169 break
170 else:
171 break
172 del tb[-1]
173 if len(tb) == 0:
174 # exception was in IDLE internals, don't prune!
175 tb[:] = orig_tb[:]
176 print>>sys.stderr, "** IDLE Internal Exception: "
177 for i in range(len(tb)):
178 fn, ln, nm, line = tb[i]
179 if nm == '?':
180 nm = "-toplevel-"
181 if not line and fn.startswith("<pyshell#"):
182 line = self.rpchandler.remotecall('linecache', 'getline',
183 (fn, ln), {})
184 tb[i] = fn, ln, nm, line
Chui Tey5d2af632002-05-26 13:36:41 +0000185
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000186 def interrupt_the_server(self):
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000187 self.rpchandler.interrupted = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000188 ##print>>sys.__stderr__, "** Interrupt main!"
189 interrupt.interrupt_main()
190
191 def shutdown_the_server(self):
192 global exit_requested
193
194 exit_requested = True
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000195
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000196 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000197 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
198
199 def stop_the_debugger(self, idb_adap_oid):
200 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
201 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000202
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000203 def get_the_calltip(self, name):
204 return self.calltip.fetch_tip(name)
205
Chui Tey5d2af632002-05-26 13:36:41 +0000206 def stackviewer(self, flist_oid=None):
207 if not hasattr(sys, "last_traceback"):
208 return None
209 flist = None
210 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000211 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000212 tb = sys.last_traceback
213 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
214 tb = tb.tb_next
215 item = StackViewer.StackTreeItem(flist, tb)
216 return RemoteObjectBrowser.remote_object_tree_item(item)