Skip to main content
CI Status https://img.shields.io/pypi/v/reg.svg https://img.shields.io/pypi/pyversions/reg.svg

Reg: Clever Dispatch

Reg is a Python library that provides generic function support to Python. It help you build powerful registration and configuration APIs for your application, library or framework.

Documentation.

CHANGES

1.0.0 (2026-10-10)

  • Add type annotations and integrate mypy and pyright.

  • Switch to pyproject.toml based project setup.

  • Replace repoze.lru.lru_cache with functools.lru_cache to get rid of the dependency and gain typing support.

  • reg.arginfo is now implemented manually using inspect.signature, instead of relying on the deprecated compatibility method in inspect, in order to better support Python 3.14+.

    It is recommended to migrate from reg.arginfo to pure inspect.signature, since the utility this module provides is now very limited, compared to inspect.signature, since that already properly handles self parameters.

  • Add support for Python 3.11, 3.12, 3.13, 3.14 and 3.15.

  • Drop support for Python below 3.11.

  • Support Pypy 3.12.

  • Use GitHub Actions for CI.

  • Fix docs, docstrings and Sphinx config.

  • Update developing documentation.

  • Make an overall cleanup.

  • Fix readthedocs integration.

  • Replace flake8, black, isort, pyupgrade and pre-commit with Ruff.

  • Add a tracked Git pre-commit hook for Ruff checks on staged Python files.

  • Remove coveralls integration.

  • Adjust the deployment strategy:

    • Move the Pypi upload from zest.release to gh-actions.

    • Use v + version as release tags like v1.0.0.

    • So we still use zest.release but without publishing to Pypi. The Pypi upload is triggered by pushing the new release tag to GitHub. This happens in the Release workflow in .github/workflows/release.yml. With this workflow we get Trusted Publishing with short-lived OIDC tokens that PyPI issues to one specific repository, workflow file and environment (pypi). We also get PEP 740 provenance and can set required reviewers for the environment and a ruleset who can create release tags and trigger releases.

0.12 (2020-01-29)

  • Breaking change

    reg.arginfo(callable) returns now a FullArgSpec tuple instead of the deprecated ArgSpec tuple. FullArgSpec has full support for annotations and keyword-only parameters.

    Fixes #55.

  • Removed: Removed support for Python 2.

    You have to upgrade to Python 3 if you want to use this version.

  • Dropped support for Python 3.3.

  • Added support for Python 3.5, 3.6, 3.7, 3.8 and PyPy 3.6.

  • Make Python 3.7 the default testing environment.

  • Add integration for the Black code formatter.

0.11 (2016-12-23)

  • Breaking change

    The key_predicate function is gone. You can now use Predicate(..., index=KeyIndex) or match_key instead.

  • Breaking change

    The class_predicate function is gone. You can now use Predicate(..., index=ClassIndex), match_instance or match_class instead.

  • Breaking change

    The undocumented Sentinel class and NOT_FOUND object are gone.

  • Breaking change

    The class PredicateRegistry is not longer part of the API. Internally, the classes MultiPredicate, MultiIndex, SingleValueRegistry have all been merged into PredicateRegistry, which should now considered an implementation detail.

  • The second argument for match_key is now optional; if you don’t supply it match_key will generate a predicate function that extracts that name by default.

  • The documentation now includes a section describing the internals of Reg.

  • Upload universal wheels to pypi during release.

