Source code for transonic.signatures

"""Compute function signatures
==============================

Internal API
------------

.. autofunction:: _format_types_as_backend_types

.. autofunction:: compute_signatures_from_typeobjects

.. autofunction:: _make_signature_from_template_variables

.. autofunction:: make_signatures_from_typehinted_func

"""

import itertools
import inspect
from typing import List

from transonic.typing import format_type_as_backend_type, str2type


[docs]def _format_types_as_backend_types(types, backend_type_formatter, **kwargs): """Compute a list of Pythran/Cython/... types""" backend_types = [] for type_ in types: backend_types.append( format_type_as_backend_type(type_, backend_type_formatter, **kwargs) ) # TODO: handle this with an exception if "_empty" in backend_types: raise ValueError( "At least one annotation type lacking in a signature.\n" f"types = {types}" ) return backend_types
[docs]def compute_signatures_from_typeobjects( types_in, backend_type_formatter ) -> List[List[str]]: """Compute a list of lists (signatures) of strings (backend types)""" if isinstance(types_in, dict): types_in = types_in.values() types = [] for type_ in types_in: if isinstance(type_, str): type_ = str2type(type_) types.append(type_) template_parameters = set() for type_ in types: if hasattr(type_, "get_template_parameters"): template_parameters.update(type_.get_template_parameters()) if not template_parameters: if "_empty" in types: raise ValueError( "At least one annotation type lacking in a signature.\n" f"types = {types}" ) str_types = [ format_type_as_backend_type(type_, backend_type_formatter) for type_ in types ] return (str_types,) if not all(param.values for param in template_parameters): raise ValueError( f"{template_parameters}, {[param.values for param in template_parameters]}" ) values_template_parameters = {} for param in template_parameters: values_template_parameters[param.__name__] = param.values backend_types = [] names = values_template_parameters.keys() for set_types in itertools.product(*values_template_parameters.values()): template_variables = dict(zip(names, set_types)) backend_types.append( _format_types_as_backend_types( types, backend_type_formatter, **template_variables ) ) return backend_types
[docs]def _make_signature_from_template_variables( func, backend_type_formatter, _signature=None, as_list_str=False, **kwargs ): """Create signature for a function with values for the template types (This function should only be used in :func:`make_signatures_from_typehinted_func`) Parameters ---------- func: a function kwargs : dict The template types and their value """ if _signature is None: _signature = inspect.signature(func) types = [param.annotation for param in _signature.parameters.values()] backend_types = _format_types_as_backend_types( types, backend_type_formatter, **kwargs ) # "multiply" the signatures to take into account the "or" syntax multi_pythran_types = [ _ for _ in itertools.product(*[t.split(" or ") for t in backend_types]) ] signatures = [] for backend_types in multi_pythran_types: if as_list_str: signature = backend_types else: signature = f"{func.__name__}(" + ", ".join(backend_types) + ")" signatures.append(signature) return signatures
[docs]def make_signatures_from_typehinted_func( func, backend_type_formatter, as_list_str=False ): """Make the signatures from annotations if it is possible Useful when there are only "not templated" types. """ annotations = func.__annotations__ if not annotations: return tuple() for key, value in annotations.items(): if isinstance(value, str): annotations[key] = str2type(value) types = annotations.values() template_parameters = [] for type_ in types: if hasattr(type_, "get_template_parameters"): template_parameters.extend(type_.get_template_parameters()) template_parameters = set(template_parameters) _signature = inspect.signature(func) if not template_parameters: signatures = _make_signature_from_template_variables( func, backend_type_formatter, _signature=_signature, as_list_str=as_list_str, ) return signatures if not all(param.values for param in template_parameters): return tuple() values_template_parameters = {} for param in template_parameters: values_template_parameters[param.__name__] = param.values names = values_template_parameters.keys() signatures = [] for set_types in itertools.product(*values_template_parameters.values()): template_variables = dict(zip(names, set_types)) signatures.extend( _make_signature_from_template_variables( func, backend_type_formatter, _signature=_signature, as_list_str=as_list_str, **template_variables, ) ) return signatures