What I want is to create a class decorator to decorate a class and works on subclasses too.
Imagine this class:
JavaScript
x
7
1
class CustomBaseTest(TransactionTestCase):
2
def __init__(self, *args, **kwargs):
3
4
5
def more_custom_helpers(self):
6
7
and the real Test:
JavaScript
1
7
1
class FooTest(CustomBaseTest):
2
def decorate_this_foo_is_ok(self):
3
.
4
5
def decorate_this_fails(self):
6
7
what I want is to use a decorator in CustomBaseTest
that finds all methods that starts with ‘decoratte_this_’ and execute custom code after and before. I already have the decorator, something like this:
JavaScript
1
19
19
1
def class_decorator(klass):
2
is_method_test = lambda m: not m.startswith('_') and m.startswith('decorate_this_') and isinstance(getattr(klass, m), MethodType)
3
test_methods = filter(is_method_test, dir(klass))
4
5
for method_name in test_methods:
6
class_method = getattr(klass, method_name)
7
8
def helper(mname, method):
9
@wraps(method)
10
some logic here
11
retval = method(*a, **kw)
12
more logic here
13
return retval
14
return wrapper
15
16
fn = MethodType(helper(method_name, class_method), None, klass)
17
setattr(klass, method_name, fn)
18
return klass
19
do you know if is possible to do that? and how?
thanks!!!
Advertisement
Answer
Thanks to @Markku and @BrenBarn.
Here is the solution.
First we have a simple decorator:
JavaScript
1
10
10
1
from functools import wraps
2
def my_decorator(func):
3
@wraps(func)
4
def wrapper(*args, **kwargs):
5
# do some stuff
6
retval = func(*args, **kwargs)
7
# do more stuff
8
return retval
9
return wrapper
10
And the metaclass:
JavaScript
1
7
1
class ProfileMetaByClass(type):
2
def __init__(cls, name, bases, dct):
3
for method_name, method in dct.items():
4
if method_name.startswith('decorate_this_'):
5
setattr(cls, method_name, my_decorator(method))
6
type.__init__(cls, name, bases, dct)
7
And that worked for me!