blob: a161a93c4dad1d49c244710d163fffd15f4949cf [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
Georg Brandl2067bfd2008-05-25 13:05:15 +00006import _thread as thread
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +00007import threading
Alexandre Vassalottif260e442008-05-11 19:59:59 +00008import queue
Andrew Svetlov05bab932012-03-14 13:22:12 -07009import builtins
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
Andrew Svetlova2251aa2012-03-13 18:36:13 -070042
43def handle_tk_events():
44 """Process any tk events that are ready to be dispatched if tkinter
45 has been imported, a tcl interpreter has been created and tk has been
46 loaded."""
47 tkinter = sys.modules.get('tkinter')
48 if tkinter and tkinter._default_root:
49 # tkinter has been imported, an Tcl interpreter was created and
50 # tk has been loaded.
51 root = tkinter._default_root
52 while root.tk.dooneevent(tkinter._tkinter.DONT_WAIT):
53 # Process pending events.
54 pass
55
56
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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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. Kaisere67842a2009-04-04 20:13:23 +000088 try:
89 assert(len(sys.argv) > 1)
90 port = int(sys.argv[-1])
91 except:
Kurt B. Kaiser8fc98c32009-04-04 20:20:29 +000092 print("IDLE Subprocess: no IP port passed in sys.argv.",
93 file=sys.__stderr__)
Kurt B. Kaisere67842a2009-04-04 20:13:23 +000094 return
Chui Tey5d2af632002-05-26 13:36:41 +000095 sys.argv[:] = [""]
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +000096 sockthread = threading.Thread(target=manage_socket,
97 name='SockThread',
Kurt B. Kaiser24d7e0c2003-06-05 23:51:29 +000098 args=((LOCALHOST, port),))
Benjamin Peterson71088cc2008-09-19 21:49:37 +000099 sockthread.daemon = True
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000100 sockthread.start()
101 while 1:
102 try:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000103 if exit_now:
104 try:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000105 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000106 except KeyboardInterrupt:
107 # exiting but got an extra KBI? Try again!
108 continue
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000109 try:
Kurt B. Kaiser20345fb2005-05-05 23:29:54 +0000110 seq, request = rpc.request_queue.get(block=True, timeout=0.05)
Alexandre Vassalottif260e442008-05-11 19:59:59 +0000111 except queue.Empty:
Andrew Svetlova2251aa2012-03-13 18:36:13 -0700112 handle_tk_events()
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:
122 raise
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000123 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000124 type, value, tb = sys.exc_info()
Kurt B. Kaisera2792be2003-05-17 21:04:10 +0000125 try:
126 print_exception()
127 rpc.response_queue.put((seq, None))
128 except:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000129 # Link didn't work, print same exception to __stderr__
130 traceback.print_exception(type, value, tb, file=sys.__stderr__)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000131 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000132 else:
133 continue
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000134
135def manage_socket(address):
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000136 for i in range(3):
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000137 time.sleep(i)
138 try:
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000139 server = MyRPCServer(address, MyHandler)
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000140 break
Guido van Rossumb940e112007-01-10 16:19:56 +0000141 except socket.error as err:
Georg Brandl6464d472007-10-22 16:16:13 +0000142 print("IDLE Subprocess: socket error: " + err.args[1] +
143 ", retrying....", file=sys.__stderr__)
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000144 socket_error = err
Kurt B. Kaiserb4179362002-07-26 00:06:42 +0000145 else:
Amaury Forgeot d'Arcefae8c42008-11-21 23:08:09 +0000146 print("IDLE Subprocess: Connection to "
147 "IDLE GUI failed, exiting.", file=sys.__stderr__)
148 show_socket_error(socket_error, 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 Brandl14fc4272008-05-17 18:39:55 +0000155 import tkinter
156 import tkinter.messagebox as tkMessageBox
157 root = tkinter.Tk()
Kurt B. Kaiseraf3eb872004-01-21 18:54:30 +0000158 root.withdraw()
Georg Brandl6464d472007-10-22 16:16:13 +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:
Georg Brandl6464d472007-10-22 16:16:13 +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)
Guido van Rossum33d26892007-08-05 15:29:28 +0000178 print('Traceback (most recent call last):', file=efile)
Georg Brandl15a51e32008-05-25 07:17:27 +0000179 exclude = ("run.py", "rpc.py", "threading.py", "queue.py",
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000180 "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:
Guido van Rossum33d26892007-08-05 15:29:28 +0000185 print(line, end='', file=efile)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000186
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[:]
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000207 print("** IDLE Internal Exception: ", file=sys.stderr)
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000208 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():
Guido van Rossum79139b22007-02-09 23:20:19 +0000219 """XXX How to do this now?"""
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000220
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000221def exit():
Guido van Rossumc76a2502007-08-09 14:26:58 +0000222 """Exit subprocess, possibly after first clearing exit functions.
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000223
224 If config-main.cfg/.def 'General' 'delete-exitfunc' is True, then any
Guido van Rossumc76a2502007-08-09 14:26:58 +0000225 functions registered with atexit will be removed before exiting.
226 (VPython support)
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000227
228 """
229 if no_exitfunc:
Guido van Rossumc76a2502007-08-09 14:26:58 +0000230 import atexit
231 atexit._clear()
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000232 sys.exit(0)
Chui Tey5d2af632002-05-26 13:36:41 +0000233
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000234class MyRPCServer(rpc.RPCServer):
235
236 def handle_error(self, request, client_address):
237 """Override RPCServer method for IDLE
238
239 Interrupt the MainThread and exit server if link is dropped.
240
241 """
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000242 global quitting
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000243 try:
244 raise
245 except SystemExit:
246 raise
247 except EOFError:
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000248 global exit_now
249 exit_now = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000250 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000251 except:
252 erf = sys.__stderr__
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000253 print('\n' + '-'*40, file=erf)
254 print('Unhandled server exception!', file=erf)
Amaury Forgeot d'Arcbed17102008-11-29 01:48:47 +0000255 print('Thread: %s' % threading.current_thread().name, file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000256 print('Client Address: ', client_address, file=erf)
257 print('Request: ', repr(request), file=erf)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000258 traceback.print_exc(file=erf)
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000259 print('\n*** Unrecoverable, server exiting!', file=erf)
260 print('-'*40, file=erf)
Kurt B. Kaisere9535112004-11-19 15:46:49 +0000261 quitting = True
262 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000263
264
Andrew Svetlov05bab932012-03-14 13:22:12 -0700265def displayhook(value):
266 """Override standard display hook to use non-locale encoding"""
267 if value is None:
268 return
269 # Set '_' to None to avoid recursion
270 builtins._ = None
271 text = repr(value)
272 try:
273 sys.stdout.write(text)
274 except UnicodeEncodeError:
275 # let's use ascii while utf8-bmp codec doesn't present
276 encoding = 'ascii'
277 bytes = text.encode(encoding, 'backslashreplace')
278 text = bytes.decode(encoding, 'strict')
279 sys.stdout.write(text)
280 sys.stdout.write("\n")
281 builtins._ = value
282
283
Chui Tey5d2af632002-05-26 13:36:41 +0000284class MyHandler(rpc.RPCHandler):
285
286 def handle(self):
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000287 """Override base method"""
Chui Tey5d2af632002-05-26 13:36:41 +0000288 executive = Executive(self)
289 self.register("exec", executive)
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000290 sys.stdin = self.console = self.get_remote_proxy("stdin")
Chui Tey5d2af632002-05-26 13:36:41 +0000291 sys.stdout = self.get_remote_proxy("stdout")
292 sys.stderr = self.get_remote_proxy("stderr")
Andrew Svetlov05bab932012-03-14 13:22:12 -0700293 sys.displayhook = displayhook
Kurt B. Kaiserf609a342007-12-28 03:57:56 +0000294 # page help() text to shell.
295 import pydoc # import must be done here to capture i/o binding
296 pydoc.pager = pydoc.plainpager
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +0000297 from idlelib import IOBinding
Martin v. Löwisbcc651a2003-06-22 07:52:56 +0000298 sys.stdin.encoding = sys.stdout.encoding = \
299 sys.stderr.encoding = IOBinding.encoding
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000300 self.interp = self.get_remote_proxy("interp")
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000301 rpc.RPCHandler.getresponse(self, myseq=None, wait=0.05)
302
303 def exithook(self):
304 "override SocketIO method - wait for MainThread to shut us down"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000305 time.sleep(10)
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000306
307 def EOFhook(self):
308 "Override SocketIO method - terminate wait on callback and exit thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000309 global quitting
310 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000311 thread.interrupt_main()
Kurt B. Kaisera00050f2003-05-08 20:26:55 +0000312
313 def decode_interrupthook(self):
314 "interrupt awakened thread"
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000315 global quitting
316 quitting = True
Kurt B. Kaiser93e8e542003-06-13 22:03:43 +0000317 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000318
Chui Tey5d2af632002-05-26 13:36:41 +0000319
Kurt B. Kaiserdcba6622004-12-21 22:10:32 +0000320class Executive(object):
Chui Tey5d2af632002-05-26 13:36:41 +0000321
322 def __init__(self, rpchandler):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000323 self.rpchandler = rpchandler
Kurt B. Kaiseradc63842002-08-25 14:08:07 +0000324 self.locals = __main__.__dict__
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000325 self.calltip = CallTips.CallTips()
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000326 self.autocomplete = AutoComplete.AutoComplete()
Chui Tey5d2af632002-05-26 13:36:41 +0000327
328 def runcode(self, code):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000329 global interruptable
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000330 try:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000331 self.usr_exc_info = None
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000332 interruptable = True
333 try:
334 exec(code, self.locals)
335 finally:
336 interruptable = False
Kurt B. Kaiser86bc4642003-02-27 23:04:17 +0000337 except:
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000338 self.usr_exc_info = sys.exc_info()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000339 if quitting:
Kurt B. Kaiser62df0442003-05-28 01:47:46 +0000340 exit()
Kurt B. Kaiser67fd0ea2003-05-24 20:59:15 +0000341 # even print a user code SystemExit exception, continue
342 print_exception()
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000343 jit = self.rpchandler.console.getvar("<<toggle-jit-stack-viewer>>")
344 if jit:
345 self.rpchandler.interp.open_remote_stack_viewer()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000346 else:
Kurt B. Kaiser9ec454e2003-05-12 02:33:47 +0000347 flush_stdout()
Chui Tey5d2af632002-05-26 13:36:41 +0000348
Kurt B. Kaiser003091c2003-02-17 18:57:16 +0000349 def interrupt_the_server(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000350 if interruptable:
351 thread.interrupt_main()
Kurt B. Kaiser11c53e22003-03-22 19:40:19 +0000352
Kurt B. Kaiser0e3a5772002-06-16 03:32:24 +0000353 def start_the_debugger(self, gui_adap_oid):
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000354 return RemoteDebugger.start_debugger(self.rpchandler, gui_adap_oid)
355
356 def stop_the_debugger(self, idb_adap_oid):
357 "Unregister the Idb Adapter. Link objects and Idb then subject to GC"
358 self.rpchandler.unregister(idb_adap_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000359
Kurt B. Kaiser5afa1df2002-10-10 08:25:24 +0000360 def get_the_calltip(self, name):
361 return self.calltip.fetch_tip(name)
362
Kurt B. Kaiserb1754452005-11-18 22:05:48 +0000363 def get_the_completion_list(self, what, mode):
364 return self.autocomplete.fetch_completions(what, mode)
365
Chui Tey5d2af632002-05-26 13:36:41 +0000366 def stackviewer(self, flist_oid=None):
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000367 if self.usr_exc_info:
368 typ, val, tb = self.usr_exc_info
369 else:
Chui Tey5d2af632002-05-26 13:36:41 +0000370 return None
371 flist = None
372 if flist_oid is not None:
Kurt B. Kaiserffd3a422002-06-26 02:32:09 +0000373 flist = self.rpchandler.get_remote_proxy(flist_oid)
Chui Tey5d2af632002-05-26 13:36:41 +0000374 while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]:
375 tb = tb.tb_next
Kurt B. Kaiser9f366092003-06-02 01:50:19 +0000376 sys.last_type = typ
377 sys.last_value = val
Chui Tey5d2af632002-05-26 13:36:41 +0000378 item = StackViewer.StackTreeItem(flist, tb)
379 return RemoteObjectBrowser.remote_object_tree_item(item)