]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/DebuggerHarness.py
1 #----------------------------------------------------------------------------
2 # Name: DebuggerHarness.py
9 # Copyright: (c) 2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
14 import SimpleXMLRPCServer
22 from xml
.dom
.minidom
import getDOMImplementation
26 if sys
.platform
.startswith("win"):
33 _DEBUG_DEBUGGER
= False
37 def __init__(self
, harness
, queue
):
38 bdb
.Bdb
.__init
__(self
)
39 self
._harness
= harness
40 self
._userBreak
= False
42 self
._knownCantExpandFiles
= {}
43 self
._knownExpandedFiles
= {}
45 def getLongName(self
, filename
):
48 if self
._knownCantExpandFiles
.get(filename
):
50 if self
._knownExpandedFiles
.get(filename
):
51 return self
._knownExpandedFiles
.get(filename
)
53 newname
= win32api
.GetLongPathName(filename
)
54 self
._knownExpandedFiles
[filename
] = newname
57 self
._knownCantExpandFiles
[filename
] = filename
60 def canonic(self
, orig_filename
):
61 if orig_filename
== "<" + orig_filename
[1:-1] + ">":
63 filename
= self
.getLongName(orig_filename
)
65 canonic
= self
.fncache
.get(filename
)
67 canonic
= os
.path
.abspath(filename
)
68 canonic
= os
.path
.normcase(canonic
)
69 self
.fncache
[filename
] = canonic
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
79 def do_clear(self
, arg
):
80 bdb
.Breakpoint
.bpbynumber
[int(arg
)].deleteMe()
82 def user_line(self
, frame
):
83 if self
.in_debugger_code(frame
):
86 message
= self
.__frame
2message
(frame
)
87 self
._harness
.interaction(message
, frame
, "")
89 def user_call(self
, frame
, argument_list
):
90 if self
.in_debugger_code(frame
):
93 if self
.stop_here(frame
):
94 message
= self
.__frame
2message
(frame
)
95 self
._harness
.interaction(message
, frame
, "")
97 def user_return(self
, frame
, return_value
):
98 if self
.in_debugger_code(frame
):
101 message
= self
.__frame
2message
(frame
)
102 self
._harness
.interaction(message
, frame
, "")
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
109 exc_type_name
= exc_type
.__name
__
110 message
= "Exception occurred: " + 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
)
114 def in_debugger_code(self
, frame
):
115 if _DEBUG_DEBUGGER
: return False
116 message
= self
.__frame
2message
(frame
)
117 return message
.count('DebuggerHarness') > 0
119 def frame2message(self
, frame
):
120 return self
.__frame
2message
(frame
)
122 def __frame2message(self
, frame
):
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
)
132 def runFile(self
, fileName
):
135 #global_dict['__name__'] = '__main__'
137 fileToRun
= open(fileName
, mode
='r')
138 if _VERBOSE
: print "Running file ", fileName
139 sys
.settrace(self
.trace_dispatch
)
141 exec fileToRun
in __main__
.__dict
__,__main__
.__dict
__
145 tp
, val
, tb
= sys
.exc_info()
146 traceback
.print_exception(tp
, val
, tb
)
152 def trace_dispatch(self
, frame
, event
, arg
):
155 # Check for ui events
158 return self
.dispatch_line(frame
)
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
169 while self
._queue
.qsize():
171 item
= self
._queue
.get_nowait()
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())
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
:
187 if _VERBOSE
: print "Setting break at line ", str(lineNumber
), " in file ", self
.canonic(fileName
)
188 self
.set_break(fileName
, int(lineNumber
))
191 def stop_here(self
, frame
):
192 if( self
._userBreak
):
193 self
._userBreak
= False
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
:
201 while frame
is not None and frame
is not self
.stopframe
:
202 if frame
is self
.botframe
:
207 class BreakNotify(object):
208 def __init__(self
, bps
=None, break_here
=False, kill
=False):
210 self
._break
_here
= break_here
214 return self
._break
_here
219 def getBreakpoints(self
):
222 def hasBreakpoints(self
):
223 return (self
._bps
!= None)
225 class AGXMLRPCServer(SimpleXMLRPCServer
.SimpleXMLRPCServer
):
226 def __init__(self
, address
, logRequests
=0):
227 SimpleXMLRPCServer
.SimpleXMLRPCServer
.__init
__(self
, address
, logRequests
=logRequests
)
229 class BreakListenerThread(threading
.Thread
):
230 def __init__(self
, host
, port
, queue
):
231 threading
.Thread
.__init
__(self
)
233 self
._port
= int(port
)
234 self
._keepGoing
= True
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
)
241 def break_requested(self
):
242 bn
= BreakNotify(break_here
=True)
246 def update_breakpoints(self
, pickled_Binary_bpts
):
247 dict = pickle
.loads(pickled_Binary_bpts
.data
)
248 bn
= BreakNotify(bps
=dict)
253 bn
= BreakNotify(kill
=True)
258 while self
._keepGoing
:
260 self
._server
.handle_request()
263 tp
, val
, tb
= sys
.exc_info()
264 print "Exception in BreakListenerThread.run():", str(tp
), str(val
)
265 self
._keepGoing
= False
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"
275 class DebuggerHarness(object):
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])
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
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)
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
)
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
)
317 self
.message_frame_dict
= {}
318 self
.introspection_list
= []
319 atexit
.register(self
.do_exit
)
322 self
._adb
.runFile(self
._command
)
323 self
.do_exit(kill
=True)
326 def do_exit(self
, kill
=False):
328 self
._breakListener
.AskToStop()
329 self
._server
.server_close()
331 self
._guiServer
.quit()
340 def set_breakpoint(self
, fileName
, lineNo
):
341 self
._adb
.set_break(fileName
, lineNo
)
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
353 def clear_breakpoint(self
, fileName
, lineNo
):
354 self
._adb
.clear_break(fileName
, lineNo
)
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
]
361 item
= eval(text
, frame
.f_globals
, frame
.f_locals
)
362 return self
.get_watch_document(item
, name
)
364 tp
, val
, tb
= sys
.exc_info()
365 return self
.get_exception_document(tp
, val
, tb
)
368 def attempt_introspection(self
, frame_message
, chain
):
370 frame
= self
.message_frame_dict
[frame_message
]
373 if name
== 'globals':
374 item
= frame
.f_globals
375 elif name
== 'locals':
376 item
= frame
.f_locals
379 item
= self
.getNextItem(item
, name
)
380 return self
.get_introspection_document(item
, name
)
382 tp
, val
, tb
= sys
.exc_info()
383 traceback
.print_exception(tp
, val
, tb
)
384 return self
.get_empty_introspection_document()
386 def getNextItem(self
, link
, identifier
):
388 if self
.isTupleized(identifier
):
389 return self
.deTupleize(link
, identifier
)
391 if tp
== types
.DictType
or tp
== types
.DictProxyType
:
392 return link
[identifier
]
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
))
399 def isPrimitive(self
, 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
405 def isTupleized(self
, value
):
406 return value
.count('[')
408 def deTupleize(self
, link
, string1
):
410 start
= string1
.find('[')
411 end
= string1
.find(']')
412 num
= int(string1
[start
+1:end
])
415 tp
,val
,tb
= sys
.exc_info()
416 if _VERBOSE
: print "Got exception in deTupleize: ", val
419 def wrapAndCompress(self
, stringDoc
):
421 return xmlrpclib
.Binary(bz2
.compress(stringDoc
))
423 def get_empty_introspection_document(self
):
424 doc
= getDOMImplementation().createDocument(None, "replacement", None)
425 return self
.wrapAndCompress(doc
.toxml())
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())
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())
439 def get_exception_document(self
, name
, tp
, val
, tb
):
440 stack
= traceback
.format_exception(tp
, val
, tb
)
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
)
451 cantIntro
= [types
.FunctionType
,
461 def addAny(self
, top_element
, name
, item
, doc
, ply
):
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)
477 self
.addNode(top_element
,name
, item
, doc
)
480 def canIntrospect(self
, item
):
482 if tp
in DebuggerHarness
.cantIntro
:
484 elif tp
is types
.TupleType
or tp
is types
.ListType
:
486 elif tp
is types
.DictType
or tp
is types
.DictProxyType
:
488 elif inspect
.ismodule(item
):
490 elif inspect
.isclass(item
) or tp
is types
.InstanceType
:
491 if hasattr(item
, '__dict__'):
493 elif hasattr(item
, '__name__'):
495 elif hasattr(item
, '__module__'):
497 elif hasattr(item
, '__doc__'):
501 elif hasattr(item
, '__dict__'):
502 return len(item
.__dict
__) > 0
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
)
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
)
522 self
.addAny(tupleNode
, name
+'[' + str(count
) + ']',item
, doc
, ply
-1)
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
532 def addDict(self
, root_node
, name
, dict, document
, ply
):
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
)
539 dict_node
= root_node
540 for key
in dict.keys():
544 self
.addAny(dict_node
, strkey
, value
, document
, ply
-1)
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
)
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
)
557 if hasattr(class_item
, '__dict__'):
558 self
.addDict(item_node
, '', class_item
.__dict
__, document
, ply
-1)
560 tp
,val
,tb
=sys
.exc_info()
562 traceback
.print_exception(tp
, val
, tb
)
564 if hasattr(class_item
, '__name__'):
565 self
.addAny(item_node
,'__name__',class_item
.__name
__, document
, ply
-1)
567 tp
,val
,tb
=sys
.exc_info()
569 traceback
.print_exception(tp
, val
, tb
)
571 if hasattr(class_item
, '__module__'):
572 self
.addAny(item_node
, '__module__', class_item
.__module
__, document
, ply
-1)
574 tp
,val
,tb
=sys
.exc_info()
576 traceback
.print_exception(tp
, val
, tb
)
578 if hasattr(class_item
, '__doc__'):
579 self
.addAny(item_node
, '__doc__', class_item
.__doc
__, document
, ply
-1)
581 tp
,val
,tb
=sys
.exc_info()
583 traceback
.print_exception(tp
, val
, tb
)
585 if hasattr(class_item
, '__bases__'):
586 self
.addAny(item_node
, '__bases__', class_item
.__bases
__, document
, ply
-1)
588 tp
,val
,tb
=sys
.exc_info()
590 traceback
.print_exception(tp
, val
, tb
)
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
)
598 if hasattr(module_item
, '__file__'):
599 self
.addAny(item_node
, '__file__', module_item
.__file
__, document
, ply
-1)
603 if hasattr(module_item
, '__doc__'):
604 self
.addAny(item_node
,'__doc__', module_item
.__doc
__, document
, ply
-1)
610 def getFrameXML(self
, base_frame
):
611 doc
= getDOMImplementation().createDocument(None, "stack", None)
612 top_element
= doc
.documentElement
616 while frame
is not None:
617 if((frame
.f_code
.co_filename
.count('DebuggerHarness.py') == 0) or _DEBUG_DEBUGGER
):
621 self
.message_frame_dict
= {}
623 self
.addFrame(f
,top_element
, doc
)
626 def addFrame(self
, frame
, root_element
, document
):
627 frameNode
= document
.createElement('frame')
628 root_element
.appendChild(frameNode
)
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
)
641 def getRepr(self
, varName
, globals, locals):
643 return repr(eval(varName
, globals, locals))
645 return 'Error: Could not recover value.'
648 def saferepr(self
, thing
):
652 tp
, val
, tb
= sys
.exc_info()
653 traceback
.print_exception(tp
, val
, tb
)
656 # The debugger calls this method when it reaches a breakpoint.
657 def interaction(self
, message
, frame
, info
):
659 print 'hit debug side interaction'
660 self
._userBreak
= False
662 self
._currentFrame
= frame
667 xml
= self
.getFrameXML(frame
)
668 arg
= xmlrpclib
.Binary(bz2
.compress(xml
))
670 print '============== calling gui side interaction============'
671 self
._guiServer
.interaction(xmlrpclib
.Binary(message
), arg
, info
)
673 print 'after interaction'
676 tp
, val
, tb
= sys
.exc_info()
678 print 'Error contacting GUI server!: '
680 traceback
.print_exception(tp
, val
, tb
)
682 print "Exception printing traceback",
683 tp
, val
, tb
= sys
.exc_info()
684 traceback
.print_exception(tp
, val
, tb
)
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.
691 def waitForRPC(self
):
696 print "+++ in harness wait for rpc, before handle_request"
697 self
._server
.handle_request()
699 print "+++ in harness wait for rpc, after handle_request"
702 tp
, val
, tb
= sys
.exc_info()
703 print "Got waitForRpc exception : ", repr(tp
), ": ", val
711 def set_continue(self
):
712 self
._adb
.set_continue()
717 self
._adb
.set_next(self
._currentFrame
)
721 def set_return(self
):
722 self
._adb
.set_return(self
._currentFrame
)
726 if __name__
== '__main__':
728 harness
= DebuggerHarness()
730 harness
.do_exit(kill
=True)
734 tp
, val
, tb
= sys
.exc_info()
735 traceback
.print_exception(tp
, val
, tb
)