444 lines · python
1import sys2import inspect3from collections import OrderedDict4 5 6class TracebackFancy:7 def __init__(self, traceback):8 self.t = traceback9 10 def getFrame(self):11 return FrameFancy(self.t.tb_frame)12 13 def getLineNumber(self):14 return self.t.tb_lineno if self.t is not None else None15 16 def getNext(self):17 return TracebackFancy(self.t.tb_next)18 19 def __str__(self):20 if self.t is None:21 return ""22 str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber())23 return str_self + "\n" + self.getNext().__str__()24 25 26class ExceptionFancy:27 def __init__(self, frame):28 self.etraceback = frame.f_exc_traceback29 self.etype = frame.exc_type30 self.evalue = frame.f_exc_value31 32 def __init__(self, tb, ty, va):33 self.etraceback = tb34 self.etype = ty35 self.evalue = va36 37 def getTraceback(self):38 return TracebackFancy(self.etraceback)39 40 def __nonzero__(self):41 return (42 self.etraceback is not None43 or self.etype is not None44 or self.evalue is not None45 )46 47 def getType(self):48 return str(self.etype)49 50 def getValue(self):51 return self.evalue52 53 54class CodeFancy:55 def __init__(self, code):56 self.c = code57 58 def getArgCount(self):59 return self.c.co_argcount if self.c is not None else 060 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 def __init__(self, frame, arginfo):76 self.f = frame77 self.a = arginfo78 79 def __str__(self):80 args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()81 ret = ""82 count = 083 size = len(args)84 for arg in args:85 ret = ret + ("%s = %s" % (arg, args[arg]))86 count = count + 187 if count < size:88 ret = ret + ", "89 if varargs:90 if size > 0:91 ret = ret + " "92 ret = ret + "varargs are " + str(varargs)93 if kwargs:94 if size > 0:95 ret = ret + " "96 ret = ret + "kwargs are " + str(kwargs)97 return ret98 99 def getNumArgs(wantVarargs=False, wantKWArgs=False):100 args, varargs, keywords, values = self.a101 size = len(args)102 if varargs and wantVarargs:103 size = size + len(self.getVarArgs())104 if keywords and wantKWArgs:105 size = size + len(self.getKWArgs())106 return size107 108 def getArgs(self):109 args, _, _, values = self.a110 argWValues = OrderedDict()111 for arg in args:112 argWValues[arg] = values[arg]113 return argWValues114 115 def getVarArgs(self):116 _, vargs, _, _ = self.a117 if vargs:118 return self.f.f_locals[vargs]119 return ()120 121 def getKWArgs(self):122 _, _, kwargs, _ = self.a123 if kwargs:124 return self.f.f_locals[kwargs]125 return {}126 127 128class FrameFancy:129 def __init__(self, frame):130 self.f = frame131 132 def getCaller(self):133 return FrameFancy(self.f.f_back)134 135 def getLineNumber(self):136 return self.f.f_lineno if self.f is not None else 0137 138 def getCodeInformation(self):139 return CodeFancy(self.f.f_code) if self.f is not None else None140 141 def getExceptionInfo(self):142 return ExceptionFancy(self.f) if self.f is not None else None143 144 def getName(self):145 return self.getCodeInformation().getName() if self.f is not None else ""146 147 def getFileName(self):148 return self.getCodeInformation().getFileName() if self.f is not None else ""149 150 def getLocals(self):151 return self.f.f_locals if self.f is not None else {}152 153 def getArgumentInfo(self):154 return (155 ArgsFancy(self.f, inspect.getargvalues(self.f))156 if self.f is not None157 else None158 )159 160 161class TracerClass:162 def callEvent(self, frame):163 pass164 165 def lineEvent(self, frame):166 pass167 168 def returnEvent(self, frame, retval):169 pass170 171 def exceptionEvent(self, frame, exception, value, traceback):172 pass173 174 def cCallEvent(self, frame, cfunct):175 pass176 177 def cReturnEvent(self, frame, cfunct):178 pass179 180 def cExceptionEvent(self, frame, cfunct):181 pass182 183 184tracer_impl = TracerClass()185 186 187def the_tracer_entrypoint(frame, event, args):188 if tracer_impl is None:189 return None190 if event == "call":191 call_retval = tracer_impl.callEvent(FrameFancy(frame))192 if not call_retval:193 return None194 return the_tracer_entrypoint195 elif event == "line":196 line_retval = tracer_impl.lineEvent(FrameFancy(frame))197 if not line_retval:198 return None199 return the_tracer_entrypoint200 elif event == "return":201 tracer_impl.returnEvent(FrameFancy(frame), args)202 elif event == "exception":203 exty, exva, extb = args204 exception_retval = tracer_impl.exceptionEvent(205 FrameFancy(frame), ExceptionFancy(extb, exty, exva)206 )207 if not exception_retval:208 return None209 return the_tracer_entrypoint210 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 None217 218 219def enable(t=None):220 global tracer_impl221 if t:222 tracer_impl = t223 sys.settrace(the_tracer_entrypoint)224 225 226def disable():227 sys.settrace(None)228 229 230class LoggingTracer:231 def callEvent(self, frame):232 print(233 "call "234 + frame.getName()235 + " from "236 + frame.getCaller().getName()237 + " @ "238 + str(frame.getCaller().getLineNumber())239 + " args are "240 + str(frame.getArgumentInfo())241 )242 243 def lineEvent(self, frame):244 print(245 "running "246 + frame.getName()247 + " @ "248 + str(frame.getLineNumber())249 + " locals are "250 + str(frame.getLocals())251 + " in "252 + frame.getFileName()253 )254 255 def returnEvent(self, frame, retval):256 print(257 "return from "258 + frame.getName()259 + " value is "260 + str(retval)261 + " locals are "262 + str(frame.getLocals())263 )264 265 def exceptionEvent(self, frame, exception):266 print(267 "exception %s %s raised from %s @ %s"268 % (269 exception.getType(),270 str(exception.getValue()),271 frame.getName(),272 frame.getLineNumber(),273 )274 )275 print("tb: " + str(exception.getTraceback()))276 277 278# the same functionality as LoggingTracer, but with a little more279# lldb-specific smarts280 281 282class LLDBAwareTracer:283 def callEvent(self, frame):284 if frame.getName() == "<module>":285 return286 if frame.getName() == "run_one_line":287 print(288 "call run_one_line(%s)"289 % (frame.getArgumentInfo().getArgs()["input_string"])290 )291 return292 if "Python.framework" in frame.getFileName():293 print("call into Python at " + frame.getName())294 return295 if (296 frame.getName() == "__init__"297 and frame.getCaller().getName() == "run_one_line"298 and frame.getCaller().getLineNumber() == 101299 ):300 return False301 strout = "call " + frame.getName()302 if frame.getCaller().getFileName() == "":303 strout += " from LLDB - args are "304 args = frame.getArgumentInfo().getArgs()305 for arg in args:306 if arg == "dict" or arg == "internal_dict":307 continue308 strout = strout + ("%s = %s " % (arg, args[arg]))309 else:310 strout += (311 " from "312 + frame.getCaller().getName()313 + " @ "314 + str(frame.getCaller().getLineNumber())315 + " args are "316 + str(frame.getArgumentInfo())317 )318 print(strout)319 320 def lineEvent(self, frame):321 if frame.getName() == "<module>":322 return323 if frame.getName() == "run_one_line":324 print(325 "running run_one_line(%s) @ %s"326 % (327 frame.getArgumentInfo().getArgs()["input_string"],328 frame.getLineNumber(),329 )330 )331 return332 if "Python.framework" in frame.getFileName():333 print(334 "running into Python at "335 + frame.getName()336 + " @ "337 + str(frame.getLineNumber())338 )339 return340 strout = (341 "running "342 + frame.getName()343 + " @ "344 + str(frame.getLineNumber())345 + " locals are "346 )347 if frame.getCaller().getFileName() == "":348 locals = frame.getLocals()349 for local in locals:350 if local == "dict" or local == "internal_dict":351 continue352 strout = strout + ("%s = %s " % (local, locals[local]))353 else:354 strout = strout + str(frame.getLocals())355 strout = strout + " in " + frame.getFileName()356 print(strout)357 358 def returnEvent(self, frame, retval):359 if frame.getName() == "<module>":360 return361 if frame.getName() == "run_one_line":362 print(363 "return from run_one_line(%s) return value is %s"364 % (frame.getArgumentInfo().getArgs()["input_string"], retval)365 )366 return367 if "Python.framework" in frame.getFileName():368 print(369 "return from Python at "370 + frame.getName()371 + " return value is "372 + str(retval)373 )374 return375 strout = (376 "return from "377 + frame.getName()378 + " return value is "379 + str(retval)380 + " locals are "381 )382 if frame.getCaller().getFileName() == "":383 locals = frame.getLocals()384 for local in locals:385 if local == "dict" or local == "internal_dict":386 continue387 strout = strout + ("%s = %s " % (local, locals[local]))388 else:389 strout = strout + str(frame.getLocals())390 strout = strout + " in " + frame.getFileName()391 print(strout)392 393 def exceptionEvent(self, frame, exception):394 if frame.getName() == "<module>":395 return396 print(397 "exception %s %s raised from %s @ %s"398 % (399 exception.getType(),400 str(exception.getValue()),401 frame.getName(),402 frame.getLineNumber(),403 )404 )405 print("tb: " + str(exception.getTraceback()))406 407 408def f(x, y=None):409 if x > 0:410 return 2 + f(x - 2)411 return 35412 413 414def g(x):415 return 1.134 / x416 417 418def print_keyword_args(**kwargs):419 # kwargs is a dict of the keyword args passed to the function420 for key, value in kwargs.items():421 print("%s = %s" % (key, value))422 423 424def total(initial=5, *numbers, **keywords):425 count = initial426 for number in numbers:427 count += number428 for key in keywords:429 count += keywords[key]430 return count431 432 433if __name__ == "__main__":434 enable(LoggingTracer())435 f(5)436 f(5, 1)437 print_keyword_args(first_name="John", last_name="Doe")438 total(10, 1, 2, 3, vegetables=50, fruits=100)439 try:440 g(0)441 except:442 pass443 disable()444