<commit_before>"""
Handles dispatching array operations to the correct backend library, as well
as converting arrays to backend formats and then potentially storing them as
constants.
"""

import importlib

import numpy

from . import cupy as _cupy
from . import jax as _jax
from . import tensorflow as _tensorflow
from . import theano as _theano
from . import torch as _torch

__all__ = ["get_func", "has_einsum", "has_tensordot", "build_expression", "evaluate_constants", "has_backend"]

# known non top-level imports
_aliases = {
    'dask': 'dask.array',
    'theano': 'theano.tensor',
    'torch': 'opt_einsum.backends.torch',
    'jax': 'jax.numpy',
    'autograd': 'autograd.numpy',
    'mars': 'mars.tensor',
}


def _import_func(func, backend, default=None):
    """Try and import ``{backend}.{func}``.
    If library is installed and func is found, return the func;
    otherwise if default is provided, return default;
    otherwise raise an error.
    """
    try:
        lib = importlib.import_module(_aliases.get(backend, backend))
        return getattr(lib, func) if default is None else getattr(lib, func, default)
    except AttributeError:
        raise AttributeError("{} doesn't seem to provide the function {}".format(backend, func))


# manually cache functions as python2 doesn't support functools.lru_cache
#     other libs will be added to this if needed, but pre-populate with numpy
_cached_funcs = {
    ('tensordot', 'numpy'): numpy.tensordot,
    ('transpose', 'numpy'): numpy.transpose,<commit_msg>more detailed error when backend is missing a function e.g. einsum (#140)<commit_after>"""
Handles dispatching array operations to the correct backend library, as well
as converting arrays to backend formats and then potentially storing them as
constants.
"""

import importlib

import numpy

from . import cupy as _cupy
from . import jax as _jax
from . import tensorflow as _tensorflow
from . import theano as _theano
from . import torch as _torch

__all__ = ["get_func", "has_einsum", "has_tensordot", "build_expression", "evaluate_constants", "has_backend"]

# known non top-level imports
_aliases = {
    'dask': 'dask.array',
    'theano': 'theano.tensor',
    'torch': 'opt_einsum.backends.torch',
    'jax': 'jax.numpy',
    'autograd': 'autograd.numpy',
    'mars': 'mars.tensor',
}


def _import_func(func, backend, default=None):
    """Try and import ``{backend}.{func}``.
    If library is installed and func is found, return the func;
    otherwise if default is provided, return default;
    otherwise raise an error.
    """
    try:
        lib = importlib.import_module(_aliases.get(backend, backend))
        return getattr(lib, func) if default is None else getattr(lib, func, default)
    except AttributeError:
        error_msg = ("{} doesn't seem to provide the function {} - see "
                     "https://optimized-einsum.readthedocs.io/en/latest/backends.html "
                     "for details on which functions are required for which contractions.")
        raise AttributeError(error_msg.format(backend, func))


# manually cache functions as python2 doesn't support functools.lru_cache
#     other libs will be added to this if needed, but pre-populate with numpy
_cached_funcs = {
    ('tensordot', 'numpy'): numpy.tensordot,
    ('transpose', 'numpy'): numpy.transpose,
{'fraction_non_alphanumeric': 0.10844817255841821, 'fraction_numerical': 0.0014979029358897543, 'mean_word_length': 3.8181818181818183, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2112760', 'n_tokens_mistral': 1017, 'n_tokens_neox': 1002, 'n_words': 348}