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)
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)
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)