traceing object usage: how to trace attribute access
Volker Apelt
gq437x at yahoo.de
Wed Mar 5 09:11:54 EST 2003
I am looking for ways to trace all kind of access to objects
of some class with least impact on the traced class and
no impact on the caller.
I have already found some code written by Greg Chapman
(glchapman at earthlink.net) on google, which traces
object method calls using __getattribute__. (see below)
With a small extension it traces all kinds
of object attribute access, too.
But it can not tell whether it is read or write
access to object attributes.
And it traces all access, even from inside the same
object.
How can I find out, if this call of __getattribute__
is a read or a write (assign) to some attribute?
other = C()
print other.x # read access
other.x = 1 # write access
How can I find out, if this call of __getattribute__
is from with in the same instance of this object,
like in self.x ?
self.x # internal access
other.x # external access
Thank you,
Volker
#
# code of Greg Chapman with modifications
#
import sys, types
class Traced(object):
traceStream = sys.stdout
callNo = long(1)
def __trace_call__(self, fp, fmt, *args):
if fp is None:
fp = Traced.traceStream
fp.write((fmt+'\n') % args)
def __getattribute__(self, name):
res = super(Traced, self).__getattribute__(name)
if name == '__trace_call__' or name == '__class__':
return res
if isinstance(res, types.MethodType):
if self.__class__.traceStream:
fullname = self.__class__.__name__ + "." + name
res = TracingWrapper(fullname, res, self)
else:
fullname = self.__class__.__name__ + "." + name
self.__trace_call__(None, "ACCESS: %s %s",fullname, res )
return res
class TracingWrapper(object):
def __init__(self, name, func, inst):
self.__name__ = name
self.func = func
self.inst = inst
def __call__(self, *args, **kw):
callNo = Traced.callNo
Traced.callNo += 1
out = None
self.inst.__trace_call__(out,
"CALL: %05d inst=%s, %s( args=%s, kw=%s)",
callNo,self.inst, self.__name__, args, kw)
try:
rv = self.func(*args, **kw)
except:
t, v, tb = sys.exc_info()
self.inst.__trace_call__(out,
"EXCEPTION: %05d %s, exception= %s: %s",
callNo,self.__name__, t, v)
raise t, v, tb
else:
self.inst.__trace_call__(out,
"RETURN: %05d %s value=%s",
callNo,self.__name__, rv)
return rv
if __name__ == '__main__':
#### TEST CASE
class C(Traced):#{
def __init__(self, x=0): self.x = x
def m1(self, x): self.x = x
def m2(self, y):
self.x += 1
return self.x + y
def raise_if2(self,x):
if x == 2:
raise ValueError('forced execption x == 2')
return self.x
#}
##
c = C()
c.m1(2)
c.x = 2
c.raise_if2(1)
try:
c.raise_if2(2)
except Exception,e:
print '**** EXCEPTION',e
pass
print c.x
c.raise_if2(3)
--
Volker Apelt
More information about the Python-list
mailing list