cubicweb.cwvreg

Cubicweb registries

class cubicweb.cwvreg.CWRegistryStore(config, initlog=True)[source]

Bases: logilab.common.registry.RegistryStore

Central registry for the cubicweb instance, extending the generic RegistryStore with some cubicweb specific stuff.

This is one of the central object in cubicweb instance, coupling dynamically loaded objects with the schema and the configuration objects.

It specializes the RegistryStore by adding some convenience methods to access to stored objects. Currently we have the following registries of objects known by the web instance (library may use some others additional registries):

  • ‘etypes’, entity type classes
  • ‘views’, views and templates (e.g. layout views)
  • ‘components’, non contextual components, like magic search, url evaluators
  • ‘ctxcomponents’, contextual components like boxes and dynamic section
  • ‘actions’, contextual actions, eg links to display in predefined places in the ui
  • ‘forms’, describing logic of HTML form
  • ‘formrenderers’, rendering forms to html
  • ‘controllers’, primary objects to handle request publishing, directly plugged into the application
REGISTRY_FACTORY = {None: <class 'cubicweb.cwvreg.CWRegistry'>, 'etypes': <class 'cubicweb.cwvreg.ETypeRegistry'>, 'views': <class 'cubicweb.cwvreg.ViewsRegistry'>, 'actions': <class 'cubicweb.cwvreg.ActionsRegistry'>, 'ctxcomponents': <class 'cubicweb.cwvreg.CtxComponentsRegistry'>, 'uicfg': <class 'cubicweb.cwvreg.InstancesRegistry'>}
init_properties(propvalues)[source]

init the property values registry using the given set of couple (key, value)

initialization_completed()[source]

cw specific code once vreg initialization is completed:

  • remove objects requiring a missing appobject, unless config.cleanup_unused_appobjects is false
  • init rtags
is_reload_needed(modnames)[source]

overriden to handle modules names instead of directories

items() → a set-like object providing a view on D's items[source]
iteritems()[source]
itervalues()[source]
load_file(filepath, modname)[source]

load registrable objects (if any) from a python file

parse(req, rql, args=None)[source]
property_info(key)[source]

return dictionary containing description associated to the given property key (including type, defaut value, help and a site wide boolean)

property_value(key)[source]
register(obj, *args, **kwargs)[source]

register obj application object into registryname or obj.__registry__ 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.

register_all(objects, modname, butclasses=())[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)[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_objects(path)[source]

overriden to give cubicweb’s extrapath (eg cubes package’s __path__)

register_property(key, type, help, default=None, vocabulary=None, sitewide=False)[source]

register a given property

reload(modnames, force_reload=True)[source]

modification detected, reset and reload the vreg

reload_if_needed()[source]
reset()[source]

clear all registries managed by this store

rqlhelper
set_schema(schema)[source]

set instance’schema and load application objects

setdefault(regid)[source]

Insert key with a value of default if key is not in the dictionary.

Return the value for key if key is in the dictionary, else default.

solutions(req, rqlst, args)[source]
typed_value(key, value)[source]

value is a unicode string, return it correctly typed. Let potential type error propagates.

update_schema(schema)[source]

update .schema attribute on registered objects, necessary for some tests

user_property_keys(withsitewide=False)[source]
values() → an object providing a view on D's values[source]
class cubicweb.cwvreg.CWRegistry(vreg)[source]

Bases: logilab.common.registry.Registry

Parameters:vreg – the CWRegistryStore managing this registry.
poss_visible_objects(*args, **kwargs)[source]

return an ordered list of possible app objects in a given registry, supposing they support the ‘visible’ and ‘order’ properties (as most visualizable objects)

schema

The cubicweb.schema.CubicWebSchema

select(_Registry__oid, *args, **kwargs)

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

class cubicweb.cwvreg.InstancesRegistry(vreg)[source]

Bases: cubicweb.cwvreg.CWRegistry

Parameters:vreg – the CWRegistryStore managing this registry.
selected(winner, args, kwargs)[source]

overriden to avoid the default ‘instanciation’ behaviour, ie winner(*args, **kwargs)

class cubicweb.cwvreg.ETypeRegistry(vreg)[source]

Bases: cubicweb.cwvreg.CWRegistry

Parameters:vreg – the CWRegistryStore managing this registry.
etype_class(**kwargs)

return an entity class for the given entity type.

Try to find out a specific class for this kind of entity or default to a dump of the nearest parent class (in yams inheritance) registered.

Fall back to ‘Any’ if not yams parent class found.

fetch_attrs(targettypes)[source]

return intersection of fetch_attrs of each entity type in targettypes

initialization_completed()[source]

on registration completed, clear etype_class internal cache

register(obj, **kwargs)[source]

base method to add an object in the registry

class cubicweb.cwvreg.ViewsRegistry(vreg)[source]

Bases: cubicweb.cwvreg.CWRegistry

Parameters:vreg – the CWRegistryStore managing this registry.
main_template(req, oid='main-template', rset=None, **kwargs)[source]

display query by calling the given template (default to main), and returning the output as a string instead of requiring the [w]rite method as argument

possible_views(req, rset=None, **kwargs)[source]

return an iterator on possible views for this result set

views returned are classes, not instances

class cubicweb.cwvreg.ActionsRegistry(vreg)[source]

Bases: cubicweb.cwvreg.CWRegistry

Parameters:vreg – the CWRegistryStore managing this registry.
poss_visible_objects(*args, **kwargs)[source]

return an ordered list of possible actions

class cubicweb.cwvreg.CtxComponentsRegistry(vreg)[source]

Bases: cubicweb.cwvreg.CWRegistry

Parameters:vreg – the CWRegistryStore managing this registry.
poss_visible_objects(*args, **kwargs)[source]

return an ordered list of possible components

class cubicweb.cwvreg.BwCompatCWRegistry(vreg, oldreg, redirecttoreg)[source]

Bases: object

logilab.common.registry

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.

Note

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:

__registries__
list of registry names (string like ‘views’, ‘templates’…) into which the object should be registered
__regid__
object identifier in the registry (string like ‘main’, ‘primary’, ‘folder_box’)
__select__
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).

Note

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[T_co], modname: str, butclasses: Sequence[T_co] = ()) → 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.

Note

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.

Examples:

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:
       store.register(BabarClass)

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):
   store.register(Elephant)
   # 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

unregister(obj)[source]

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

Predicates

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:

@objectify_predicate
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)[source]

and-chained selectors

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

or-chained selectors

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

negation selector

Debugging

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 logilab.common.registry.Registry.select method body.

Exceptions

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.