0.10 (2016-10-04)

  • Breaking change

    Reg has undergone another API breaking change. The goals of this change were:

    • Make everything explicit.

    • A simpler implementation structure – dispatch functions maintain their own registries, which allows for less interacting objects.

    • Make the advanced context-dependent dispatch more Pythonic by using classes with special dispatch methods.

    Detailed changes:

    • reg.Registry is gone. Instead you register directly on the dispatch function:

      @reg.dispatch('a')
      def foo(a):
        ...
      
      def foo_implementation(a):
        ...
      
      foo.register(foo_implementation, a=Document)
    • Caching is now per dispatch function, not globally per lookup. You can pass a get_key_lookup function that wraps reg.PredicateRegistry instance inside a reg.DictCachingKeyLookup cache. You can also use a reg.LruCachingKeyLookup if you expect a dispatch to be called with a large amount of possible predicate combinations, to preserve memory.

    • The whole concept of a “lookup” is gone:

      • reg.implicit is gone: everything is explicit. There is no more implicit lookup.

      • reg.Lookup itself is gone – its now implemented directly in the dispatch object, but was already how you accessed it.

      • The special lookup argument to pass through the current Lookup is gone. If you need context-dependent dispatch, you use dispatch methods.

      • If you need context dependent dispatch, where the functions being dispatched to depend on application context (such as Morepath’s application mounting), you use reg.dispatch_method to create a dispatch method. A dispatch method maintains an entirely separate dispatch registry for each subclass. You use reg.methodify to register a dispatch function that takes an optional context first argument.

    If you do not use the context-dependent dispatch feature, then to upgrade your code:

    • remove any reg.set_implicit from your code, setup of Lookup and the like.

    • If you use an explicit lookup argument you can just remove them.

    • You also need to change your registration code: no more reg.Registry setup.

    • Change your registrations to be on the dispatch objects itself using Dispatch.register.

    • To enable caching you need to set up get_key_lookup on the dispatch functions. You can create a partially applied version of dispatch to make this less verbose:

      import reg
      from functools import partial
      
      def get_caching_key_lookup(r):
          return reg.CachingKeyLookup(r, 5000, 5000, 5000)
      
      dispatch = partial(reg.dispatch, get_key_lookup=get_caching_key_lookup)
    • dispatch_external_predicates is gone. Just use dispatch directly. You can add predicates to an existing Dispatch object using the add_predicates method.

    If you do use the context-dependent dispatch feature, then you also need to:

    • identify the context class in your application (or create one).

    • move the dispatch functions to this class, marking them with @reg.dispatch_method instead of @reg.dispatch.

    • Registration is now using <context_class>.<method>.register. Functions you register this way behave as methods to context_class, so get an instance of this class as the first argument.

    • You can also use reg.methodify to register implementation functions that do not take the context as the first argument – this is useful when upgrading existing code.

    • Call your context-dependent methods as methods on the context instance. This way you can indicate what context you are calling your dispatch methods in, instead of using the lookup` argument.

    In some cases you want a context-dependent method that actually does not dispatch on any of its arguments. To support this use case you can simply set function (that takes an app argument) as a the method on the context class directly:

    Context.my_method = some_function

    If you want to set up a function that doesn’t take a reference to a Context instance as its first argument, you can use reg.methodify to turn it into a method that ignores its first argument:

    Context.my_method = reg.methodify(some_function)

    If you want to register a function that might or might not have a reference to a Context instance as its first argument, called, e.g., app, you can use the following:

    Context.my_method = reg.methodify(some_function, selfname='app')
  • Breaking change

    Removed the helper function mapply from the API.

  • Breaking change

    Removed the exception class KeyExtractorError from the API. When passing the wrong number of arguments to a dispatch function, or when using the wrong argument names, you will now get a TypeError, in conformity with standard Python behaviour.

  • Breaking change

    Removed the KeyExtractor class from the API. Callables used in predicate construction now expect the same arguments as the dispatch function.

  • Breaking change

    Removed the argnames attribute from Predicate and its descendant.

  • Breaking change

    Remove the match_argname predicate. You can now use match_instance with no callable instead.

  • The second argument for match_class is now optional; if you don’t supply it match_class will generate a predicate function that extracts that name by default.

  • The second argument for match_instance is now optional; if you don’t supply it match_instance will generate a predicate function that extracts that name by default.

  • Include doctests in Tox and Travis.

  • We now use virtualenv and pip instead of buildout to set up the development environment. The development documentation has been updated accordingly.

  • As we reached 100% code coverage for pytest, coveralls integration was replaced by the --fail-under=100 argument of coverage report in the tox coverage test.

0.9.3 (2016-07-18)

  • Minor fixes to documentation.

  • Add tox test environments for Python 3.4 and 3.5, PyPy 3 and PEP 8.

  • Make Python 3.5 the default Python environment.

  • Changed location NoImplicitLookupError was imported from in __init__.py.

0.9.2 (2014-11-13)

  • Reg was a bit too strict; when you had multiple (but not single) predicates, Reg would raise KeyError when you put in an unknown key. Now they’re just being silently ignored, as they don’t do any harm.

  • Eliminated a check in ArgExtractor that could never take place.

  • Bring test coverage back up to 100%.

  • Add converage configuration to ignore test files in coverage reporting.

0.9.1 (2014-11-11)

  • A bugfix in the behavior of the fallback logic. In situations with multiple predicates of which one is a class predicate it was possible for a fallback not to be found even though a fallback was available.

0.9 (2014-11-11)

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

    to this:

    @reg.dispatch('obj')
    def foo(obj):
       pass

    And this:

    @reg.generic
    def bar(a, b):
        pass

    To this:

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

    with:

    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

    with:

    @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.

0.8 (2014-08-28)

  • 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.

0.7 (2014-06-17)

  • 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.

0.6 (2014-04-08)

  • Removed unused code from mapply.py.

  • Typo fix in API docs.

0.5 (2014-01-21)

  • Make reg.ANY public. Used for predicates that match any value.

0.4 (2014-01-14)

  • arginfo has been totally rewritten and is now part of the public API of reg.

0.3 (2014-01-06)

  • Experimental Python 3.3 support thanks to the future module.

0.2 (2013-12-19)

  • 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.

0.1 (2013-10-28)

  • Initial public release.

Metadata

Release files for reg 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for reg 1.0.0
File Size Uploaded
reg-1.0.0.tar.gz 65.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for reg 1.0.0
File Interpreter ABI Platform
reg-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 131.1 kB

Release files / reg-1.0.0.tar.gz

Download URL reg-1.0.0.tar.gz
Size 65.5 kB
Tags Source
SHA-256 checksum
How to use checksums
1eccf0348ae7e262aadb7645efa6d563d1e72f0483ca8b91b426cdc135575af3
BLAKE2b-256 checksum
How to use checksums
bd8a0902344e077467504812ccef78f538cf93de3bafb0e655aea3895805b605
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / reg-1.0.0-py3-none-any.whl

Download URL reg-1.0.0-py3-none-any.whl
Size 65.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1adcbc2a13da6696d604ff163c9b88c43f3d5216c0ca6b340719de7c45afed8a
BLAKE2b-256 checksum
How to use checksums
18fcd690383c3e6103d04e0dd9d0ec5774be1f8a3ea729d3854a95611f61d627
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.12

2 release files

0.11

2 release files

0.10

1 release file

0.9.3

1 release file

0.9.2

1 release file

0.9.1

1 release file

0.9

1 release file

0.8

1 release file

0.7

1 release file

0.6

1 release file

0.5

1 release file

0.4

1 release file

0.3

1 release file

0.2

1 release file

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page