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
= {'etypes': <class 'cubicweb.cwvreg.ETypeRegistry'>, 'ctxcomponents': <class 'cubicweb.cwvreg.CtxComponentsRegistry'>, 'views': <class 'cubicweb.cwvreg.ViewsRegistry'>, None: <class 'cubicweb.cwvreg.CWRegistry'>, 'uicfg': <class 'cubicweb.cwvreg.InstancesRegistry'>, 'actions': <class 'cubicweb.cwvreg.ActionsRegistry'>}¶
-
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_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
-
rqlhelper
¶
-
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)
-
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
(*args, **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 directlyobjectify_predicate()
You’ll eventually find one concrete predicate: yes
-
class
logilab.common.registry.
RegistryStore
(debugmode=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_objects()
method, given a list of directories to inspect for python modules.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, 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, 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, registryname=None, oid=None, clear=False)[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)[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()
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:
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)[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=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.