Access self from decorator - python

In setUp() method of unittest I've setup some self variables, which are later referenced in actual tests. I've also created a decorator to do some logging. Is there a way in which I can access those self variables from decorator?
For the sake of simplicity, I'm posting this code:
def decorator(func):
def _decorator(*args, **kwargs):
# access a from TestSample
func(*args, **kwargs)
return _decorator
class TestSample(unittest.TestCase):
def setUp(self):
self.a = 10
def tearDown(self):
# tear down code
#decorator
def test_a(self):
# testing code goes here
What would be the best way of accessing a (set in setUp()) from decorator?

Since you're decorating a method, and self is a method argument, your decorator has access to self at runtime. Obviously not at parsetime, because there are no objects yet, just a class.
So you change your decorator to:
def decorator(func):
def _decorator(self, *args, **kwargs):
# access a from TestSample
print 'self is %s' % self
return func(self, *args, **kwargs)
return _decorator

Related

Class method as decorator in python

So, im writing a library for appium tests.
I have a main class that look like this:
class APP():
def __init__(self):
self.variable1 = 1
self.current_view = "main_screen"
def do_operation_A(self):
self.open_side_menu()
do_something
self.current_view = "side_menu"
def do_operation_B(self):
self.open_side_menu()
do_something_else
self.current_view = "side_menu"
def set_landscape(self):
self.open_settings_menu()
configure_landscape
self.current_view = "settings_menu"
The class has a lot of operations so i can do things like app.do_operation_A() or app.set_landscape() without having to first go to each menu manually (resolved inside the class)
To reduce this i want to implement a decorator to do something like this if possible:
class APP():
def __init__(self):
self.variable1 = 1
self.current_view = "main_screen"
#DEFINE_DECORATOR_HERE
#side_menu
def do_operation_A(self):
do_something
#side_menu
def do_operation_B(self):
do_something_else
#settings_menu
def set_landscape(self):
configure_landscape
So i want to implement this decorators to navigate to the corresponding view and also change that variable that i use to check some things in other functions. I have seen some examples with functools.wraps but is not clear to me of how to implement the decorator inside the class to be able to modify this self variables.
Any help?
Using a decorator means that you "wrap" your other function, i.e. you call the decorator and then call the function from inside the decorator.
E.g.:
import functools
def outer(func):
#functools.wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
Upon defining the function, the decorator will be called, returning the inner function.
Whenever you call func, you will in reality call inner, which runs it's own code, including calling the original func function.
So for your use case, you should be able to create decorators similar to:
def settings_menu(func):
#functools.wraps(func)
def inner(self, *args, **kwargs):
self.open_settings_menu()
self.current_view = "settings_menu"
return func(self, *args, **kwargs)
return inner
So a decorator is basically a function that returns another function, right?
def side_menu(func):
def wrapper():
return func()
return wrapper
The wrapper, returned by side_menu, will be called whenever App().do_operationA is called. And whenever that method is called, self is always the first argument. Or rather, the first argument is the instance of App, but whatever. So we could do:
def side_menu(func):
def wrapper(self, *args, **kwargs):
self.open_menu()
func(self, *args, **kwargs)
return wrapper
Now, you don't want the method to present itself as wrapper - you like the name do_operationA. That's where #functools.wraps comes in, it makes things look and work right when decorating.
def side_menu(func):
#functools.wraps
def wrapper(self, *args, **kwargs):
self.open_menu()
func(self, *args, **kwargs)
return wrapper

A function decorates a class

I happened to read the following code yesterday (I cannot guarantee this is a valid code):
def singleton(cls, *args, **kw):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
#singleton
class MyClass:
...
Looks like a function singleton is designed to decorate a class MyClass. I understand the simple and standard decorator which, as a function, decorates a function. Like this:
def bold(func):
def wrapper():
return '<b>'+func()+'</b>'
return wrapper
#bold
def test():
return 'This is a test'
But I can't really get how the function-decorates-class thing works. Can anyone provide a more detailed example?

Using decorator from base class both in base class and derived class

