This module provides bases for predicates dispatching (the pattern in use here is similar to what’s refered as multi-dispatch or predicate-dispatch in the literature, though a bit different since the idea is to select across different implementation ‘e.g. classes), not to dispatch a message to a function or method. It contains the following classes:

  • RegistryStore, the top level object which loads implementation objects and stores them into registries. You’ll usually use it to access registries and their contained objects;

  • Registry, the base class which contains objects semantically grouped (for instance, sharing a same API, hence the ‘implementation’ name). You’ll use it to select the proper implementation according to a context. Notice you may use registries on their own without using the store.


implementation objects are usually designed to be accessed through the registry and not by direct instantiation, besides to use it as base classe.

The selection procedure is delegated to a selector, which is responsible for scoring the object according to some context. At the end of the selection, if an implementation has been found, an instance of this class is returned. A selector is built from one or more predicates combined together using AND, OR, NOT operators (actually &, | and ~). You’ll thus find some base classes to build predicates:

You’ll eventually find one concrete predicate: yes

class logilab.common.registry.RegistryStore(debugmode: bool = False)[source]#

This class is responsible for loading objects and storing them in their registry which is created on the fly as needed.

It handles dynamic registration of objects and provides a convenient api to access them. To be recognized as an object that should be stored into one of the store’s registry (Registry), an object must provide the following attributes, used control how they interact with the registry:


list of registry names (string like ‘views’, ‘templates’…) into which the object should be registered


object identifier in the registry (string like ‘main’, ‘primary’, ‘folder_box’)


the object predicate selectors

Moreover, the __abstract__ attribute may be set to True to indicate that an object is abstract and should not be registered (such inherited attributes not considered).


When using the store to load objects dynamically, you always have to use super() to get the methods and attributes of the superclasses, and not use the class identifier. If not, you’ll get into trouble at reload time.

For example, instead of writing:

class Thing(Parent):
    __regid__ = 'athing'
    __select__ = yes()

    def f(self, arg1):
        Parent.f(self, arg1)

You must write:

class Thing(Parent):
    __regid__ = 'athing'
    __select__ = yes()

    def f(self, arg1):
        super(Thing, self).f(arg1)

Dynamic loading is triggered by calling the register_modnames() method, given a list of modules names to inspect.

register_modnames(modnames: List[str]) None[source]#

register all objects found in <modnames>

For each module, by default, all compatible objects are registered automatically. However if some objects come as replacement of other objects, or have to be included only if some condition is met, you’ll have to define a registration_callback(vreg) function in the module and explicitly register all objects in this module, using the api defined below.

register_all(objects: Iterable, modname: str, butclasses: Sequence = ()) None[source]#

register registrable objects into objects.

Registrable objects are properly configured subclasses of RegistrableObject. Objects which are not defined in the module modname or which are in butclasses won’t be registered.

Typical usage is:

store.register_all(globals().values(), __name__, (ClassIWantToRegisterExplicitly,))

So you get partially automatic registration, keeping manual registration for some object (to use register_and_replace() for instance).

register_and_replace(obj, replaced, registryname=None)[source]#

register obj object into registryname or obj.__registries__ if not specified. If found, the replaced object will be unregistered first (else a warning will be issued as it is generally unexpected).

register(obj: Any, registryname: Optional[Any] = None, oid: Optional[Any] = None, clear: bool = False) None[source]#

register obj implementation into registryname or obj.__registries__ if not specified, with identifier oid or obj.__regid__ if not specified.

If clear is true, all objects with the same identifier will be previously unregistered.

unregister(obj, registryname=None)[source]#

unregister obj object from the registry registryname or obj.__registries__ if not specified.


Once the function registration_callback(vreg) is implemented in a module, all the objects from this module have to be explicitly registered as it disables the automatic object registration.


def registration_callback(store):
   # register everything in the module except BabarClass
   store.register_all(globals().values(), __name__, (BabarClass,))

   # conditionally register BabarClass
   if 'babar_relation' in store.schema:

In this example, we register all application object classes defined in the module except BabarClass. This class is then registered only if the ‘babar_relation’ relation type is defined in the instance schema.

def registration_callback(store):
   # replace Babar by Celeste
   store.register_and_replace(Celeste, Babar)

