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.

This module is an adapted work from the decorator version 3.3.2 package and is copyright of its owner as stated below. Adaptation work is done by Merchise.

Original copyright and license notices from decorator package:

Copyright (c) 2005-2011, Michele Simionato

All rights reserved.

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in bytecode form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

class xotl.tools.decorator.meta.FunctionMaker(func=None, name=None, signature=None, defaults=None, doc=None, module=None, funcdict=None)[source]

An object with the ability to create functions with a given signature. It has attributes name, doc, module, signature, defaults, dict and methods update and make.

classmethod create(obj, body, evaldict, defaults=None, doc=None, module=None, addsource=True, **attrs)[source]

Create a function from the strings name, signature and body. “evaldict” is the evaluation dictionary. If addsource is true an attribute __source__ is added to the result. The attributes attrs are added, if any.

make(src_templ, evaldict=None, addsource=False, **attrs)[source]

Make a new function from a given template and update the signature

update(func, **kw)[source]

Update the signature of func with the data in self

xotl.tools.decorator.meta.flat_decorator(caller, func=None)[source]

Creates a signature keeping decorator.

decorator(caller) converts a caller function into a decorator.

decorator(caller, func) decorates a function using a caller.

Deprecated since version 1.9.9: Use the decorator package.

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.