The goal is that I wan't to have one decorator that will work with both, function and instance methods, and I would like to retrieve within wrapping function the self
object when decorator has been applied on method or the function object itself when applied to function.
Here's what I have found almost working, this is only the func I'm using to detect on what decorator has been applied:
def _is_method(func):
for stack_frame in inspect.stack():
# if the code_context of the stack frame starts with 'class' this
# function is defined within a class and so a method.
if inspect.getframeinfo(stack_frame[0]).code_context[0].strip().startswith('class'):
return True
return False
This does work for me, with one small exception, It throws exceptions when I run tests in parallel in multiple processes.
Thanks to this SO answer: Using the same decorator (with arguments) with functions and methods
I came to this solution witch works for me flawlessly:
def proofOfConcept():
def wrapper(func):
class MethodDecoratorAdapter(object):
def __init__(self, func):
self.func = func
self.is_method = False
def __get__(self, instance, owner):
if not self.is_method:
self.is_method = True
self.instance = instance
return self
def __call__(self, *args, **kwargs):
# Decorator real logic goes here
if self.is_method:
return self.func(self.instance, *args, **kwargs)
else:
return self.func(*args, **kwargs)
return wraps(func)(MethodDecoratorAdapter(func))
return wrapper
NOTE This is not thread safe, to have a thread safe method one must return a callable object from __get__
that will have scope tied to instance
You can use inspect.getargspec
:
import inspect
def _is_method(func):
spec = inspect.getargspec(func)
return spec.args and spec.args[0] == 'self'
Example usage:
>>> def dummy_deco(f):
... print('{} is method? {}'.format(f.__name__, _is_method(f)))
... return f
...
>>> @dummy_deco
... def add(a, b):
... return a + b
...
add is method? False
>>> class A:
... @dummy_deco
... def meth(self, a, b):
... return a + b
...
meth is method? True
NOTE This code depend on the name of the first argument. If the name is not self
it will treat it as non-instance-method even though it is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With