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