blob: b0a47942311eb6e8ffa8d6f29f23edcd709ef5dd [file] [log] [blame]
Chui Tey5d2af632002-05-26 13:36:41 +00001import sys
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +02002import io
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +00003import linecache
Kurt B. Kaiserb4179362002-07-26 00:06:42 +00004import time
5import socket
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +00006import traceback
Georg Brandl2067bfd2008-05-25 13:05:15 +00007import _thread as thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00008import threading
Alexandre Vassalottif260e442008-05-11 19:59:59 +00009import queue
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000010
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000011from idlelib import CallTips
12from idlelib import AutoComplete
Kurt B. Kaiserb1754452005-11-18 22:05:48 +000013
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +000014from idlelib import RemoteDebugger
15from idlelib import RemoteObjectBrowser
16from idlelib import StackViewer
17from idlelib import rpc
Chui Tey5d2af632002-05-26 13:36:41 +000018
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000019import __main__
20
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000021LOCALHOST = '127.0.0.1'
22
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000023try:
24 import warnings
25except ImportError:
26 pass
27else:
Benjamin Peterson206e3072008-10-19 14:07:49 +000028 def idle_formatwarning_subproc(message, category, filename, lineno,
Guilherme Polo1fff0082009-08-14 15:05:30 +000029 line=None):
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000030 """Format warnings the IDLE way"""
31 s = "\nWarning (from warnings module):\n"
32 s += ' File \"%s\", line %s\n' % (filename, lineno)
Guilherme Polo1fff0082009-08-14 15:05:30 +000033 if line is None:
34 line = linecache.getline(filename, lineno)
35 line = line.strip()
Kurt B. Kaiser49a5fe12004-07-04 01:25:56 +000036 if line:
37 s += " %s\n" % line
38 s += "%s: %s\n" % (category.__name__, message)
39 return s
40 warnings.formatwarning = idle_formatwarning_subproc
41
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000042# Thread shared globals: Establish a queue between a subthread (which handles
43# the socket) and the main thread (which runs user code), plus global
Guido van Rossum8ce8a782007-11-01 19:42:39 +000044# completion, exit and interruptable (the main thread) flags:
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000045
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000046exit_now = False
47quitting = False
Guido van Rossum8ce8a782007-11-01 19:42:39 +000048interruptable = False
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000049
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000050def main(del_exitfunc=False):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000051 """Start the Python execution server in a subprocess
52
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000053 In the Python subprocess, RPCServer is instantiated with handlerclass
54 MyHandler, which inherits register/unregister methods from RPCHandler via
55 the mix-in class SocketIO.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000056
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000057 When the RPCServer 'server' is instantiated, the TCPServer initialization
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +000058 creates an instance of run.MyHandler and calls its handle() method.
59 handle() instantiates a run.Executive object, passing it a reference to the
60 MyHandler object. That reference is saved as attribute rpchandler of the
61 Executive instance. The Executive methods have access to the reference and
62 can pass it on to entities that they command
63 (e.g. RemoteDebugger.Debugger.start_debugger()). The latter, in turn, can
64 call MyHandler(SocketIO) register/unregister methods via the reference to
65 register and unregister themselves.
Kurt B. Kaiserb4179362002-07-26 00:06:42 +000066
67 """
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000068 global exit_now
69 global quitting
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000070 global no_exitfunc
71 no_exitfunc = del_exitfunc
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +000072 #time.sleep(15) # test subprocess not responding
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000073 try:
74 assert(len(sys.argv) > 1)
75 port = int(sys.argv[-1])
76 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +000077 print("IDLE Subprocess: no IP port passed in sys.argv.",
78 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000079 return
Chui Tey5d2af632002-05-26 13:36:41 +000080 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000081 sockthread = threading.Thread(target=manage_socket,
82 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000083 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000084 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000085 sockthread.start()
86 while 1:
87 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000088 if exit_now:
89 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +000090 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +000091 except KeyboardInterrupt:
92 # exiting but got an extra KBI? Try again!
93 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000094 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +000095 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +000096 except queue.Empty:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +000097 continue
98 method, args, kwargs = request
99 ret = method(*args, **kwargs)
100 rpc.response_queue.put((seq, ret))
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000101 except KeyboardInterrupt:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000102 if quitting:
103 exit_now = True
Kurt B. Kaiseraa6b8562003-05-14 18:15:40 +0000104 continue
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000105 except SystemExit:
106 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000107 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000108 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000109 try:
110 print_exception()
111 rpc.response_queue.put((seq, None))
112 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000113 # Link didn't work, print same exception to __stderr__
114 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000115 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000116 else:
117 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000118
119def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000120 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000121 time.sleep(i)
122 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000123 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000124 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000125 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000126 print("IDLE Subprocess: socket error: " + err.args[1] +
127 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000128 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000129 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000130 print("IDLE Subprocess: Connection to "
131 "IDLE GUI failed, exiting.", file=sys.__stderr__)
132 show_socket_error(socket_error, address)
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000133 global exit_now
134 exit_now = True
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000135 return
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000136 server.handle_request() # A single request only
137
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000138def show_socket_error(err, address):
Georg Brandl14fc4272008-05-17 18:39:55 +0000139 import tkinter
140 import tkinter.messagebox as tkMessageBox
141 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000142 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +0000143 if err.args[0] == 61: # connection refused
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000144 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\
145 "to your personal firewall configuration. It is safe to "\
146 "allow this internal connection because no data is visible on "\
147 "external ports." % address
148 tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root)
149 else:
Georg Brandl6464d472007-10-22 16:16:13 +0000150 tkMessageBox.showerror("IDLE Subprocess Error",
151 "Socket Error: %s" % err.args[1])
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000152 root.destroy()
153
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000154def print_exception():
Kurt B. Kaisere9802a32004-01-02 04:04:04 +0000155 import linecache
156 linecache.checkcache()
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000157 flush_stdout()
158 efile = sys.stderr
Kurt B. Kaiser924f6162003-11-19 04:52:32 +0000159 typ, val, tb = excinfo = sys.exc_info()
160 sys.last_type, sys.last_value, sys.last_traceback = excinfo
Serhiy Storchaka78470b42013-01-09 12:21:57 +0200161 seen = set()
162
163 def print_exc(typ, exc, tb):
164 seen.add(exc)
165 context = exc.__context__
166 cause = exc.__cause__
167 if cause is not None and cause not in seen:
168 print_exc(type(cause), cause, cause.__traceback__)
169 print("\nThe above exception was the direct cause "
170 "of the following exception:\n", file=efile)
171 elif context is not None and context not in seen:
172 print_exc(type(context), context, context.__traceback__)
173 print("\nDuring handling of the above exception, "
174 "another exception occurred:\n", file=efile)
175 if tb:
176 tbe = traceback.extract_tb(tb)
177 print('Traceback (most recent call last):', file=efile)
178 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
179 "RemoteDebugger.py", "bdb.py")
180 cleanup_traceback(tbe, exclude)
181 traceback.print_list(tbe, file=efile)
182 lines = traceback.format_exception_only(typ, exc)
183 for line in lines:
184 print(line, end='', file=efile)
185
186 print_exc(typ, val, tb)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000187
188def cleanup_traceback(tb, exclude):
189 "Remove excluded traces from beginning/end of tb; get cached lines"
190 orig_tb = tb[:]
191 while tb:
192 for rpcfile in exclude:
193 if tb[0][0].count(rpcfile):
194 break # found an exclude, break for: and delete tb[0]
195 else:
196 break # no excludes, have left RPC code, break while:
197 del tb[0]
198 while tb:
199 for rpcfile in exclude:
200 if tb[-1][0].count(rpcfile):
201 break
202 else:
203 break
204 del tb[-1]
205 if len(tb) == 0:
206 # exception was in IDLE internals, don't prune!
207 tb[:] = orig_tb[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000208 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000209 rpchandler = rpc.objecttable['exec'].rpchandler
210 for i in range(len(tb)):
211 fn, ln, nm, line = tb[i]
212 if nm == '?':
213 nm = "-toplevel-"
214 if not line and fn.startswith("<pyshell#"):
215 line = rpchandler.remotecall('linecache', 'getline',
216 (fn, ln), {})
217 tb[i] = fn, ln, nm, line
218
219def flush_stdout():
Guido van Rossum79139b22007-02-09 23:20:19 +0000220 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000221
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000222def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000223 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000224
225 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000226 functions registered with atexit will be removed before exiting.
227 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000228
229 """
230 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000231 import atexit
232 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000233 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000234
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000235class MyRPCServer(rpc.RPCServer):
236
237 def handle_error(self, request, client_address):
238 """Override RPCServer method for IDLE
239
240 Interrupt the MainThread and exit server if link is dropped.
241
242 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000243 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000244 try:
245 raise
246 except SystemExit:
247 raise
248 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000249 global exit_now
250 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000251 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000252 except:
253 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000254 print('\n' + '-'*40, file=erf)
255 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000256 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000257 print('Client Address: ', client_address, file=erf)
258 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000259 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000260 print('\n*** Unrecoverable, server exiting!', file=erf)
261 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000262 quitting = True
263 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000264
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200265class _RPCFile(io.TextIOBase):
Martin v. Löwis1d0f6dd2012-07-09 20:52:40 +0200266 """Wrapper class for the RPC proxy to typecheck arguments
Martin v. Löwisc2761652012-07-11 08:48:34 +0200267 that may not support pickling. The base class is there only
268 to support type tests; all implementations come from the remote
269 object."""
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200270
271 def __init__(self, rpc):
272 super.__setattr__(self, 'rpc', rpc)
273
Martin v. Löwisc2761652012-07-11 08:48:34 +0200274 def __getattribute__(self, name):
Martin v. Löwis67097fd2012-07-11 09:17:15 +0200275 # When accessing the 'rpc' attribute, or 'write', use ours
Martin v. Löwisc882b7c2012-07-25 10:47:20 +0200276 if name in ('rpc', 'write', 'writelines'):
Martin v. Löwisc2761652012-07-11 08:48:34 +0200277 return io.TextIOBase.__getattribute__(self, name)
278 # Else only look into the remote object only
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200279 return getattr(self.rpc, name)
280
281 def __setattr__(self, name, value):
282 return setattr(self.rpc, name, value)
283
Martin v. Löwisc882b7c2012-07-25 10:47:20 +0200284 @staticmethod
285 def _ensure_string(func):
286 def f(self, s):
287 if not isinstance(s, str):
288 raise TypeError('must be str, not ' + type(s).__name__)
289 return func(self, s)
290 return f
291
292class _RPCOutputFile(_RPCFile):
293 @_RPCFile._ensure_string
Martin v. Löwis9ae3f7a2012-07-09 20:46:11 +0200294 def write(self, s):
295 if not isinstance(s, str):
296 raise TypeError('must be str, not ' + type(s).__name__)
297 return self.rpc.write(s)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000298
Martin v. Löwisc882b7c2012-07-25 10:47:20 +0200299class _RPCInputFile(_RPCFile):
300 @_RPCFile._ensure_string
301 def write(self, s):
302 raise io.UnsupportedOperation("not writable")
303 writelines = write
304
Chui Tey5d2af632002-05-26 13:36:41 +0000305class MyHandler(rpc.RPCHandler):
306
307 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000308 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000309 executive = Executive(self)
310 self.register("exec", executive)
Martin v. Löwisc882b7c2012-07-25 10:47:20 +0200311 self.console = self.get_remote_proxy("stdin")
312 sys.stdin = _RPCInputFile(self.console)
313 sys.stdout = _RPCOutputFile(self.get_remote_proxy("stdout"))
314 sys.stderr = _RPCOutputFile(self.get_remote_proxy("stderr"))
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000315 # page help() text to shell.
316 import pydoc # import must be done here to capture i/o binding
317 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000318 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000319 sys.stdin.encoding = sys.stdout.encoding = \
320 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000321 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000322 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
323
324 def exithook(self):
325 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000326 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000327
328 def EOFhook(self):
329 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000330 global quitting
331 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000332 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000333
334 def decode_interrupthook(self):
335 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000336 global quitting
337 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000338 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000339
Chui Tey5d2af632002-05-26 13:36:41 +0000340
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000341class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000342
343 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000344 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000345 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000346 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000347 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000348
349 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000350 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000351 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000352 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000353 interruptable = True
354 try:
355 exec(code, self.locals)
356 finally:
357 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000358 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000359 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000360 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000361 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000362 # even print a user code SystemExit exception, continue
363 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000364 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
365 if jit:
366 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000367 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000368 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000369
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000370 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000371 if interruptable:
372 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000373
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000374 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000375 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
376
377 def stop_the_debugger(self, idb_adap_oid):
378 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
379 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000380
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000381 def get_the_calltip(self, name):
382 return self.calltip.fetch_tip(name)
383
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000384 def get_the_completion_list(self, what, mode):
385 return self.autocomplete.fetch_completions(what, mode)
386
Chui Tey5d2af632002-05-26 13:36:41 +0000387 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000388 if self.usr_exc_info:
389 typ, val, tb = self.usr_exc_info
390 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000391 return None
392 flist = None
393 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000394 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000395 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
396 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000397 sys.last_type = typ
398 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000399 item = StackViewer.StackTreeItem(flist, tb)
400 return RemoteObjectBrowser.remote_object_tree_item(item)