<commit_before>from repoze.lru import LRUCache
from .predicate import PredicateRegistry, MultiPredicate, SingleValueRegistry
from .sentinel import NOT_FOUND
from .argextract import ArgExtractor
from .arginfo import arginfo
from .error import RegistrationError, KeyExtractorError
from .mapply import lookup_mapply


class Registry(object):
    """A registry of predicate registries

    The key is an immutable that we perform the lookup for. The
    permutation key is the key to do the lookup with. The value should
    be an immutable as well (or at least hashable).

    The registry can be configured with predicates for a key, and
    the predicates are aware of permutations of keys. This means, among
    others, that a value registered for a base class is also matched
    when you look up a subclass.

    The Registry is designed to be easily cacheable.
    """
    def __init__(self):
        self.clear()

    def clear(self):
        """Clear the registry.
        """
        self.known_keys = set()
        self.arg_extractors = {}
        self.predicate_registries = {}

    def register_predicates(self, key, predicates):
        """Register the predicates to use for a lookup key.

        :param key: an immutable for which to register the predicates.
        :param predicates: a sequence of :class:`reg.Predicate` objects.
        :returns: a :class:`reg.PredicateRegistry`.
        """
        if len(predicates) == 0:
            result = self.predicate_registries[key] = SingleValueRegistry()
            return result
        if len(predicates) == 1:
            # an optimization in case just one predicate in use
            predicate = predicates[0]
        else:
            predicate = MultiPredicate(predicates)
        self.predicate_registries[key] = result = PredicateRegistry(predicate)
        return result

    def register_callable_predicates(self, callable, predicates):
        """Register predicates for a callable key.

        Works as :meth:`register_predicates`, but also
        makes sure a predicate key can be constructed from arguments
        to this callable.

        :param callable: a function from which to extract argument
          information.
        :param predicates: a sequence of :class:`reg.Predicate` objects.
        :returns: a :class:`reg.PredicateRegistry`.

        """
        r = self.register_predicates(callable, predicates)
        self.arg_extractors[callable] = ArgExtractor(callable, r.argnames())
        return r

    def register_dispatch_predicates(self, callable, predicates):
        """Register a dispatch function.

        Works as :meth:`register_callable_predicates`, but works
        with a dispatch and makes sure predicates can't be registered
        twice.

        :param callable: a dispatch callable.
        :param predicates: a sequence of :class:`reg.Predicate` objects.
        :returns: a :class:`reg.PredicateRegistry`.
        """
        if callable.initialized:
            return
        callable.initialized = True
        return self.register_callable_predicates(callable.wrapped_func,
                                                 predicates)

    def register_dispatch(self, callable):
        """Register a dispatch function.

        Works as :meth:`register_dispatch_predicates`, but extracts
        predicate information from information registered using the
        :func:`reg.dispatch` decorator.

        :param callable: a dispatch callable.
        :returns: a :class:`reg.PredicateRegistry`.
        """
        return self.register_dispatch_predicates(callable, callable.predicates)

    def register_value(self, key, predicate_key, value):
        """Register a value for a predicate_key.

        Given a key, register a value for a particular predicate_key
        in the registry. Raises a :exc:`reg.RegistrationError`
        if the predicate_key is already known for this key.

        :param key: an immutable
        :param predicate_key: an immutable predicate key defined by
          the predicates for this key.
        :param value: an immutable value to register.
        """
        if isinstance(predicate_key, list):
            predicate_key = tuple(predicate_key)
        # if we have a 1 tuple, we register the single value inside
        if isinstance(predicate_key, tuple) and len(predicate_key) == 1:
            predicate_key = predicate_key[0]
        self.predicate_registries[key].register(predicate_key, value)

    def register_function(self, callable, predicate_key, value):
        """Register a callable for a dispatch function.

        Like :meth:`register_value`, but makes sure that the value is
        a callable with the same signature as the original dispatch callable.
        If not, a :exc:`reg.RegistrationError` is raised.
        """
        self.register_dispatch(callable)
        value_arginfo = arginfo(value)
        if value_arginfo is None:
            raise RegistrationError(
                "Cannot register non-callable for dispatch "
                "function %r: %r" % (callable, value))
        if not same_signature(arginfo(callable.wrapped_func), value_arginfo):
            raise RegistrationError(
                "Signature of callable dispatched to (%r) "
                "not that of dispatch function (%r)" % (
                    value, callable.wrapped_func))
        self.register_value(callable.wrapped_func, predicate_key, value)

    def register_function_by_predicate_name(self, callable, value, **kw):
        """Register a callable for a dispatch function.

        Like :meth:`register_function`, but constructs the predicate_key
        based on the values in the ``kw`` argument, using the ``name``
        and ``default`` arguments to :class:`Predicate`.
        """
        predicate_key = self.predicate_key_by_predicate_name(
            callable.wrapped_func, kw)
        self.register_function(callable, predicate_key, value)

    def predicate_key(self, callable, *args, **kw):
        """Construct predicate_key for function arguments.

        For a callable and its function arguments, construct the
        appropriate predicate_key. This is used by the dispatch
        mechanism to dispatch to the right function.

        If the predicate_key cannot be constructed from args and kw,
        this raises a :exc:`KeyExtractorError`.

        :param callable: the callable for which to extract the predicate_key
        :param args: the varargs given to the callable.
        :param kw: the keyword arguments given to the callable.
        :returns: an immutable predicate_key based on the predicates
          the callable was configured with.
        """
        r = self.predicate_registries.get(callable)
        if r is None:
            raise KeyExtractorError()
        return r.key(self.arg_extractors[callable](*args, **kw))

    def predicate_key_by_predicate_name(self, callable, d):
        """Construct predicate key from dictionary.

        Uses ``name`` and ``default`` to predicate to construct the
        predicate key. If ``name`` is ``None`` then the predicate
        key cannot be constructed and a ``RegistrationError`` is raised.

        :param callable: the callable for which to extract the predicate_key
        :param d: dictionary with as keys predicate names and as values
          parts of the key.
        :returns: an immutable predicate_key based on the dictionary
          and the names and defaults of the predicates the callable
          was configured with.
        """
        r = self.predicate_registries.get(callable)
        if r is None:
            raise RegistrationError(
                "No predicate_key information known for: %s"
                % callable)
        return r.key_by_predicate_name(d)

    def component(self, key, predicate_key):
        """Lookup value in registry based on predicate_key.
<commit_msg>Fix docstring.<commit_after>from repoze.lru import LRUCache
from .predicate import PredicateRegistry, MultiPredicate, SingleValueRegistry
from .sentinel import NOT_FOUND
from .argextract import ArgExtractor
from .arginfo import arginfo
from .error import RegistrationError, KeyExtractorError
from .mapply import lookup_mapply


class Registry(object):
    """A registry of predicate registries

    The key is an immutable that we perform the lookup for. The
    permutation key is the key to do the lookup with. The value should
    be an immutable as well (or at least hashable).

    The registry can be configured with predicates for a key, and
    the predicates are aware of permutations of keys. This means, among
    others, that a value registered for a base class is also matched
    when you look up a subclass.

    The Registry is designed to be easily cacheable.
    """
    def __init__(self):
        self.clear()

    def clear(self):
        """Clear the registry.
        """
        self.known_keys = set()
        self.arg_extractors = {}
        self.predicate_registries = {}

    def register_predicates(self, key, predicates):
        """Register the predicates to use for a lookup key.

        :param key: an immutable for which to register the predicates.
        :param predicates: a sequence of :class:`reg.Predicate` objects.
        :returns: a :class:`reg.PredicateRegistry`.
        """
        if len(predicates) == 0:
            result = self.predicate_registries[key] = SingleValueRegistry()
            return result
        if len(predicates) == 1:
            # an optimization in case just one predicate in use
            predicate = predicates[0]
        else:
            predicate = MultiPredicate(predicates)
        self.predicate_registries[key] = result = PredicateRegistry(predicate)
        return result

    def register_callable_predicates(self, callable, predicates):
        """Register predicates for a callable key.

        Works as :meth:`register_predicates`, but also
        makes sure a predicate key can be constructed from arguments
        to this callable.

        :param callable: a function from which to extract argument
          information.
        :param predicates: a sequence of :class:`reg.Predicate` objects.
        :returns: a :class:`reg.PredicateRegistry`.

        """
        r = self.register_predicates(callable, predicates)
        self.arg_extractors[callable] = ArgExtractor(callable, r.argnames())
        return r

    def register_dispatch_predicates(self, callable, predicates):
        """Register a dispatch function.

        Works as :meth:`register_callable_predicates`, but works
        with a dispatch and makes sure predicates can't be registered
        twice.

        :param callable: a dispatch callable.
        :param predicates: a sequence of :class:`reg.Predicate` objects.
        :returns: a :class:`reg.PredicateRegistry`.
        """
        if callable.initialized:
            return
        callable.initialized = True
        return self.register_callable_predicates(callable.wrapped_func,
                                                 predicates)

    def register_dispatch(self, callable):
        """Register a dispatch function.

        Works as :meth:`register_dispatch_predicates`, but extracts
        predicate information from information registered using the
        :func:`reg.dispatch` decorator.

        :param callable: a dispatch callable.
        :returns: a :class:`reg.PredicateRegistry`.
        """
        return self.register_dispatch_predicates(callable, callable.predicates)

    def register_value(self, key, predicate_key, value):
        """Register a value for a predicate_key.

        Given a key, register a value for a particular predicate_key
        in the registry. Raises a :exc:`reg.RegistrationError`
        if the predicate_key is already known for this key.

        :param key: an immutable
        :param predicate_key: an immutable predicate key defined by
          the predicates for this key.
        :param value: an immutable value to register.
        """
        if isinstance(predicate_key, list):
            predicate_key = tuple(predicate_key)
        # if we have a 1 tuple, we register the single value inside
        if isinstance(predicate_key, tuple) and len(predicate_key) == 1:
            predicate_key = predicate_key[0]
        self.predicate_registries[key].register(predicate_key, value)

    def register_function(self, callable, predicate_key, value):
        """Register a callable for a dispatch function.

        Like :meth:`register_value`, but makes sure that the value is
        a callable with the same signature as the original dispatch callable.
        If not, a :exc:`reg.RegistrationError` is raised.
        """
        self.register_dispatch(callable)
        value_arginfo = arginfo(value)
        if value_arginfo is None:
            raise RegistrationError(
                "Cannot register non-callable for dispatch "
                "function %r: %r" % (callable, value))
        if not same_signature(arginfo(callable.wrapped_func), value_arginfo):
            raise RegistrationError(
                "Signature of callable dispatched to (%r) "
                "not that of dispatch function (%r)" % (
                    value, callable.wrapped_func))
        self.register_value(callable.wrapped_func, predicate_key, value)

    def register_function_by_predicate_name(self, callable, value, **kw):
        """Register a callable for a dispatch function.

        Like :meth:`register_function`, but constructs the predicate_key
        based on the values in the ``kw`` argument, using the ``name``
        and ``default`` arguments to :class:`Predicate`.
        """
        predicate_key = self.predicate_key_by_predicate_name(
            callable.wrapped_func, kw)
        self.register_function(callable, predicate_key, value)

    def predicate_key(self, callable, *args, **kw):
        """Construct predicate_key for function arguments.

        For a callable and its function arguments, construct the
        appropriate predicate_key. This is used by the dispatch
        mechanism to dispatch to the right function.

        If the predicate_key cannot be constructed from args and kw,
        this raises a :exc:`KeyExtractorError`.

        :param callable: the callable for which to extract the predicate_key
        :param args: the varargs given to the callable.
        :param kw: the keyword arguments given to the callable.
        :returns: an immutable predicate_key based on the predicates
          the callable was configured with.
        """
        r = self.predicate_registries.get(callable)
        if r is None:
            raise KeyExtractorError()
        return r.key(self.arg_extractors[callable](*args, **kw))

    def predicate_key_by_predicate_name(self, callable, d):
        """Construct predicate key from dictionary.

        Uses ``name`` and ``default`` to predicate to construct the
        predicate key. If the key cannot be constructed then
        a ``RegistrationError`` is raised.

        :param callable: the callable for which to extract the predicate_key
        :param d: dictionary with as keys predicate names and as values
          parts of the key.
        :returns: an immutable predicate_key based on the dictionary
          and the names and defaults of the predicates the callable
          was configured with.
        """
        r = self.predicate_registries.get(callable)
        if r is None:
            raise RegistrationError(
                "No predicate_key information known for: %s"
                % callable)
        return r.key_by_predicate_name(d)

    def component(self, key, predicate_key):
        """Lookup value in registry based on predicate_key.

{'fraction_non_alphanumeric': 0.07141950228542407, 'fraction_numerical': 0.0007618080243778568, 'mean_word_length': 2.5867486338797816, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6910684', 'n_tokens_mistral': 4153, 'n_tokens_neox': 3979, 'n_words': 1496}