I have some python objects with some methods in which i would like to do some check at the beggining, depending of this check, the method's code would run, or an execption would be raised. Instead of replicating the "check" code at the beginning of every method I though of doing a decorator, I also want the decorator to be embedded inside the class itself, since it is closely related to it. So basically:
instead of this
class A(object):
def a_method(self):
if self.check_var is True:
(some_code)
else:
raise Exception
I would like to have this
class A(object):
def decorator(function):
def function_wrapper(self, *args, **kwargs):
if self.check_var is True:
return function(self, *args, **kwargs)
else:
raise Exception
return function_wrapper
#decorator
def a_method(self):
(some_code)
My first question is, am I going about this right? or is there a better way. I have many methods of the A class that need to have this check, so that is why I don't want to replicate the code unnecessarily.
My second question is, if I go about this the way I described, I run into a problem when I want to derive a class from class A and performe the same decorator checks. Again I don't want to replicate the code, so I want to reuse the decorator in the base class A to performe checks in the derived class. I read about turning the decorator into a #classmethod however when I do this I am able to use the decorator in the derived class but not in the base class anymore!
So basically I would like something like this:
class A(object):
#classmethod #maybe
def decorator(function):
def function_wrapper(self, *args, **kwargs):
if self.check_var is True:
return function(self, *args, **kwargs)
else:
raise Exception
return function_wrapper
#decorator
def a_method(self):
(some_code)
class B(A):
#decorator
def b_method(self):
(some_code)
Does anybody know of any clean way to do this?
Since you would prefer to put the decorator inside the class (rather than outside both of them as I suggested in a comment), below shows a way to do it. It makes the decorator a staticmethod instead of a classmethod, and requires using it in a slightly unusual manner, but only within the class.
For more information regarding the necessity of using the decorator like this, see my question Calling class staticmethod within the class body?
class A(object):
#staticmethod
def decorator(function):
def function_wrapper(*args, **kwargs):
print('in function_wrapper')
return function(*args, **kwargs)
return function_wrapper
#decorator.__func__ #### Note unusual decorator usage inside defining class
def a_method(self):
print('in a_method')
class B(A):
#A.decorator #### Normal decorator usage outside defining class
def b_method(self):
print('in b_method')
One way to avoid having to use __func__ and still keep the definition in the first class would be to postpone turning it into a staticmethod until the very end of the class definition:
class A(object):
def decorator(function):
def function_wrapper(*args, **kwargs):
print('in function_wrapper')
return function(*args, **kwargs)
return function_wrapper
#decorator
def a_method(self):
print('in a_method')
decorator = staticmethod(decorator) #### convert for use outside this class
class B(A):
#A.decorator
def b_method(self):
print('in b_method')
Yet another way to avoid the __func__ is something like this:
class A(object):
class Check:
#staticmethod
def decorator(function):
def function_wrapper(*args, **kwargs):
print('in function_wrapper')
return function(*args, **kwargs)
return function_wrapper
#Check.decorator
def a_method(self):
print('in a_method')
class B(A):
Check = A.Check
#Check.decorator
def b_method(self):
print('in b_method')
Which has the additional advantage of making usage of the decorator very uniform.
My first question is, am I going about this right?
As martineau said below, the good practice is put classic decorator outside class.
def get_decorator(function, argument):
def function_wrapper(*args, **kwargs):
if argument is True:
return function(*args, **kwargs)
else:
raise Exception
return function_wrapper
class A(object):
def __init__(self):
self.check_var = True
self.a_method = get_decorator(self.a_method, self.check_var)
def a_method(self):
(whatever)
class B(A):
def __init__(self):
super(B, self).__init__()
self.b_method = get_decorator(self.b_method, self.check_var)
def b_method(self):
(whatever)
Classic decorator is called during class creation time, which is long before an instance is created. Reference

How can I extend a library's decorator?

I would like to extend a library's decorator. I know that I can just call both decorators:
#my_decorator
#lib_decorator
def func():
pass
But I would like to avoid having to pass #lib_decorator to each function each time. I would like my decorator to automatically decorate func() with lib_decorator. How can I do this? Can they be nested?
You can incorporate the lib's decorator within yours. For simple, argument-less decorators, it's rather straight-forward:
def my_decorator():
#lib_decorator # <--- Just include the lib's decorator here
def inner:
func(*args, **kwargs)
return inner
It's a bit trickier for decorators that have arguments. Just remember that your decorator is replacing the decorated function with the inner-most function. So that's the one you need to decorate. So if you call your decorator with args, e.g.
#my_decorator(arg)
def func():
pass
Then decorate the inner function with the lib decorator:
def my_decorator(arg):
def wrapper(func):
#lib_decorator # <--- Just include the lib's decorator here
def inner(*args, **kwargs):
func(*args, **kwargs)
return inner
return wrapper
Or, using the class form of the decorator function:
class my_decorator():
def __init__(self, arg):
pass
def __call__(self, func):
#lib_decorator # <--- Just include the lib's decorator here
def inner(*args, **kwargs):
func(*args, **kwargs)
return inner
You can easily transform a decoration like yours:
#my_decorator
#lib_decorator
def func():
pass
To this simpler decoration, using function composition:
my_composed_decorator = lambda func: my_decorator(lib_decorator(func))
#my_composed_decorator
def func():
pass

Pass parameters to a decorator for a class method is to be decorated

I am trying to define a decorator in flask which will finally be decorating class methods passing parameters of that class instance. Here is an example what I really want to do.
from functools import wraps
def user_permission(myname):
def decorator(f):
#wraps(f)
def decorated(*args,**argws):
if myname == 'My Name':
return f(*args,**argws)
else:
return "Not Permitted"
return decorated
return decorator
And my manager class is defined as:
class Manager(flask.views.MethodView):
def __init__(self,name):
self.name = name
#user_permission(self.my_name)
def post(self):
return "Response"
def get(self):
return "Response"
What I am trying to do is pass the class variables to the decorator. Yes "self" is not defined at that point but "#decorator.user_permission(self.my_name)" is what I am trying actually because I am yet not solved with my problem.
I couldn't find solution from HERE.
Does anybody knows about these stuffs please?
As you say, self is not defined at that point. This could never work, as a decorator is executed when the class is defined, whereas you want something to run when the instance method is called.
However I think you're really overcomplicating this. self is passed to the method itself. So there's no reason to try and make it a parameter to the decorator, since the decorator has access to the method arguments. This would be much simpler:
from functools import wraps
def user_permission():
#wraps(f)
def decorated(self, *args, **kwargs):
if self.myname == 'My Name':
return f(self, *args, **kwargs)
else:
return "Not Permitted"
return decorated
self is just an argument. You don't need a decorator factory.
def user_permission(f):
#wraps(f)
def decorated(self, *args, **kw):
if self.myname == 'My Name':
return f(self, *args, **kw)
else:
return "Not Permitted"
return decorated

Categories