1import sys 2import inspect 3from collections import OrderedDict 4 5class TracebackFancy: 6 def __init__(self,traceback): 7 self.t = traceback 8 9 def getFrame(self): 10 return FrameFancy(self.t.tb_frame) 11 12 def getLineNumber(self): 13 return self.t.tb_lineno if self.t != None else None 14 15 def getNext(self): 16 return TracebackFancy(self.t.tb_next) 17 18 def __str__(self): 19 if self.t == None: 20 return "" 21 str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber()) 22 return str_self + "\n" + self.getNext().__str__() 23 24class ExceptionFancy: 25 def __init__(self,frame): 26 self.etraceback = frame.f_exc_traceback 27 self.etype = frame.exc_type 28 self.evalue = frame.f_exc_value 29 30 def __init__(self,tb,ty,va): 31 self.etraceback = tb 32 self.etype = ty 33 self.evalue = va 34 35 def getTraceback(self): 36 return TracebackFancy(self.etraceback) 37 38 def __nonzero__(self): 39 return self.etraceback != None or self.etype != None or self.evalue != None 40 41 def getType(self): 42 return str(self.etype) 43 44 def getValue(self): 45 return self.evalue 46 47class CodeFancy: 48 def __init__(self,code): 49 self.c = code 50 51 def getArgCount(self): 52 return self.c.co_argcount if self.c != None else 0 53 54 def getFilename(self): 55 return self.c.co_filename if self.c != None else "" 56 57 def getVariables(self): 58 return self.c.co_varnames if self.c != None else [] 59 60 def getName(self): 61 return self.c.co_name if self.c != None else "" 62 63 def getFileName(self): 64 return self.c.co_filename if self.c != None else "" 65 66class ArgsFancy: 67 def __init__(self,frame,arginfo): 68 self.f = frame 69 self.a = arginfo 70 71 def __str__(self): 72 args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs() 73 ret = "" 74 count = 0 75 size = len(args) 76 for arg in args: 77 ret = ret + ("%s = %s" % (arg, args[arg])) 78 count = count + 1 79 if count < size: 80 ret = ret + ", " 81 if varargs: 82 if size > 0: 83 ret = ret + " " 84 ret = ret + "varargs are " + str(varargs) 85 if kwargs: 86 if size > 0: 87 ret = ret + " " 88 ret = ret + "kwargs are " + str(kwargs) 89 return ret 90 91 def getNumArgs(wantVarargs = False, wantKWArgs=False): 92 args, varargs, keywords, values = self.a 93 size = len(args) 94 if varargs and wantVarargs: 95 size = size+len(self.getVarArgs()) 96 if keywords and wantKWArgs: 97 size = size+len(self.getKWArgs()) 98 return size 99 100 def getArgs(self): 101 args, _, _, values = self.a 102 argWValues = OrderedDict() 103 for arg in args: 104 argWValues[arg] = values[arg] 105 return argWValues 106 107 def getVarArgs(self): 108 _, vargs, _, _ = self.a 109 if vargs: 110 return self.f.f_locals[vargs] 111 return () 112 113 def getKWArgs(self): 114 _, _, kwargs, _ = self.a 115 if kwargs: 116 return self.f.f_locals[kwargs] 117 return {} 118 119class FrameFancy: 120 def __init__(self,frame): 121 self.f = frame 122 123 def getCaller(self): 124 return FrameFancy(self.f.f_back) 125 126 def getLineNumber(self): 127 return self.f.f_lineno if self.f != None else 0 128 129 def getCodeInformation(self): 130 return CodeFancy(self.f.f_code) if self.f != None else None 131 132 def getExceptionInfo(self): 133 return ExceptionFancy(self.f) if self.f != None else None 134 135 def getName(self): 136 return self.getCodeInformation().getName() if self.f != None else "" 137 138 def getFileName(self): 139 return self.getCodeInformation().getFileName() if self.f != None else "" 140 141 def getLocals(self): 142 return self.f.f_locals if self.f != None else {} 143 144 def getArgumentInfo(self): 145 return ArgsFancy(self.f,inspect.getargvalues(self.f)) if self.f != None else None 146 147class TracerClass: 148 def callEvent(self,frame): 149 pass 150 151 def lineEvent(self,frame): 152 pass 153 154 def returnEvent(self,frame,retval): 155 pass 156 157 def exceptionEvent(self,frame,exception,value,traceback): 158 pass 159 160 def cCallEvent(self,frame,cfunct): 161 pass 162 163 def cReturnEvent(self,frame,cfunct): 164 pass 165 166 def cExceptionEvent(self,frame,cfunct): 167 pass 168 169tracer_impl = TracerClass() 170 171 172def the_tracer_entrypoint(frame,event,args): 173 if tracer_impl == None: 174 return None 175 if event == "call": 176 call_retval = tracer_impl.callEvent(FrameFancy(frame)) 177 if call_retval == False: 178 return None 179 return the_tracer_entrypoint 180 elif event == "line": 181 line_retval = tracer_impl.lineEvent(FrameFancy(frame)) 182 if line_retval == False: 183 return None 184 return the_tracer_entrypoint 185 elif event == "return": 186 tracer_impl.returnEvent(FrameFancy(frame),args) 187 elif event == "exception": 188 exty,exva,extb = args 189 exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva)) 190 if exception_retval == False: 191 return None 192 return the_tracer_entrypoint 193 elif event == "c_call": 194 tracer_impl.cCallEvent(FrameFancy(frame),args) 195 elif event == "c_return": 196 tracer_impl.cReturnEvent(FrameFancy(frame),args) 197 elif event == "c_exception": 198 tracer_impl.cExceptionEvent(FrameFancy(frame),args) 199 return None 200 201def enable(t=None): 202 global tracer_impl 203 if t: 204 tracer_impl = t 205 sys.settrace(the_tracer_entrypoint) 206 207def disable(): 208 sys.settrace(None) 209 210class LoggingTracer: 211 def callEvent(self,frame): 212 print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()) 213 214 def lineEvent(self,frame): 215 print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName() 216 217 def returnEvent(self,frame,retval): 218 print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals()) 219 220 def exceptionEvent(self,frame,exception): 221 print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()) 222 print "tb: " + str(exception.getTraceback()) 223 224# the same functionality as LoggingTracer, but with a little more lldb-specific smarts 225class LLDBAwareTracer: 226 def callEvent(self,frame): 227 if frame.getName() == "<module>": 228 return 229 if frame.getName() == "run_one_line": 230 print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"]) 231 return 232 if "Python.framework" in frame.getFileName(): 233 print "call into Python at " + frame.getName() 234 return 235 if frame.getName() == "__init__" and frame.getCaller().getName() == "run_one_line" and frame.getCaller().getLineNumber() == 101: 236 return False 237 strout = "call " + frame.getName() 238 if (frame.getCaller().getFileName() == ""): 239 strout += " from LLDB - args are " 240 args = frame.getArgumentInfo().getArgs() 241 for arg in args: 242 if arg == "dict" or arg == "internal_dict": 243 continue 244 strout = strout + ("%s = %s " % (arg,args[arg])) 245 else: 246 strout += " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()) 247 print strout 248 249 def lineEvent(self,frame): 250 if frame.getName() == "<module>": 251 return 252 if frame.getName() == "run_one_line": 253 print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"],frame.getLineNumber()) 254 return 255 if "Python.framework" in frame.getFileName(): 256 print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber()) 257 return 258 strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " 259 if (frame.getCaller().getFileName() == ""): 260 locals = frame.getLocals() 261 for local in locals: 262 if local == "dict" or local == "internal_dict": 263 continue 264 strout = strout + ("%s = %s " % (local,locals[local])) 265 else: 266 strout = strout + str(frame.getLocals()) 267 strout = strout + " in " + frame.getFileName() 268 print strout 269 270 def returnEvent(self,frame,retval): 271 if frame.getName() == "<module>": 272 return 273 if frame.getName() == "run_one_line": 274 print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"],retval) 275 return 276 if "Python.framework" in frame.getFileName(): 277 print "return from Python at " + frame.getName() + " return value is " + str(retval) 278 return 279 strout = "return from " + frame.getName() + " return value is " + str(retval) + " locals are " 280 if (frame.getCaller().getFileName() == ""): 281 locals = frame.getLocals() 282 for local in locals: 283 if local == "dict" or local == "internal_dict": 284 continue 285 strout = strout + ("%s = %s " % (local,locals[local])) 286 else: 287 strout = strout + str(frame.getLocals()) 288 strout = strout + " in " + frame.getFileName() 289 print strout 290 291 def exceptionEvent(self,frame,exception): 292 if frame.getName() == "<module>": 293 return 294 print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()) 295 print "tb: " + str(exception.getTraceback()) 296 297def f(x,y=None): 298 if x > 0: 299 return 2 + f(x-2) 300 return 35 301 302def g(x): 303 return 1.134 / x 304 305def print_keyword_args(**kwargs): 306 # kwargs is a dict of the keyword args passed to the function 307 for key, value in kwargs.iteritems(): 308 print "%s = %s" % (key, value) 309 310def total(initial=5, *numbers, **keywords): 311 count = initial 312 for number in numbers: 313 count += number 314 for key in keywords: 315 count += keywords[key] 316 return count 317 318if __name__ == "__main__": 319 enable(LoggingTracer()) 320 f(5) 321 f(5,1) 322 print_keyword_args(first_name="John", last_name="Doe") 323 total(10, 1, 2, 3, vegetables=50, fruits=100) 324 try: 325 g(0) 326 except: 327 pass 328 disable() 329