In this example, we explicitly register classes one by one:

  • the Elephant class

  • the Celeste to replace Babar

If at some point we register a new appobject class in this module, it won’t be registered at all without modification to the registration_callback implementation. The first example will register it though, thanks to the call to the register_all method.

The REGISTRY_FACTORY class dictionary allows to specify which class should be instantiated for a given registry name. The class associated to None key will be the class used when there is no specific class for a name.

class logilab.common.registry.Registry(debugmode: bool)[source]#

The registry store a set of implementations associated to identifier:

  • to each identifier are associated a list of implementations

  • to select an implementation of a given identifier, you should use one of the select() or select_or_none() method

  • to select a list of implementations for a context, you should use the possible_objects() method

  • dictionary like access to an identifier will return the bare list of implementations for this identifier.

To be usable in a registry, the only requirement is to have a __select__ attribute.

At the end of the registration process, the __registered__() method is called on each registered object which have them, given the registry in which it’s registered as argument.

Registration methods:

register(obj: Any, oid: Optional[Any] = None, clear: bool = False) None[source]#

base method to add an object in the registry


remove object <obj> from this registry

Selection methods:

select(_Registry__oid, *args, **kwargs)[source]#

return the most specific object among those with the given oid according to the given context.

raise ObjectNotFound if there are no object with id oid in this registry

raise NoSelectableObject if no object can be selected

select_or_none(_Registry__oid, *args, **kwargs)[source]#

return the most specific object among those with the given oid according to the given context, or None if no object applies.

possible_objects(*args, **kwargs)[source]#

return an iterator on possible objects in this registry for the given context

object_by_id(oid, *args, **kwargs)[source]#

return object with the oid identifier. Only one object is expected to be found.

raise ObjectNotFound if there are no object with id oid in this registry

raise AssertionError if there is more than one object there


class logilab.common.registry.Predicate[source]#

base class for selector classes providing implementation for operators &, | and ~

This class is only here to give access to binary operators, the selector logic itself should be implemented in the __call__() method. Notice it should usually accept any arbitrary arguments (the context), though that may vary depending on your usage of the registry.

a selector is called to help choosing the correct object for a particular context by returning a score (int) telling how well the implementation given as first argument fit to the given context.

0 score means that the class doesn’t apply.

logilab.common.registry.objectify_predicate(selector_func: Callable) Any[source]#

Most of the time, a simple score function is enough to build a selector. The objectify_predicate() decorator turn it into a proper selector class:

def one(cls, req, rset=None, **kwargs):
    return 1

class MyView(View):
    __select__ = View.__select__ & one()
class logilab.common.registry.yes(score: float = 0.5)[source]#

Return the score given as parameter, with a default score of 0.5 so any other selector take precedence.

Usually used for objects which can be selected whatever the context, or also sometimes to add arbitrary points to a score.

Take care, yes(0) could be named ‘no’…

class logilab.common.registry.AndPredicate(*selectors: Any)[source]#

and-chained selectors

class logilab.common.registry.OrPredicate(*selectors: Any)[source]#

or-chained selectors

class logilab.common.registry.NotPredicate(selector)[source]#

negation selector


class logilab.common.registry.traced_selection(traced='all')[source]#

Typical usage is :

>>> from logilab.common.registry import traced_selection
>>> with traced_selection():
...     # some code in which you want to debug selectors
...     # for all objects

This will yield lines like this in the logs:

selector one_line_rset returned 0 for <class 'elephant.Babar'>

You can also give to traced_selection the identifiers of objects on which you want to debug selection (‘oid1’ and ‘oid2’ in the example above).

>>> with traced_selection( ('regid1', 'regid2') ):
...     # some code in which you want to debug selectors
...     # for objects with __regid__ 'regid1' and 'regid2'

A potentially useful point to set up such a tracing function is the method body.


class logilab.common.registry.RegistryException[source]#

Base class for registry exception.

class logilab.common.registry.RegistryNotFound[source]#

Raised when an unknown registry is requested.

This is usually a programming/typo error.

class logilab.common.registry.ObjectNotFound[source]#

Raised when an unregistered object is requested.

This may be a programming/typo or a misconfiguration error.

class logilab.common.registry.NoSelectableObject(args, kwargs, objects)[source]#

Raised when no object is selectable for a given context.