| 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() == "<module>": | |
| 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() == "<module>": | |
| 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() == "<module>": | |
| 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() == "<module>": | |
| 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() |