]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/DebuggerHarness.py
More updates to the docview library modules and sample apps from the
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / DebuggerHarness.py
1 #----------------------------------------------------------------------------
2 # Name: DebuggerHarness.py
3 # Purpose:
4 #
5 # Author: Matt Fryer
6 #
7 # Created: 7/28/04
8 # CVS-ID: $Id$
9 # Copyright: (c) 2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12 import bdb
13 import sys
14 import SimpleXMLRPCServer
15 import threading
16 import xmlrpclib
17 import os
18 import types
19 import Queue
20 import traceback
21 import inspect
22 from xml.dom.minidom import getDOMImplementation
23 import atexit
24 import pickle
25
26 if sys.platform.startswith("win"):
27 import win32api
28 _WINDOWS = True
29 else:
30 _WINDOWS = False
31
32 _VERBOSE = False
33 _DEBUG_DEBUGGER = False
34
35 class Adb(bdb.Bdb):
36
37 def __init__(self, harness, queue):
38 bdb.Bdb.__init__(self)
39 self._harness = harness
40 self._userBreak = False
41 self._queue = queue
42 self._knownCantExpandFiles = {}
43 self._knownExpandedFiles = {}
44
45 def getLongName(self, filename):
46 if not _WINDOWS:
47 return filename
48 if self._knownCantExpandFiles.get(filename):
49 return filename
50 if self._knownExpandedFiles.get(filename):
51 return self._knownExpandedFiles.get(filename)
52 try:
53 newname = win32api.GetLongPathName(filename)
54 self._knownExpandedFiles[filename] = newname
55 return newname
56 except:
57 self._knownCantExpandFiles[filename] = filename
58 return filename
59
60 def canonic(self, orig_filename):
61 if orig_filename == "<" + orig_filename[1:-1] + ">":
62 return orig_filename
63 filename = self.getLongName(orig_filename)
64
65 canonic = self.fncache.get(filename)
66 if not canonic:
67 canonic = os.path.abspath(filename)
68 canonic = os.path.normcase(canonic)
69 self.fncache[filename] = canonic
70 return canonic
71
72
73 # Overriding this so that we continue to trace even if no breakpoints are set.
74 def set_continue(self):
75 self.stopframe = self.botframe
76 self.returnframe = None
77 self.quitting = 0
78
79 def do_clear(self, arg):
80 bdb.Breakpoint.bpbynumber[int(arg)].deleteMe()
81
82 def user_line(self, frame):
83 if self.in_debugger_code(frame):
84 self.set_step()
85 return
86 message = self.__frame2message(frame)
87 self._harness.interaction(message, frame, "")
88
89 def user_call(self, frame, argument_list):
90 if self.in_debugger_code(frame):
91 self.set_step()
92 return
93 if self.stop_here(frame):
94 message = self.__frame2message(frame)
95 self._harness.interaction(message, frame, "")
96
97 def user_return(self, frame, return_value):
98 if self.in_debugger_code(frame):
99 self.set_step()
100 return
101 message = self.__frame2message(frame)
102 self._harness.interaction(message, frame, "")
103
104 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
105 frame.f_locals['__exception__'] = exc_type, exc_value
106 if type(exc_type) == type(''):
107 exc_type_name = exc_type
108 else:
109 exc_type_name = exc_type.__name__
110 message = "Exception occured: " + repr(exc_type_name) + " See locals.__exception__ for details."
111 traceback.print_exception(exc_type, exc_value, exc_traceback)
112 self._harness.interaction(message, frame, message)
113
114 def in_debugger_code(self, frame):
115 if _DEBUG_DEBUGGER: return False
116 message = self.__frame2message(frame)
117 return message.count('DebuggerHarness') > 0
118
119 def frame2message(self, frame):
120 return self.__frame2message(frame)
121
122 def __frame2message(self, frame):
123 code = frame.f_code
124 filename = code.co_filename
125 lineno = frame.f_lineno
126 basename = os.path.basename(filename)
127 message = "%s:%s" % (basename, lineno)
128 if code.co_name != "?":
129 message = "%s: %s()" % (message, code.co_name)
130 return message
131
132 def runFile(self, fileName):
133 self.reset()
134 #global_dict = {}
135 #global_dict['__name__'] = '__main__'
136 try:
137 fileToRun = open(fileName, mode='r')
138 if _VERBOSE: print "Running file ", fileName
139 sys.settrace(self.trace_dispatch)
140 import __main__
141 exec fileToRun in __main__.__dict__,__main__.__dict__
142 except SystemExit:
143 pass
144 except:
145 tp, val, tb = sys.exc_info()
146 traceback.print_exception(tp, val, tb)
147
148 sys.settrace(None)
149 self.quitting = 1
150 #global_dict.clear()
151
152 def trace_dispatch(self, frame, event, arg):
153 if self.quitting:
154 return # None
155 # Check for ui events
156 self.readQueue()
157 if event == 'line':
158 return self.dispatch_line(frame)
159 if event == 'call':
160 return self.dispatch_call(frame, arg)
161 if event == 'return':
162 return self.dispatch_return(frame, arg)
163 if event == 'exception':
164 return self.dispatch_exception(frame, arg)
165 print 'Adb.dispatch: unknown debugging event:', `event`
166 return self.trace_dispatch
167
168 def readQueue(self):
169 while self._queue.qsize():
170 try:
171 item = self._queue.get_nowait()
172 if item.kill():
173 self._harness.do_exit(kill=True)
174 elif item.breakHere():
175 self._userBreak = True
176 elif item.hasBreakpoints():
177 self.set_all_breakpoints(item.getBreakpoints())
178 except Queue.Empty:
179 pass
180
181 def set_all_breakpoints(self, dict):
182 self.clear_all_breaks()
183 for fileName in dict.keys():
184 lineList = dict[fileName]
185 for lineNumber in lineList:
186
187 if _VERBOSE: print "Setting break at line ", str(lineNumber), " in file ", self.canonic(fileName)
188 self.set_break(fileName, int(lineNumber))
189 return ""
190
191 def stop_here(self, frame):
192 if( self._userBreak ):
193 self._userBreak = False
194 return True
195
196
197 # (CT) stopframe may now also be None, see dispatch_call.
198 # (CT) the former test for None is therefore removed from here.
199 if frame is self.stopframe:
200 return True
201 while frame is not None and frame is not self.stopframe:
202 if frame is self.botframe:
203 return True
204 frame = frame.f_back
205 return False
206
207 class BreakNotify(object):
208 def __init__(self, bps=None, break_here=False, kill=False):
209 self._bps = bps
210 self._break_here = break_here
211 self._kill = kill
212
213 def breakHere(self):
214 return self._break_here
215
216 def kill(self):
217 return self._kill
218
219 def getBreakpoints(self):
220 return self._bps
221
222 def hasBreakpoints(self):
223 return (self._bps != None)
224
225 class AGXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
226 def __init__(self, address, logRequests=0):
227 SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, logRequests=logRequests)
228
229 class BreakListenerThread(threading.Thread):
230 def __init__(self, host, port, queue):
231 threading.Thread.__init__(self)
232 self._host = host
233 self._port = int(port)
234 self._keepGoing = True
235 self._queue = queue
236 self._server = AGXMLRPCServer((self._host, self._port), logRequests=0)
237 self._server.register_function(self.update_breakpoints)
238 self._server.register_function(self.break_requested)
239 self._server.register_function(self.die)
240
241 def break_requested(self):
242 bn = BreakNotify(break_here=True)
243 self._queue.put(bn)
244 return ""
245
246 def update_breakpoints(self, pickled_Binary_bpts):
247 dict = pickle.loads(pickled_Binary_bpts.data)
248 bn = BreakNotify(bps=dict)
249 self._queue.put(bn)
250 return ""
251
252 def die(self):
253 bn = BreakNotify(kill=True)
254 self._queue.put(bn)
255 return ""
256
257 def run(self):
258 while self._keepGoing:
259 try:
260 self._server.handle_request()
261 except:
262 if _VERBOSE:
263 tp, val, tb = sys.exc_info()
264 print "Exception in BreakListenerThread.run():", str(tp), str(val)
265 self._keepGoing = False
266
267 def AskToStop(self):
268 self._keepGoing = False
269 if type(self._server) is not types.NoneType:
270 if _VERBOSE: print "Before calling server close on breakpoint server"
271 self._server.server_close()
272 if _VERBOSE: print "Calling server close on breakpoint server"
273
274
275 class DebuggerHarness(object):
276
277 def __init__(self):
278 # Host and port for debugger-side RPC server
279 self._hostname = sys.argv[1]
280 self._portNumber = int(sys.argv[2])
281 # Name the gui proxy object is registered under
282 self._breakPortNumber = int(sys.argv[3])
283 # Host and port where the gui proxy can be found.
284 self._guiHost = sys.argv[4]
285 self._guiPort = int(sys.argv[5])
286 # Command to debug.
287 self._command = sys.argv[6]
288 # Strip out the harness' arguments so that the process we run will see argv as if
289 # it was called directly.
290 sys.argv = sys.argv[6:]
291 self._currentFrame = None
292 self._wait = False
293 # Connect to the gui-side RPC server.
294 self._guiServerUrl = 'http://' + self._guiHost + ':' + str(self._guiPort) + '/'
295 if _VERBOSE: print "Connecting to gui server at ", self._guiServerUrl
296 self._guiServer = xmlrpclib.ServerProxy(self._guiServerUrl,allow_none=1)
297
298 # Start the break listener
299 self._breakQueue = Queue.Queue(50)
300 self._breakListener = BreakListenerThread(self._hostname, self._breakPortNumber, self._breakQueue)
301 self._breakListener.start()
302 # Create the debugger.
303 self._adb = Adb(self, self._breakQueue)
304
305 # Create the debugger-side RPC Server and register functions for remote calls.
306 self._server = AGXMLRPCServer((self._hostname, self._portNumber), logRequests=0)
307 self._server.register_function(self.set_step)
308 self._server.register_function(self.set_continue)
309 self._server.register_function(self.set_next)
310 self._server.register_function(self.set_return)
311 self._server.register_function(self.set_breakpoint)
312 self._server.register_function(self.clear_breakpoint)
313 self._server.register_function(self.set_all_breakpoints)
314 self._server.register_function(self.attempt_introspection)
315 self._server.register_function(self.add_watch)
316
317 self.message_frame_dict = {}
318 self.introspection_list = []
319 atexit.register(self.do_exit)
320
321 def run(self):
322 self._adb.runFile(self._command)
323 self.do_exit(kill=True)
324
325
326 def do_exit(self, kill=False):
327 self._adb.set_quit()
328 self._breakListener.AskToStop()
329 self._server.server_close()
330 try:
331 self._guiServer.quit()
332 except:
333 pass
334 if kill:
335 try:
336 sys.exit()
337 except:
338 pass
339
340 def set_breakpoint(self, fileName, lineNo):
341 self._adb.set_break(fileName, lineNo)
342 return ""
343
344 def set_all_breakpoints(self, dict):
345 self._adb.clear_all_breaks()
346 for fileName in dict.keys():
347 lineList = dict[fileName]
348 for lineNumber in lineList:
349 self._adb.set_break(fileName, int(lineNumber))
350 if _VERBOSE: print "Setting break at ", str(lineNumber), " in file ", fileName
351 return ""
352
353 def clear_breakpoint(self, fileName, lineNo):
354 self._adb.clear_break(fileName, lineNo)
355 return ""
356
357 def add_watch(self, name, text, frame_message, run_once):
358 if len(frame_message) > 0:
359 frame = self.message_frame_dict[frame_message]
360 try:
361 item = eval(text, frame.f_globals, frame.f_locals)
362 return self.get_watch_document(item, name)
363 except:
364 tp, val, tb = sys.exc_info()
365 return self.get_exception_document(tp, val, tb)
366 return ""
367
368 def attempt_introspection(self, frame_message, chain):
369 try:
370 frame = self.message_frame_dict[frame_message]
371 if frame:
372 name = chain.pop(0)
373 if name == 'globals':
374 item = frame.f_globals
375 elif name == 'locals':
376 item = frame.f_locals
377
378 for name in chain:
379 item = self.getNextItem(item, name)
380 return self.get_introspection_document(item, name)
381 except:
382 tp, val, tb = sys.exc_info()
383 traceback.print_exception(tp, val, tb)
384 return self.get_empty_introspection_document()
385
386 def getNextItem(self, link, identifier):
387 tp = type(link)
388 if self.isTupleized(identifier):
389 return self.deTupleize(link, identifier)
390 else:
391 if tp == types.DictType or tp == types.DictProxyType:
392 return link[identifier]
393 else:
394 if hasattr(link, identifier):
395 return getattr(link, identifier)
396 if _VERBOSE or True: print "Failed to find link ", identifier, " on thing: ", self.saferepr(link), " of type ", repr(type(link))
397 return None
398
399 def isPrimitive(self, item):
400 tp = type(item)
401 return tp is types.IntType or tp is types.LongType or tp is types.FloatType \
402 or tp is types.BooleanType or tp is types.ComplexType \
403 or tp is types.StringType
404
405 def isTupleized(self, value):
406 return value.count('[')
407
408 def deTupleize(self, link, string1):
409 try:
410 start = string1.find('[')
411 end = string1.find(']')
412 num = int(string1[start+1:end])
413 return link[num]
414 except:
415 tp,val,tb = sys.exc_info()
416 if _VERBOSE: print "Got exception in deTupleize: ", val
417 return None
418
419 def wrapAndCompress(self, stringDoc):
420 import bz2
421 return xmlrpclib.Binary(bz2.compress(stringDoc))
422
423 def get_empty_introspection_document(self):
424 doc = getDOMImplementation().createDocument(None, "replacement", None)
425 return self.wrapAndCompress(doc.toxml())
426
427 def get_watch_document(self, item, identifier):
428 doc = getDOMImplementation().createDocument(None, "watch", None)
429 top_element = doc.documentElement
430 self.addAny(top_element, identifier, item, doc, 2)
431 return self.wrapAndCompress(doc.toxml())
432
433 def get_introspection_document(self, item, identifier):
434 doc = getDOMImplementation().createDocument(None, "replacement", None)
435 top_element = doc.documentElement
436 self.addAny(top_element, identifier, item, doc, 2)
437 return self.wrapAndCompress(doc.toxml())
438
439 def get_exception_document(self, name, tp, val, tb):
440 stack = traceback.format_exception(tp, val, tb)
441 wholeStack = ""
442 for line in stack:
443 wholeStack += line
444 doc = getDOMImplementation().createDocument(None, "watch", None)
445 top_element = doc.documentElement
446 item_node = doc.createElement("dict_nv_element")
447 item_node.setAttribute('value', wholeStack)
448 item_node.setAttribute('name', str(name))
449 top_element.appendChild(item_node)
450
451 cantIntro = [types.FunctionType,
452 types.LambdaType,
453 types.UnicodeType,
454 types.StringType,
455 types.NoneType,
456 types.IntType,
457 types.LongType,
458 types.FloatType,
459 types.BooleanType]
460
461 def addAny(self, top_element, name, item, doc, ply):
462 tp = type(item)
463
464 if tp in DebuggerHarness.cantIntro or ply < 1:
465 self.addNode(top_element,name, item, doc)
466 elif tp is types.TupleType or tp is types.ListType:
467 self.addTupleOrList(top_element, name, item, doc, ply - 1)
468 elif tp is types.DictType or tp is types.DictProxyType:
469 self.addDict(top_element, name, item, doc, ply -1)
470 elif inspect.ismodule(item):
471 self.addModule(top_element, name, item, doc, ply -1)
472 elif inspect.isclass(item) or tp is types.InstanceType:
473 self.addClass(top_element, name, item, doc, ply -1)
474 elif hasattr(item, '__dict__'):
475 self.addDictAttr(top_element, name, item, doc, ply -1)
476 else:
477 self.addNode(top_element,name, item, doc)
478
479
480 def canIntrospect(self, item):
481 tp = type(item)
482 if tp in DebuggerHarness.cantIntro:
483 return False
484 elif tp is types.TupleType or tp is types.ListType:
485 return len(item) > 0
486 elif tp is types.DictType or tp is types.DictProxyType:
487 return len(item) > 0
488 elif inspect.ismodule(item):
489 return True
490 elif inspect.isclass(item) or tp is types.InstanceType:
491 if hasattr(item, '__dict__'):
492 return True
493 elif hasattr(item, '__name__'):
494 return True
495 elif hasattr(item, '__module__'):
496 return True
497 elif hasattr(item, '__doc__'):
498 return True
499 else:
500 return False
501 elif hasattr(item, '__dict__'):
502 return len(item.__dict__) > 0
503 else:
504 return False
505
506 def addNode(self, parent_node, name, item, document):
507 item_node = document.createElement("dict_nv_element")
508 item_node.setAttribute('value', self.saferepr(item))
509 item_node.setAttribute('name', str(name))
510 introVal = str(self.canIntrospect(item))
511 item_node.setAttribute('intro', str(introVal))
512 parent_node.appendChild(item_node)
513
514
515 def addTupleOrList(self, top_node, name, tupple, doc, ply):
516 tupleNode = doc.createElement('tuple')
517 tupleNode.setAttribute('name', str(name))
518 tupleNode.setAttribute('value', self.saferepr(tupple))
519 top_node.appendChild(tupleNode)
520 count = 0
521 for item in tupple:
522 self.addAny(tupleNode, name +'[' + str(count) + ']',item, doc, ply -1)
523 count += 1
524
525 def addDictAttr(self, root_node, name, thing, document, ply):
526 dict_node = document.createElement('thing')
527 dict_node.setAttribute('name', name)
528 dict_node.setAttribute('value', self.saferepr(thing))
529 root_node.appendChild(dict_node)
530 self.addDict(dict_node, '', thing.__dict__, document, ply) # Not decreminting ply
531
532 def addDict(self, root_node, name, dict, document, ply):
533 if name != '':
534 dict_node = document.createElement('dict')
535 dict_node.setAttribute('name', name)
536 dict_node.setAttribute('value', self.saferepr(dict))
537 root_node.appendChild(dict_node)
538 else:
539 dict_node = root_node
540 for key in dict.keys():
541 strkey = str(key)
542 try:
543 value = dict[key]
544 self.addAny(dict_node, strkey, value, document, ply-1)
545 except:
546 if _VERBOSE:
547 tp,val,tb=sys.exc_info()
548 print "Error recovering key: ", str(key), " from node ", str(name), " Val = ", str(val)
549 traceback.print_exception(tp, val, tb)
550
551 def addClass(self, root_node, name, class_item, document, ply):
552 item_node = document.createElement('class')
553 item_node.setAttribute('name', str(name))
554 item_node.setAttribute('value', self.saferepr(class_item))
555 root_node.appendChild(item_node)
556 try:
557 if hasattr(class_item, '__dict__'):
558 self.addDict(item_node, '', class_item.__dict__, document, ply -1)
559 except:
560 tp,val,tb=sys.exc_info()
561 if _VERBOSE:
562 traceback.print_exception(tp, val, tb)
563 try:
564 if hasattr(class_item, '__name__'):
565 self.addAny(item_node,'__name__',class_item.__name__, document, ply -1)
566 except:
567 tp,val,tb=sys.exc_info()
568 if _VERBOSE:
569 traceback.print_exception(tp, val, tb)
570 try:
571 if hasattr(class_item, '__module__'):
572 self.addAny(item_node, '__module__', class_item.__module__, document, ply -1)
573 except:
574 tp,val,tb=sys.exc_info()
575 if _VERBOSE:
576 traceback.print_exception(tp, val, tb)
577 try:
578 if hasattr(class_item, '__doc__'):
579 self.addAny(item_node, '__doc__', class_item.__doc__, document, ply -1)
580 except:
581 tp,val,tb=sys.exc_info()
582 if _VERBOSE:
583 traceback.print_exception(tp, val, tb)
584 try:
585 if hasattr(class_item, '__bases__'):
586 self.addAny(item_node, '__bases__', class_item.__bases__, document, ply -1)
587 except:
588 tp,val,tb=sys.exc_info()
589 if _VERBOSE:
590 traceback.print_exception(tp, val, tb)
591
592 def addModule(self, root_node, name, module_item, document, ply):
593 item_node = document.createElement('module')
594 item_node.setAttribute('name', str(name))
595 item_node.setAttribute('value', self.saferepr(module_item))
596 root_node.appendChild(item_node)
597 try:
598 if hasattr(module_item, '__file__'):
599 self.addAny(item_node, '__file__', module_item.__file__, document, ply -1)
600 except:
601 pass
602 try:
603 if hasattr(module_item, '__doc__'):
604 self.addAny(item_node,'__doc__', module_item.__doc__, document, ply -1)
605 except:
606 pass
607
608
609
610 def getFrameXML(self, base_frame):
611 doc = getDOMImplementation().createDocument(None, "stack", None)
612 top_element = doc.documentElement
613
614 stack = []
615 frame = base_frame
616 while frame is not None:
617 if((frame.f_code.co_filename.count('DebuggerHarness.py') == 0) or _DEBUG_DEBUGGER):
618 stack.append(frame)
619 frame = frame.f_back
620 stack.reverse()
621 self.message_frame_dict = {}
622 for f in stack:
623 self.addFrame(f,top_element, doc)
624 return doc.toxml()
625
626 def addFrame(self, frame, root_element, document):
627 frameNode = document.createElement('frame')
628 root_element.appendChild(frameNode)
629
630 code = frame.f_code
631 filename = code.co_filename
632 frameNode.setAttribute('file', str(filename))
633 frameNode.setAttribute('line', str(frame.f_lineno))
634 message = self._adb.frame2message(frame)
635 frameNode.setAttribute('message', message)
636 #print "Frame: %s %s %s" %(message, frame.f_lineno, filename)
637 self.message_frame_dict[message] = frame
638 self.addDict(frameNode, "locals", frame.f_locals, document, 2)
639 self.addNode(frameNode, "globals", frame.f_globals, document)
640
641 def getRepr(self, varName, globals, locals):
642 try:
643 return repr(eval(varName, globals, locals))
644 except:
645 return 'Error: Could not recover value.'
646
647
648 def saferepr(self, thing):
649 try:
650 return repr(thing)
651 except:
652 tp, val, tb = sys.exc_info()
653 traceback.print_exception(tp, val, tb)
654 return repr(val)
655
656 # The debugger calls this method when it reaches a breakpoint.
657 def interaction(self, message, frame, info):
658 if _VERBOSE:
659 print 'hit debug side interaction'
660 self._userBreak = False
661
662 self._currentFrame = frame
663 done = False
664 while not done:
665 try:
666 import bz2
667 xml = self.getFrameXML(frame)
668 arg = xmlrpclib.Binary(bz2.compress(xml))
669 if _VERBOSE:
670 print '============== calling gui side interaction============'
671 self._guiServer.interaction(xmlrpclib.Binary(message), arg, info)
672 if _VERBOSE:
673 print 'after interaction'
674 done = True
675 except:
676 tp, val, tb = sys.exc_info()
677 if True or _VERBOSE:
678 print 'Error contacting GUI server!: '
679 try:
680 traceback.print_exception(tp, val, tb)
681 except:
682 print "Exception printing traceback",
683 tp, val, tb = sys.exc_info()
684 traceback.print_exception(tp, val, tb)
685 done = False
686 # Block while waiting to be called back from the GUI. Eventually, self._wait will
687 # be set false by a function on this side. Seems pretty lame--I'm surprised it works.
688 self.waitForRPC()
689
690
691 def waitForRPC(self):
692 self._wait = True
693 while self._wait :
694 try:
695 if _VERBOSE:
696 print "+++ in harness wait for rpc, before handle_request"
697 self._server.handle_request()
698 if _VERBOSE:
699 print "+++ in harness wait for rpc, after handle_request"
700 except:
701 if _VERBOSE:
702 tp, val, tb = sys.exc_info()
703 print "Got waitForRpc exception : ", repr(tp), ": ", val
704 #time.sleep(0.1)
705
706 def set_step(self):
707 self._adb.set_step()
708 self._wait = False
709 return ""
710
711 def set_continue(self):
712 self._adb.set_continue()
713 self._wait = False
714 return ""
715
716 def set_next(self):
717 self._adb.set_next(self._currentFrame)
718 self._wait = False
719 return ""
720
721 def set_return(self):
722 self._adb.set_return(self._currentFrame)
723 self._wait = False
724 return ""
725
726 if __name__ == '__main__':
727 try:
728 harness = DebuggerHarness()
729 harness.run()
730 harness.do_exit(kill=True)
731 except SystemExit:
732 print "Exiting..."
733 except:
734 tp, val, tb = sys.exc_info()
735 traceback.print_exception(tp, val, tb)