from __future__ import print_function import sys import inspect from collections import OrderedDict class TracebackFancy: def __init__(self, traceback): self.t = traceback def getFrame(self): return FrameFancy(self.t.tb_frame) def getLineNumber(self): return self.t.tb_lineno if self.t is not None else None def getNext(self): return TracebackFancy(self.t.tb_next) def __str__(self): if self.t is None: return "" str_self = "%s @ %s" % ( self.getFrame().getName(), self.getLineNumber()) return str_self + "\n" + self.getNext().__str__() class ExceptionFancy: def __init__(self, frame): self.etraceback = frame.f_exc_traceback self.etype = frame.exc_type self.evalue = frame.f_exc_value def __init__(self, tb, ty, va): self.etraceback = tb self.etype = ty self.evalue = va def getTraceback(self): return TracebackFancy(self.etraceback) def __nonzero__(self): return self.etraceback is not None or self.etype is not None or self.evalue is not None def getType(self): return str(self.etype) def getValue(self): return self.evalue class CodeFancy: def __init__(self, code): self.c = code def getArgCount(self): return self.c.co_argcount if self.c is not None else 0 def getFilename(self): return self.c.co_filename if self.c is not None else "" def getVariables(self): return self.c.co_varnames if self.c is not None else [] def getName(self): return self.c.co_name if self.c is not None else "" def getFileName(self): return self.c.co_filename if self.c is not None else "" class ArgsFancy: def __init__(self, frame, arginfo): self.f = frame self.a = arginfo def __str__(self): args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs() ret = "" count = 0 size = len(args) for arg in args: ret = ret + ("%s = %s" % (arg, args[arg])) count = count + 1 if count < size: ret = ret + ", " if varargs: if size > 0: ret = ret + " " ret = ret + "varargs are " + str(varargs) if kwargs: if size > 0: ret = ret + " " ret = ret + "kwargs are " + str(kwargs) return ret def getNumArgs(wantVarargs=False, wantKWArgs=False): args, varargs, keywords, values = self.a size = len(args) if varargs and wantVarargs: size = size + len(self.getVarArgs()) if keywords and wantKWArgs: size = size + len(self.getKWArgs()) return size def getArgs(self): args, _, _, values = self.a argWValues = OrderedDict() for arg in args: argWValues[arg] = values[arg] return argWValues def getVarArgs(self): _, vargs, _, _ = self.a if vargs: return self.f.f_locals[vargs] return () def getKWArgs(self): _, _, kwargs, _ = self.a if kwargs: return self.f.f_locals[kwargs] return {} class FrameFancy: def __init__(self, frame): self.f = frame def getCaller(self): return FrameFancy(self.f.f_back) def getLineNumber(self): return self.f.f_lineno if self.f is not None else 0 def getCodeInformation(self): return CodeFancy(self.f.f_code) if self.f is not None else None def getExceptionInfo(self): return ExceptionFancy(self.f) if self.f is not None else None def getName(self): return self.getCodeInformation().getName() if self.f is not None else "" def getFileName(self): return self.getCodeInformation().getFileName() if self.f is not None else "" def getLocals(self): return self.f.f_locals if self.f is not None else {} def getArgumentInfo(self): return ArgsFancy( self.f, inspect.getargvalues( self.f)) if self.f is not None else None class TracerClass: def callEvent(self, frame): pass def lineEvent(self, frame): pass def returnEvent(self, frame, retval): pass def exceptionEvent(self, frame, exception, value, traceback): pass def cCallEvent(self, frame, cfunct): pass def cReturnEvent(self, frame, cfunct): pass def cExceptionEvent(self, frame, cfunct): pass tracer_impl = TracerClass() def the_tracer_entrypoint(frame, event, args): if tracer_impl is None: return None if event == "call": call_retval = tracer_impl.callEvent(FrameFancy(frame)) if not call_retval: return None return the_tracer_entrypoint elif event == "line": line_retval = tracer_impl.lineEvent(FrameFancy(frame)) if not line_retval: return None return the_tracer_entrypoint elif event == "return": tracer_impl.returnEvent(FrameFancy(frame), args) elif event == "exception": exty, exva, extb = args exception_retval = tracer_impl.exceptionEvent( FrameFancy(frame), ExceptionFancy(extb, exty, exva)) if not exception_retval: return None return the_tracer_entrypoint elif event == "c_call": tracer_impl.cCallEvent(FrameFancy(frame), args) elif event == "c_return": tracer_impl.cReturnEvent(FrameFancy(frame), args) elif event == "c_exception": tracer_impl.cExceptionEvent(FrameFancy(frame), args) return None def enable(t=None): global tracer_impl if t: tracer_impl = t sys.settrace(the_tracer_entrypoint) def disable(): sys.settrace(None) class LoggingTracer: def callEvent(self, frame): print("call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())) def lineEvent(self, frame): print("running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName()) def returnEvent(self, frame, retval): print("return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())) def exceptionEvent(self, frame, exception): print("exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())) print("tb: " + str(exception.getTraceback())) # the same functionality as LoggingTracer, but with a little more # lldb-specific smarts class LLDBAwareTracer: def callEvent(self, frame): if frame.getName() == "": return if frame.getName() == "run_one_line": print("call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])) return if "Python.framework" in frame.getFileName(): print("call into Python at " + frame.getName()) return if frame.getName() == "__init__" and frame.getCaller().getName( ) == "run_one_line" and frame.getCaller().getLineNumber() == 101: return False strout = "call " + frame.getName() if (frame.getCaller().getFileName() == ""): strout += " from LLDB - args are " args = frame.getArgumentInfo().getArgs() for arg in args: if arg == "dict" or arg == "internal_dict": continue strout = strout + ("%s = %s " % (arg, args[arg])) else: strout += " from " + frame.getCaller().getName() + " @ " + \ str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()) print(strout) def lineEvent(self, frame): if frame.getName() == "": return if frame.getName() == "run_one_line": print("running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"], frame.getLineNumber())) return if "Python.framework" in frame.getFileName(): print("running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber())) return strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + \ " locals are " if (frame.getCaller().getFileName() == ""): locals = frame.getLocals() for local in locals: if local == "dict" or local == "internal_dict": continue strout = strout + ("%s = %s " % (local, locals[local])) else: strout = strout + str(frame.getLocals()) strout = strout + " in " + frame.getFileName() print(strout) def returnEvent(self, frame, retval): if frame.getName() == "": return if frame.getName() == "run_one_line": print("return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"], retval)) return if "Python.framework" in frame.getFileName(): print("return from Python at " + frame.getName() + " return value is " + str(retval)) return strout = "return from " + frame.getName() + " return value is " + \ str(retval) + " locals are " if (frame.getCaller().getFileName() == ""): locals = frame.getLocals() for local in locals: if local == "dict" or local == "internal_dict": continue strout = strout + ("%s = %s " % (local, locals[local])) else: strout = strout + str(frame.getLocals()) strout = strout + " in " + frame.getFileName() print(strout) def exceptionEvent(self, frame, exception): if frame.getName() == "": return print("exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())) print("tb: " + str(exception.getTraceback())) def f(x, y=None): if x > 0: return 2 + f(x - 2) return 35 def g(x): return 1.134 / x def print_keyword_args(**kwargs): # kwargs is a dict of the keyword args passed to the function for key, value in kwargs.items(): print("%s = %s" % (key, value)) def total(initial=5, *numbers, **keywords): count = initial for number in numbers: count += number for key in keywords: count += keywords[key] return count if __name__ == "__main__": enable(LoggingTracer()) f(5) f(5, 1) print_keyword_args(first_name="John", last_name="Doe") total(10, 1, 2, 3, vegetables=50, fruits=100) try: g(0) except: pass disable()