Why does a decorated class looses its docstrings? - python

I'm currently implementing an API on which I need to decorate the class Wrapper, but I want it to keep its docstring to make it available to the API user. Take a look at the following minimal working example :
class ClassDecorator:
"""ClassDecorator docstring
"""
def __init__(self, enableCache=True):
self.enableCache = enableCache
def __call__(self, wrapper):
def numericalmathfunction(*args, **kwargs):
func = wrapper(*args, **kwargs)
return func
return numericalmathfunction
#ClassDecorator(enableCache=True)
class Wrapper(object):
"""Wrapper docstring
Instructions on how to use the Wrapper
"""
def __init__(self, p):
self.p = p
model = Wrapper(4)
print model.__doc__
print Wrapper.__doc__
This returns
Wrapper docstring
None
Instances of Wrapper do keep the docstring, which is fine, but Wrapper itself does not. If a user wants to learn how to use Wrapper using help(Wrapper), he won't get what he wants.
I know I could just copy paste the dosctring into numericalmathfunction, but the decorator will be used on several classes with different docstrings.
Any ideas on how to make numericalmathfunction systematically inherit the docstrings of the wrapped class ?

Use functools.wraps() to update the attributes of the decorator:
from functools import wraps
class ClassDecorator:
"""ClassDecorator docstring
"""
def __init__(self, enableCache=True):
self.enableCache = enableCache
def __call__(self, wrapper):
#wraps(wrapper) # <-----------
def numericalmathfunction(*args, **kwargs):
func = wrapper(*args, **kwargs)
return func
return numericalmathfunction
#ClassDecorator(enableCache=True)
class Wrapper(object):
"""Wrapper docstring
Instructions on how to use the Wrapper
"""
def __init__(self, p):
self.p = p
See more standard library documentation for functools.wrap.

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

Implementing __getattr__ inside a class method such as __call__

So I've created a module inspired heavily by amoffat's sh module, where I can import shell programs as functions; unlike sh, my module can do something like git(C = path).commit(m = message) directly, by returning the module class itself as a partial: return partial(bakery, self.program). However, I've lost the ability to run something like ls() without a placeholder method like ls._(), which doesn't look as good. The code in the latter: return output_as_list(args, kwargs).
from functools import partial
def __getattr__(name):
if name == "__path__":
raise AttributeError
return bakery(name)
class bakery:
def __init__(self, program):
self.program = program
def __getattr__(self, subcommand):
return subcommand
#property
def __call__(self):
return partial(bakery, self.program)
My question is this:
Is there a way to tell __call__ you're accessing a dynamic attribute, using a __getattr__ inside it, for example, to implement both the git(C = path).commit(m = message) and ls() scenarios? Or to conditionally return a partial or an output list depending on whether an attribute of __call__ is being accessed?
Edit:
I was wondering if something similar to this might work?
def __call__(self, *args, **kwargs):
class inner_class:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def __getattr__(self, subcommand):
return partial(bakery, self.program)
def __call__(self, *args, **kwargs):
return bakery(*self.args, **self.kwargs)._get_output_as_list(*args, **kwargs)
return inner_class(self.program, *args, **kwargs)
Edit 2:
I suppose I could just convert the individual __call__ functions to subclasses, and import from whichever is necessary.

How to Create a Decorator Class that takes Arguments while Using `functools.wraps` and Preserving Access to the Decorated Instance

