xotl.tools.decorator.meta - Decorator-making facilities

Decorator-making facilities.

This module provides a signature-keeping version of the xotl.tools.decorators.decorator(), which is now deprecated in favor of this module’s version.

We scinded the decorator-making facilities from decorators per se to allow the module xotl.tools.deprecation to be used by decorators and at the same time, implement the decorator deprecated() more easily.

xotl.tools.decorator.meta.decorator(caller)[source]

Eases the creation of decorators with arguments. Normally a decorator with arguments needs three nested functions like this:

def decorator(*decorator_arguments):
    def real_decorator(target):
        def inner(*args, **kwargs):
            return target(*args, **kwargs)
        return inner
    return real_decorator

This decorator reduces the need of the first level by comprising both into a single function definition. However it does not removes the need for an inner function:

>>> @decorator
... def plus(target, value):
...    from functools import wraps
...    @wraps(target)
...    def inner(*args):
...        return target(*args) + value
...    return inner

>>> @plus(10)
... def ident(val):
...     return val

>>> ident(1)
11

A decorator with default values for all its arguments (except, of course, the first one which is the decorated target) may be invoked without parenthesis:

>>> @decorator
... def plus2(func, value=1, missing=2):
...    from functools import wraps
...    @wraps(func)
...    def inner(*args):
...        print(missing)
...        return func(*args) + value
...    return inner

>>> @plus2
... def ident2(val):
...     return val

>>> ident2(10)
2
11

But (if you like) you may place the parenthesis:

>>> @plus2()
... def ident3(val):
...     return val

>>> ident3(10)
2
11

However, this is not for free, you cannot pass a single positional argument which type is a function:

>>> def p():
...    print('This is p!!!')

>>> @plus2(p)   
... def dummy():
...    print('This is dummy')
Traceback (most recent call last):
    ...
TypeError: p() takes ...

The workaround for this case is to use a keyword argument.