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: Dict[Union[None, str], type] = {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
- property_info(key)[source]#
return dictionary containing description associated to the given property key (including type, defaut value, help and a site wide boolean)
- 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_property(key, type, help, default=None, vocabulary=None, sitewide=False)[source]#
register a given property
- property rqlhelper#
- 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.
- typed_value(key, value)[source]#
value is a unicode string, return it correctly typed. Let potential type error propagates.
- 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)
- property 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 registryraise
NoSelectableObject
if no object can be selected
- class cubicweb.cwvreg.InstancesRegistry(vreg)[source]#
Bases:
cubicweb.cwvreg.CWRegistry
- Parameters
vreg â the
CWRegistryStore
managing this registry.
- 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.
- class cubicweb.cwvreg.ViewsRegistry(vreg)[source]#
Bases:
cubicweb.cwvreg.CWRegistry
- Parameters
vreg â the
CWRegistryStore
managing this registry.
- class cubicweb.cwvreg.ActionsRegistry(vreg)[source]#
Bases:
cubicweb.cwvreg.CWRegistry
- Parameters
vreg â the
CWRegistryStore
managing this registry.
- class cubicweb.cwvreg.CtxComponentsRegistry(vreg)[source]#
Bases:
cubicweb.cwvreg.CWRegistry
- Parameters
vreg â the
CWRegistryStore
managing this registry.
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:
Predicate
, the abstract base predicate classAndPredicate
,OrPredicate
,NotPredicate
, which you shouldnât have to use directly. Youâll use &, | and â~â operators between predicates directly
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.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.
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()
orselect_or_none()
methodto select a list of implementations for a context, you should use the
possible_objects()
methoddictionary 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
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 registryraise
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 registryraise
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ââŠ
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.RegistryNotFound[source]#
Raised when an unknown registry is requested.
This is usually a programming/typo error.