1. My Requirements
The Decorator Class should use functools.wraps so it has proper introspection and organization for later.
Access to the decorated instance should be possible.
In the example below, I do it by passing a wrapped_self argument to the __call__ method.
As the title states, the Decorator Class must have parameters that you can tune for for each method.
2. An Example of What It Would Look Like
The ideal situation should look something like this:
class A():
def __init__(self):
...
#LoggerDecorator(logger_name='test.log')
def do_something(self):
...
with the Decorator Class being, so far (basic logger decorator based on a recipe coming from David Beazley's Python Cookbook):
class LoggerDecorator():
def __init__(self, func, logger_name):
wraps(func)(self)
self.logger_name = logger_name
def config_logger(self):
... # for example, uses `self.logger_name` to configure the decorator
def __call__(self, wrapped_self, *args, **kwargs):
self.config_logger()
wrapped_self.logger = self.logger
func_to_return = self.__wrapped__(wrapped_self, *args, **kwargs)
return func_to_return
def __get__(self, instance, cls):
if instance is None:
return self
else:
return types.MethodType(self, instance)
3. How Do I Fix It?
The error I'm getting refers to __init__ not recognizing a third argument apparently:
TypeError: __init__() missing 1 required positional argument: 'func'
It has been suggested to me that I should be putting func in the __call__ method. However, if I put it there as a parameter, wrapped_self isn't properly read as a parameter and I get this error:
__call__() missing 1 required positional argument: 'wrapped_self'
I've tried many things to fix this issue, including: putting wraps(func)(self) inside __call__; and many variations of this very close but not quite filling all of the requirements solution (the problem with it is that I can't seem to be able to access wrapped_self anymore).
Since you're implementing a decorator that takes parameters, the __init__ method of LoggerDecorator should take only the parameters that configures the decorator, while the __call__ method instead should become the actual decorator that returns a wrapper function:
class LoggerDecorator():
def __init__(self, logger_name):
self.logger_name = logger_name
self.config_logger()
def __call__(self, func):
#wraps(func)
def wrapper(wrapped_self, *args, **kwargs):
wrapped_self.logger = self.logger
func_to_return = func(wrapped_self, *args, **kwargs)
return func_to_return
return wrapper
from functools import wraps
class LoggerDecorator:
def __init__(self, logger):
self.logger = logger
def __call__(self, func, *args, **kwargs):
print func, args, kwargs
# do processing
return func
#LoggerDecorator('lala')
def a():
print 1
The above should work as expected. If you're planning to call the decorator using keyword arguments you can remove the logger from __init__ and use **kwargs which will return a dict of the passed keywork arguments.

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

Difference between decorator classes and decorator functions

I guess that's how they are called, but I will give examples just in case.
Decorator class:
class decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print 'something'
self.func(*args, **kwargs)
Decorator function:
def decorator(func):
def wrapper(*args, **kwargs):
print 'something'
return func(*args, **kwargs)
return wrapper
Is using one or the other just a matter of taste? Is there any practical difference?
If you can write a function to implement your decorator you should prefer it. But not all decorators can easily be written as a function - for example when you want to store some internal state.
class counted(object):
""" counts how often a function is called """
def __init__(self, func):
self.func = func
self.counter = 0
def __call__(self, *args, **kwargs):
self.counter += 1
return self.func(*args, **kwargs)
#counted
def something():
pass
something()
print something.counter
I've seen people (including myself) go through ridiculous efforts to write decorators only with functions. I still have no idea why, the overhead of a class is usually totally negligible.
It is generally just a matter of taste. Most Python programs use duck typing and don't really care whether the thing they're calling is a function or an instance of some other type, so long as it is callable. And anything with a __call__() method is callable.
There are a few advantages to using function-style decorators:
Much cleaner when your decorator doesn't return a wrapper function (i.e., it returns the original function after doing something to it, such as setting an attribute).
No need to explicitly save the reference to the original function, as this is done by the closure.
Most of the tools that help you make decorators, such as functools.wraps() or Michele Simionato's signature-preserving decorator module, work with function-style decorators.
There may be some programs out there somewhere which don't use duck typing, but actually expect a function type, so returning a function to replace a function is theoretically "safer."
For these reasons, I use function-style decorators most of the time. As a counterexample, however, here is a recent instance in which the class-style decorator was more natural for me.
The proposed class decorator implementation has a slight difference with the function implementation : it will fail on methods
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('something')
self.func(*args, **kwargs)
class A:
#Decorator
def mymethod(self):
print("method")
A().mymethod()
will raise TypeError: mymethod() missing 1 required positional argument: 'self'
To add support of methods, you need to implement the __get__
import types
class Decorator2(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('something')
self.func(*args, **kwargs)
def __get__(self, instance, owner):
if instance is None:
return self
return types.MethodType(self, instance)
class B:
#Decorator2
def mymethod(self):
print("method")
B().mymethod()
will output
class B:...
something
method
The reason it works is that when you access B().mymethod, the __get__ is called first and supplies the bound method. Then __call__ is called
To conclude, provided you define the __get__, class and function implementation can be used the same way. See python cookbook recipe 9.9 for more information.

Categories