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