Total rewrite of Reg! This includes a range of changes that can break code. The primary motivations for this rewrite:
- unify predicate system with class-based lookup system.
- extract dispatch information from specific arguments instead of all arguments.
Some specific changes:
Replaced @reg.generic decorator with @reg.dispatch() decorator. This decorator can be configured with predicates that extract information from the arguments. Rewrite this:
@reg.generic def foo(obj): pass
@reg.dispatch('obj') def foo(obj): pass
@reg.generic def bar(a, b): pass
@reg.dispatch('a', 'b') def bar(a, b): pass
This is to get dispatch on the classes of these instance arguments. If you want to match on the class of an attribute of an argument (for instance) you can use match_instance with a function:
@reg.dispatch(match_instance('a', lambda a: a.attr))
The first argument to match_instance is the name of the predicate by which you refer to it in register_function.
You can also use match_class to have direct dispatch on classes (useful for replicating classmethods), and match_key to have dispatch on the (immutable) value of the argument (useful for a view predicate system). Like for match_instance, you supply functions to these match functions that extract the exact information to dispatch on from the argument.
The register_function API replaces the register API to register a function. Replace this:
r.register(foo, (SomeClass,), dispatched_to)
r.register_function(foo, dispatched_to, obj=SomeClass)
You now use keyword parameters to indicate exactly those arguments specified by reg.dispatch() are actually predicate arguments. You don’t need to worry about the order of predicates anymore when you register a function for it.
The new classgeneric functionality is part of the predicate system now; you can use reg.match_class instead. Replace:
@reg.classgeneric def foo(cls): pass
@reg.dispatch(reg.match_class('cls', lambda cls: cls)) def foo(cls): pass
You can do this with any argument now, not just the first one.
pep443 support is gone. Reg is focused on its own dispatch system.
Compose functionality is gone – it turns out Morepath doesn’t use lookup composition to support App inheritance. The cached lookup functionality has moved into registry.py and now also supports caching of predicate-based lookups.
Dependency on the future module is gone in favor of a small amount of compatibility code.
- Added a @reg.classgeneric. This is like @reg.generic, but the first argument is treated as a class, not as an instance. This makes it possible to replace @classmethod with a generic function too.
- Fix documentation on running documentation tests. For some reason this did not work properly anymore without running sphinxpython explicitly.
- Optimization: improve performance of generic function calls by employing lookup_mapply instead of general mapply, as we only care about passing in the lookup argument when it’s defined, and any other arguments should work as before. Also added a perf.py which is a simple generic function timing script.
- Python 2.6 compatibility. (Ivo van der Wijk)
- Class maps (and thus generic function lookup) now works with old style classes as well.
- Marked as production/stable now in setup.py.
- Removed unused code from mapply.py.
- Typo fix in API docs.
- Make reg.ANY public. Used for predicates that match any value.
- arginfo has been totally rewritten and is now part of the public API of reg.
- Experimental Python 3.3 support thanks to the future module.
- If a generic function implementation defines a lookup argument that argument will be the lookup used to call it.
- Added reg.mapply(). This allows you to call things with more keyword arguments than it accepts, ignoring those extra keyword args.
- A function that returns None is not assumed to fail, so no fallback to the original generic function is triggered anymore.
- An optional precalc facility is made available on Matcher to avoid some recalculation.
- Implement a specific PredicateMatcher that matches a value on predicate.
- Initial public release.