xoutil.annotate - Py3k compatible annotations for Python 2

Provides Python 3k forward-compatible (PEP 3107) annotations.

Deprecated since version 2.0.0: Not needed in Python 3.

Note

The signature argument for the annotate() in this module may not work on other python implementations than CPython. Currently, Pypy passes all but local variable tests.

xoutil.annotate.annotate(signature=None, **annotations)[source]

Annotates a function with a Python 3k forward-compatible __annotations__ mapping.

See PEP 3107 for more details about annotations.

Parameters:
  • signature
    A string with the annotated signature of the
    decorated function.

    This string should follow the annotations syntax in PEP 3107. But there are several deviations from the PEP text:

    • There’s no support for the full syntax of Python 2 expressions; in particular nested arguments are not supported since they are deprecated and are not valid in Py3k.
    • Specifying defaults is no supported (nor needed). Defaults are placed in the signature of the function.
    • In the string it makes no sense to put an argument without an annotation, so this will raise an exception (SyntaxError).
  • keyword_annotations

    These are each mapped to a single annotation.

    Since you can’t include the ‘return’ keyword argument for the annotation related with the return of the function, we provide several alternatives: if any of the following keywords arguments is provided (tested in the given order): ‘return_annotation’, ‘_return’, ‘__return’; then it will be considered the ‘return’ annotation, the rest will be regarded as other annotations.

In any of the previous cases, you may provide more (or less) annotations than possible by following the PEP syntax. This is not considered an error, since the PEP allows annotations to be modified by others means.

If you provide a signature string and keywords annotations, the keywords will take precedence over the signature:

>>> @annotate('() -> list', return_annotation=tuple)
... def otherfunction():
...    pass

>>> otherfunction.__annotations__.get('return') is tuple
True

When parsing the signature the locals and globals in the context of the declaration are taken into account:

>>> interface = object # let's mock of ourselves
>>> class ISomething(interface):
...    pass

>>> @annotate('(a: ISomething) -> ISomething')
... def somewhat(a):
...     return a

>>> somewhat.__annotations__.get('a')     
<class '...ISomething'>

Deprecated since version 2.0.0.