Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Finding defining class in a decorator

Reply
Thread Tools

Finding defining class in a decorator

 
 
lcaamano
Guest
Posts: n/a
 
      05-09-2006
We have a tracing decorator that automatically logs enter/exits to/from
functions and methods and it also figures out by itself the function
call arguments values and the class or module the function/method is
defined on. Finding the name of the class where the method we just
entered was defined in is a bit tricky.

Here's a snippet of the test code:

class Base:
@tracelevel(1)
def foomethod(self, x, y=5, **kwds):
return x+y

class TClass(Base):
@tracelevel(1)
def foomethod(self, x, y=1, **kwds):
return Base.foomethod(self, x, **kwds) + x + y

t = TClass()
t.foomethod(4, d=1)
return

The output format is irrelevant at this point but it should be
something like:

TClass:foomethod ...
Base:foomethod ...

correctly showing the name of the class where the entered method was
defined on.

We are also using the proposed decorator function in the future
functools module, which looks like this:

def _update_wrapper(decorated, func, deco_func):
# Support naive introspection
decorated.__module__ = func.__module__
decorated.__name__ = func.__name__
decorated.__doc__ = func.__doc__
decorated.__dict__.update(func.__dict__)
decorated.__decorator__ = deco_func
decorated.__decorates__ = func

def decorator(deco_func):
"""Wrap a function as an introspection friendly decorator
function"""
def wrapper(func):
decorated = deco_func(func)
if decorated is func:
return func
_update_wrapper(decorated, func, deco_func)
return decorated
# Manually make this decorator introspection friendly
_update_wrapper(wrapper, deco_func, functools_decorator)
return wrapper

In our decorator, the part that figures out the name of the class where
the wrapped method was defined in has to start with the assumption that
the first argument is self and then find the defining class from it.
This code fragment is in the wrapper function of the decorator:

if numargs > 0:
# at definition time, class methods are not methods
# yet because the class doesn't exist when the
# decorators get called and thus, we have to figure
# out classname at runtime via self
#
# assume first arg is self, see if f.__name__ is there
# as a method and if so, then grab it's class name
#
self = args[0]
if type(self) == types.InstanceType:
# getattr will find the method anywhere in the
# class tree so start from the top
bases = list(inspect.getmro(self.__class__))
bases.reverse()
for c in bases:
# f was given to us in the deco_func
meth = getattr(c, f.__name__, None)

# we found a method with that name, which
# it's probably this same wrapper function
# we used to wrap the original method with.

ofunc = getattr(meth, '__decorates__', False)

if ofunc and ofunc.func_code == f.func_code:
# got it
clsname = meth.im_class.__name__
break

Is there a way to do this without the __decorates__ attribute?

--
Luis P Caamano
Atlanta, GA, USA

 
Reply With Quote
 
 
 
 
Ziga Seilnacht
Guest
Posts: n/a
 
      05-09-2006
lcaamano wrote:
> We have a tracing decorator that automatically logs enter/exits to/from
> functions and methods and it also figures out by itself the function
> call arguments values and the class or module the function/method is
> defined on. Finding the name of the class where the method we just
> entered was defined in is a bit tricky.


[snipped]

You might find this helpful:

import sys

def tracer(func):
"""
A decorator that prints the name of the class from which it was
called.

The name is determined at class creation time. This works
only in CPython, since it relies on the sys._getframe()
function. The assumption is that it can only be called
from a class statement. The name of the class is deduced
from the code object name.
"""
classframe = sys._getframe(1)
print classframe.f_code.co_name
return func


if __name__ == '__main__':

# this should print Test1

class Test1(object):

@tracer
def spam(self):
pass

# this should print Test2

class Test2(Test1):

@tracer
def spam(self):
pass


> --
> Luis P Caamano
> Atlanta, GA, USA


Hope this helps,
Ziga

 
Reply With Quote
 
 
 
 
lcaamano
Guest
Posts: n/a
 
      05-09-2006
Nice. I had to call _getframe(2) to account for the wrapper but the
idea seems to work OK, that is, save the name of the decorator's
original caller at definition time while creating the wrapper function.
Much better than doing that at runtime.

Thanks

--
Luis P Caamano
Atlanta, GA USA

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Finding the name of a function while defining it Abhas Bhattacharya Python 28 12-29-2012 10:18 AM
Why doesnt __getattr__ with decorator dont call __get_method in decorator glomde Python 5 03-29-2007 02:48 PM
How to call a class method when (i.e. in the moment of) inheritingfrom a class/defining a descendant? Thomas Ruby 4 06-07-2005 07:21 AM
What're the benift and the drawback of defining a class embedded inside another class. Xiangliang Meng C++ 5 04-12-2005 09:07 AM
defining or not defining destructors johny smith C++ 8 07-02-2004 08:51 AM



Advertisments