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