How can I build python call tracking capability?
Suppose I have python code for example. some class defined somewhere that cannot be changed
class MyClass(object):
def __init__(self, arg1, arg2):
do_something...
def foo(self):
do_something
Now I want to add a trace function for example. some mechanism externally that keeps track of each method is called for the above class. I want to be able to print out when, for example, __init__
was called, or foo
or even a method __del__
MyClass
.
Can this be done, and what is the best way to do it?
source to share
You can create a trace decorator and attach it to all methods for defining an instance of a class or class, as shown in decorate_methods
.
import functools
import inspect
import types
class TestClass(object):
def func1(self):
pass
def func2(self, a, b):
pass
def trace(func):
@functools.wraps(func)
def decorator(*args, **kwargs):
print "TRACE:", func.__name__, args, kwargs
return func(*args, **kwargs)
return decorator
def decorate_methods(obj, decorator):
for name, func in inspect.getmembers(obj):
if isinstance(func, types.MethodType):
setattr(obj, name, decorator(func))
# Apply the decorator to a class instance
test1 = TestClass()
decorate_methods(test1, trace)
test1.func1()
test1.func2('bar1', b='bar2')
# Apply the decorator to the class definition
decorate_methods(TestClass, trace)
test2 = TestClass()
test2.func1()
test2.func2('bar1', b='bar2')
The script output will be:
TRACE: func1 () {}
TRACE: func2 ('bar1',) {'b': 'bar2'}
TRACE: func1 (<__main__.TestClass object at 0x7f5a8d888150>,) {}
TRACE: func2 (<__main__.TestClass object at 0x7f5a8d888150>, 'bar1') {'b': 'bar2'}
source to share
Use a decorator like below:
def call_trace(orig_func):
def decorated_func(*args, **kwargs):
print "========>In function: " + orig_func.__name__ + "<========"
orig_func(*args, **kwargs)
return decorated_func
Use this decorator to trace the function. It prints the name of the function before entering the function.
Example:
@call_trace
def foo(self):
do_something
Hope it helps.
[Update]: you can use the metaclass, only you have to change to add the "metaclass" parameter to your class as shown below. As you can see, the code below applies the "call_trace" decorator to every function in the "ExBase" class.
I tried this yesterday, it worked fine. I am also new to python. :)
def call_trace(orig_func):
def inner_func(*args, **kwargs):
print ("function name:" + str(orig_func.__name__))
orig_func(*args, **kwargs)
return inner_func
class ExMeta(type):
def __new__(cls, name, bases, attrs):
for attr in attrs:
if hasattr(attrs[attr], '__call__'):
attrs[attr] = call_trace(attrs[attr])
return type.__new__(cls, name, bases, attrs)
class ExBase(metaclass=ExMeta):
x = "x"
y = "y"
def __init__(self):
self.__name = "name"
def getname(self):
return self.__name
b = ExBase()
b.getname()
source to share
Get the code for OnlinePythonTutor from github.com/pgbovine/OnlinePythonTutor/tree/master/v3.
You don't have to worry about all the JS stuff. Extract the files to some directory. You can run your scripts with python / path / to / my / OnlinePythonTutor-master / v3 / generate_json_trace my_script.py
This will basically give you everything your program does step by step. It will probably be overkill, so if you want to look at the source code and the original source at bdb http://docs.python.org/2/library/bdb.html . The docs for bdb are terrible so I have a hard time figuring out what exactly is going on, but I think this is a pretty cool problem, good luck.
source to share