django_auxilium.utils.functools.decorators module¶
Collection of simple utilities which modify some behaviour of functions
-
class
django_auxilium.utils.functools.decorators.
Decorator
[source]¶ Bases:
object
Base class for various decorators.
Its aim is to do the same for decorators as Django class-based-views did to function-based-views.
The most common pattern for creating decorators in Python can be summarized in the following snippet:
from functools import wraps def decorator(f): @wraps(f) def wrapper(*args, **args): # some logic here return f(*args, **kwargs) return wrapper
The problem with the above approach is when decorators need to employ more difficult logic. That sometimes can cause decorator functions to become big hence making it difficult to maintain and test. This class is meant to simplify this task. It provides a way to make decorators by using classes. Its aim is to do the same for decorators as Django class-based-views did to function-based-views. This means that decorator’s various functionality can be split among class methods which can make the decorator’s logic more transparent and more test-friendly. It also automatically wraps the decorated object using
functools.wraps
saving some coding lines. Finally, this class allows to create decorators where initializing the decorator is optional. This perhaps can better be illustrated in a snippet:@decorator # not initialized def happy(): pass @decorator(foo='bar') # initialized def bunnies(): pass
Using this class is pretty simple. The most useful method you should know is
get_wrapped_object()
. Inside the method you can refer toto_wrap
which is the object the method should wrap. The method itself should return the wrapped version of theto_wrap
object. If your decorator needs to accept additional parameters, you can overwrite decorators__init__
. Finally, to use the decorator, don’t forget to use theas_decorator()
class method. You can refer to Examples to see a more full example of how to use this class.Examples
>>> class D(Decorator): ... def __init__(self, happy=False): ... self.happy = happy ... def get_wrapped_object(self): ... def wrapped(*args, **kwargs): ... print('called wrapped with', args, kwargs) ... if self.happy: ... print('Bunnies are very happy today!') ... return self.to_wrap(*args, **kwargs) ... return wrapped ... >>> decorator = D.as_decorator() >>> # not initialized (default values will be used if defined) >>> @decorator ... def sum(a, b): ... return a + b >>> sum(5, 6) called wrapped with (5, 6) {} 11 >>> # initialized with no parameters (default values will be used if defined) >>> @decorator() ... def sum(a, b): ... return a + b >>> sum(7, 8) called wrapped with (7, 8) {} 15 >>> # initialized with keyword parameters >>> @decorator(happy=True) ... def sum(a, b): ... "Sum function" ... return a + b >>> sum(9, 10) called wrapped with (9, 10) {} Bunnies are very happy today! 19 >>> sum.__doc__ == 'Sum function' True
-
to_wrap
¶ object – The object to be decorated/wrapped. This attributes becomes available when the decorator is called on the object.
-
classmethod
as_decorator
(*a, **kw)[source]¶ Return the actual decorator.
This method is necessary because the decorator is a class. Consider the following:
>>> class ClassDecorator(object): ... def __init__(self, obj): ... self.to_wrap = obj >>> @ClassDecorator ... def foo(): pass >>> isinstance(foo, ClassDecorator) True
In the above, since
foo
will be passed to the decorator’s class__init__
, the returned object will be an instance of the decorator’s class instead of a wrapper function. To avoid that, this method constructs a wrapper function which guarantees that the output of the decorator will be the wrapped object:>>> class D(Decorator): ... pass >>> d = D.as_decorator() >>> @d ... def foo(): pass >>> isinstance(foo, D) False
-
get_wrapped_object
()[source]¶ Returns the wrapped version of the object to be decorated/wrapped.
This is the meat of class because this method is the one which creates the decorator. Inside the method, you can refer to the object to be decorated via
self.to_wrap
.Note
This class automatically uses the
functools.wraps
to preserve theto_wrap
’s object useful attributes such as__doc__
hence there is no need to do that manually. You can just return a wrapped object and the class will take care of the rest.Returns: f – Decorated/wrapped function Return type: object
-
-
class
django_auxilium.utils.functools.decorators.
HybridDecorator
(is_method=None)[source]¶ Bases:
django_auxilium.utils.functools.decorators.Decorator
Class for implementing decorators which can decorate both regular functions as well as class methods.
This decorator automatically determines if the object to be decorated is a stand-alone function or a class method by adding an
in_class
attribute.Parameters: is_method (bool, optional) – Explicitly specify whether the decorator is being used on class method or a standalone function. When not specified, pre_wrap()
is used to automatically determine that. Please look at its documentation for the explanation of its limitations.-
in_class
¶ bool –
True
if the object to be decorated is a class method, orFalse
if it is a standalone function
-
pre_wrap
()[source]¶ Method which determines whether the
to_wrap
is a class method or a standalone functionWarning
This method uses pretty primitive technique to determine whether the wrapped callable is a class method or a function and so it might not work in all cases. It checks the first parameter name of the callable and if it is either
'self'
or'cls'
it is most likely a method.If you need more precise behavior you are encouraged to use
is_method
decorator parameter.
-