예제 #1
0
 def test_override(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     registry.register(1, name='foo')
     registry.override(2, name='foo')
     self.assertEqual(registry.lookup('foo'), 2)
예제 #2
0
 def test_override(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     registry.register(1, name='foo')
     registry.override(2, name='foo')
     self.assertEqual(registry.lookup('foo'), 2)
예제 #3
0
class FunctionDispatcher(object):
    """ Multidispatcher for functions

    This object dispatch calls to function by its argument types. Usually it is
    produced by :func:`.multifunction` decorator.

    You should not manually create objects of this type.
    """

    def __init__(self, argspec, params_arity):
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [("arg_%d" % n, TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)

    def check_rule(self, rule, *argtypes):
        # Check if we have the right number of parametrized types
        if len(argtypes) != self.params_arity:
            raise TypeError("Wrong number of type parameters.")

        # Check if we have the same argspec (by number of args)
        rule_argspec = inspect.getargspec(rule)
        if not is_equalent_argspecs(rule_argspec, self.argspec):
            raise TypeError("Rule does not conform "
                            "to previous implementations.")

    def register_rule(self, rule, *argtypes):
        """ Register new ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.register(rule, *argtypes)

    def override_rule(self, rule, *argtypes):
        """ Override ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.override(rule, *argtypes)

    def lookup_rule(self, *args):
        """ Lookup rule by ``args``. Returns None if no rule was found."""
        args = args[:self.params_arity]
        rule = self.registry.lookup(*args)
        if rule is None:
            raise TypeError("No available rule found for %r" % (args,))
        return rule

    def when(self, *argtypes):
        """ Decorator for registering new case for multifunction

        New case will be registered for types identified by ``argtypes``. The
        length of ``argtypes`` should be equal to the length of ``argtypes``
        argument were passed corresponding :func:`.multifunction` call, which
        also indicated the number of arguments multifunction dispatches on.
        """
        def register_rule(func):
            self.register_rule(func, *argtypes)
            return self
        return register_rule

    @property
    def otherwise(self):
        """ Decorator which registeres "catch-all" case for multifunction"""
        def register_rule(func):
            self.register_rule(func, [object]*self.params_arity)
            return self
        return register_rule

    def override(self, *argtypes):
        """ Decorator for overriding case for ``argtypes``"""
        def override_rule(func):
            self.override_rule(func, *argtypes)
            return self
        return override_rule

    def __call__(self, *args, **kwargs):
        """ Dispatch call to appropriate rule."""
        rule = self.lookup_rule(*args)
        return rule(*args, **kwargs)
예제 #4
0
class FunctionDispatcher(object):
    """ Multidispatcher for functions

    This object dispatch calls to function by its argument types. Usually it is
    produced by :func:`.multifunction` decorator.

    You should not manually create objects of this type.
    """
    def __init__(self, argspec, params_arity):
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [("arg_%d" % n, TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)

    def check_rule(self, rule, *argtypes):
        # Check if we have the right number of parametrized types
        if len(argtypes) != self.params_arity:
            raise TypeError("Wrong number of type parameters.")

        # Check if we have the same argspec (by number of args)
        rule_argspec = inspect.getargspec(rule)
        if not is_equalent_argspecs(rule_argspec, self.argspec):
            raise TypeError("Rule does not conform "
                            "to previous implementations.")

    def register_rule(self, rule, *argtypes):
        """ Register new ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.register(rule, *argtypes)

    def override_rule(self, rule, *argtypes):
        """ Override ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.override(rule, *argtypes)

    def lookup_rule(self, *args):
        """ Lookup rule by ``args``. Returns None if no rule was found."""
        args = args[:self.params_arity]
        rule = self.registry.lookup(*args)
        if rule is None:
            raise TypeError("No available rule found for %r" % (args, ))
        return rule

    def when(self, *argtypes):
        """ Decorator for registering new case for multifunction

        New case will be registered for types identified by ``argtypes``. The
        length of ``argtypes`` should be equal to the length of ``argtypes``
        argument were passed corresponding :func:`.multifunction` call, which
        also indicated the number of arguments multifunction dispatches on.
        """
        def register_rule(func):
            self.register_rule(func, *argtypes)
            return self

        return register_rule

    @property
    def otherwise(self):
        """ Decorator which registeres "catch-all" case for multifunction"""
        def register_rule(func):
            self.register_rule(func, [object] * self.params_arity)
            return self

        return register_rule

    def override(self, *argtypes):
        """ Decorator for overriding case for ``argtypes``"""
        def override_rule(func):
            self.override_rule(func, *argtypes)
            return self

        return override_rule

    def __call__(self, *args, **kwargs):
        """ Dispatch call to appropriate rule."""
        rule = self.lookup_rule(*args)
        return rule(*args, **kwargs)