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