--- a/vregistry.py Mon Aug 03 14:14:07 2009 +0200
+++ b/vregistry.py Mon Aug 03 15:16:47 2009 +0200
@@ -5,13 +5,13 @@
according to a context
* to interact with the vregistry, objects should inherit from the
- VObject abstract class
+ AppObject abstract class
* the selection procedure has been generalized by delegating to a
- selector, which is responsible to score the vobject according to the
+ selector, which is responsible to score the appobject according to the
current state (req, rset, row, col). At the end of the selection, if
- a vobject class has been found, an instance of this class is
- returned. The selector is instantiated at vobject registration
+ a appobject class has been found, an instance of this class is
+ returned. The selector is instantiated at appobject registration
:organization: Logilab
@@ -22,17 +22,18 @@
__docformat__ = "restructuredtext en"
import sys
-import types
from os import listdir, stat
from os.path import dirname, join, realpath, split, isdir, exists
from logging import getLogger
from warnings import warn
-from logilab.common.deprecation import deprecated
+from logilab.common.deprecation import deprecated, class_moved
+from logilab.common.logging_ext import set_log_methods
-from cubicweb import CW_SOFTWARE_ROOT, set_log_methods
+from cubicweb import CW_SOFTWARE_ROOT
from cubicweb import (RegistryNotFound, ObjectNotFound, NoSelectableObject,
RegistryOutOfDate)
+from cubicweb.appobject import AppObject
# XXX depending on cubicweb.web is ugly, we should deal with uicfg
# reset with a good old event / callback system
@@ -60,80 +61,6 @@
return _toload
-class VObject(object):
- """visual object, use to be handled somehow by the visual components
- registry.
-
- The following attributes should be set on concret vobject subclasses:
-
- :__registry__:
- name of the registry for this object (string like 'views',
- 'templates'...)
- :id:
- object's identifier in the registry (string like 'main',
- 'primary', 'folder_box')
- :__select__:
- class'selector
-
- Moreover, the `__abstract__` attribute may be set to True to indicate
- that a vobject is abstract and should not be registered
- """
- # necessary attributes to interact with the registry
- id = None
- __registry__ = None
- __select__ = None
-
- @classmethod
- def registered(cls, registry):
- """called by the registry when the vobject has been registered.
-
- It must return the object that will be actually registered (this
- may be the right hook to create an instance for example). By
- default the vobject is returned without any transformation.
- """
- cls.build___select__()
- return cls
-
- @classmethod
- def selected(cls, *args, **kwargs):
- """called by the registry when the vobject has been selected.
-
- It must return the object that will be actually returned by the
- .select method (this may be the right hook to create an
- instance for example). By default the selected object is
- returned without any transformation.
- """
- return cls
-
- @classmethod
- def classid(cls):
- """returns a unique identifier for the vobject"""
- return '%s.%s' % (cls.__module__, cls.__name__)
-
- # XXX bw compat code
- @classmethod
- def build___select__(cls):
- for klass in cls.mro():
- if klass.__name__ == 'AppObject':
- continue # the bw compat __selector__ is there
- klassdict = klass.__dict__
- if ('__select__' in klassdict and '__selectors__' in klassdict
- and '__selgenerated__' not in klassdict):
- raise TypeError("__select__ and __selectors__ can't be used together on class %s" % cls)
- if '__selectors__' in klassdict and '__selgenerated__' not in klassdict:
- cls.__selgenerated__ = True
- # case where __selectors__ is defined locally (but __select__
- # is in a parent class)
- selectors = klassdict['__selectors__']
- if len(selectors) == 1:
- # micro optimization: don't bother with AndSelector if there's
- # only one selector
- select = _instantiate_selector(selectors[0])
- else:
- select = AndSelector(*selectors)
- cls.__select__ = select
-
-
class Registry(dict):
def __init__(self, config):
@@ -155,16 +82,16 @@
oid = oid or obj.id
assert oid
if clear:
- vobjects = self[oid] = []
+ appobjects = self[oid] = []
else:
- vobjects = self.setdefault(oid, [])
+ appobjects = self.setdefault(oid, [])
# registered() is technically a classmethod but is not declared
# as such because we need to compose registered in some cases
- vobject = obj.registered.im_func(obj, self)
- assert not vobject in vobjects, \
- 'object %s is already registered' % vobject
- assert callable(vobject.__select__), vobject
- vobjects.append(vobject)
+ appobject = obj.registered.im_func(obj, self)
+ assert not appobject in appobjects, \
+ 'object %s is already registered' % appobject
+ assert callable(appobject.__select__), appobject
+ appobjects.append(appobject)
def register_and_replace(self, obj, replaced):
# XXXFIXME this is a duplication of unregister()
@@ -238,13 +165,13 @@
"""return an iterator on possible objects in this registry for the given
context
"""
- for vobjects in self.itervalues():
+ for appobjects in self.itervalues():
try:
- yield self.select_best(vobjects, *args, **kwargs)
+ yield self.select_best(appobjects, *args, **kwargs)
except NoSelectableObject:
continue
- def select_best(self, vobjects, *args, **kwargs):
+ def select_best(self, appobjects, *args, **kwargs):
"""return an instance of the most specific object according
to parameters
@@ -254,16 +181,16 @@
warn('only the request param can not be named when calling select',
DeprecationWarning, stacklevel=3)
score, winners = 0, []
- for vobject in vobjects:
- vobjectscore = vobject.__select__(vobject, *args, **kwargs)
- if vobjectscore > score:
- score, winners = vobjectscore, [vobject]
- elif vobjectscore > 0 and vobjectscore == score:
- winners.append(vobject)
+ for appobject in appobjects:
+ appobjectscore = appobject.__select__(appobject, *args, **kwargs)
+ if appobjectscore > score:
+ score, winners = appobjectscore, [appobject]
+ elif appobjectscore > 0 and appobjectscore == score:
+ winners.append(appobject)
if not winners:
raise NoSelectableObject('args: %s\nkwargs: %s %s'
% (args, kwargs.keys(),
- [repr(v) for v in vobjects]))
+ [repr(v) for v in appobjects]))
if len(winners) > 1:
if self.config.mode == 'installed':
self.error('select ambiguity, args: %s\nkwargs: %s %s',
@@ -272,7 +199,7 @@
raise Exception('select ambiguity, args: %s\nkwargs: %s %s'
% (args, kwargs.keys(),
[repr(v) for v in winners]))
- # return the result of the .selected method of the vobject
+ # return the result of the .selected method of the appobject
return winners[0].selected(*args, **kwargs)
@@ -379,7 +306,7 @@
vname = obj.__name__
except AttributeError:
vname = obj.__class__.__name__
- self.debug('registered vobject %s in registry %s with id %s',
+ self.debug('registered appobject %s in registry %s with id %s',
vname, registryname, oid)
self._loadedmods[obj.__module__]['%s.%s' % (obj.__module__, oid)] = obj
@@ -473,7 +400,7 @@
return
# skip non registerable object
try:
- if not issubclass(obj, VObject):
+ if not issubclass(obj, AppObject):
return
except TypeError:
return
@@ -487,20 +414,20 @@
def load_object(self, obj):
try:
- self.register_vobject_class(obj)
+ self.register_appobject_class(obj)
except Exception, ex:
if self.config.mode in ('test', 'dev'):
raise
- self.exception('vobject %s registration failed: %s', obj, ex)
+ self.exception('appobject %s registration failed: %s', obj, ex)
# old automatic registration XXX deprecated ###############################
- def register_vobject_class(self, cls):
- """handle vobject class registration
+ def register_appobject_class(self, cls):
+ """handle appobject class registration
- vobject class with __abstract__ == True in their local dictionnary or
+ appobject class with __abstract__ == True in their local dictionnary or
with a name starting starting by an underscore are not registered.
- Also a vobject class needs to have __registry__ and id attributes set
+ Also a appobject class needs to have __registry__ and id attributes set
to a non empty string to be registered.
"""
if (cls.__dict__.get('__abstract__') or cls.__name__[0] == '_'
@@ -512,170 +439,19 @@
self.register(cls)
# init logging
-set_log_methods(VObject, getLogger('cubicweb.appobject'))
set_log_methods(VRegistry, getLogger('cubicweb.vreg'))
set_log_methods(Registry, getLogger('cubicweb.registry'))
-# selector base classes and operations ########################################
-
-class Selector(object):
- """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
-
-
- a selector is called to help choosing the correct object for a
- particular context by returning a score (`int`) telling how well
- the class given as first argument apply to the given context.
-
- 0 score means that the class doesn't apply.
- """
-
- @property
- def func_name(self):
- # backward compatibility
- return self.__class__.__name__
-
- def search_selector(self, selector):
- """search for the given selector or selector instance in the selectors
- tree. Return it of None if not found
- """
- if self is selector:
- return self
- if isinstance(selector, type) and isinstance(self, selector):
- return self
- return None
-
- def __str__(self):
- return self.__class__.__name__
-
- def __and__(self, other):
- return AndSelector(self, other)
- def __rand__(self, other):
- return AndSelector(other, self)
-
- def __or__(self, other):
- return OrSelector(self, other)
- def __ror__(self, other):
- return OrSelector(other, self)
-
- def __invert__(self):
- return NotSelector(self)
-
- # XXX (function | function) or (function & function) not managed yet
-
- def __call__(self, cls, *args, **kwargs):
- return NotImplementedError("selector %s must implement its logic "
- "in its __call__ method" % self.__class__)
-
-class MultiSelector(Selector):
- """base class for compound selector classes"""
-
- def __init__(self, *selectors):
- self.selectors = self.merge_selectors(selectors)
-
- def __str__(self):
- return '%s(%s)' % (self.__class__.__name__,
- ','.join(str(s) for s in self.selectors))
-
- @classmethod
- def merge_selectors(cls, selectors):
- """deal with selector instanciation when necessary and merge
- multi-selectors if possible:
-
- AndSelector(AndSelector(sel1, sel2), AndSelector(sel3, sel4))
- ==> AndSelector(sel1, sel2, sel3, sel4)
- """
- merged_selectors = []
- for selector in selectors:
- try:
- selector = _instantiate_selector(selector)
- except:
- pass
- #assert isinstance(selector, Selector), selector
- if isinstance(selector, cls):
- merged_selectors += selector.selectors
- else:
- merged_selectors.append(selector)
- return merged_selectors
-
- def search_selector(self, selector):
- """search for the given selector or selector instance in the selectors
- tree. Return it of None if not found
- """
- for childselector in self.selectors:
- if childselector is selector:
- return childselector
- found = childselector.search_selector(selector)
- if found is not None:
- return found
- return None
-
-
-def objectify_selector(selector_func):
- """convenience decorator for simple selectors where a class definition
- would be overkill::
-
- @objectify_selector
- def yes(cls, *args, **kwargs):
- return 1
-
- """
- return type(selector_func.__name__, (Selector,),
- {'__call__': lambda self, *args, **kwargs: selector_func(*args, **kwargs)})
-
-def _instantiate_selector(selector):
- """ensures `selector` is a `Selector` instance
-
- NOTE: This should only be used locally in build___select__()
- XXX: then, why not do it ??
- """
- if isinstance(selector, types.FunctionType):
- return objectify_selector(selector)()
- if isinstance(selector, type) and issubclass(selector, Selector):
- return selector()
- return selector
-
-
-class AndSelector(MultiSelector):
- """and-chained selectors (formerly known as chainall)"""
- def __call__(self, cls, *args, **kwargs):
- score = 0
- for selector in self.selectors:
- partscore = selector(cls, *args, **kwargs)
- if not partscore:
- return 0
- score += partscore
- return score
-
-
-class OrSelector(MultiSelector):
- """or-chained selectors (formerly known as chainfirst)"""
- def __call__(self, cls, *args, **kwargs):
- for selector in self.selectors:
- partscore = selector(cls, *args, **kwargs)
- if partscore:
- return partscore
- return 0
-
-class NotSelector(Selector):
- """negation selector"""
- def __init__(self, selector):
- self.selector = selector
-
- def __call__(self, cls, *args, **kwargs):
- score = self.selector(cls, *args, **kwargs)
- return int(not score)
-
- def __str__(self):
- return 'NOT(%s)' % super(NotSelector, self).__str__()
-
-
# XXX bw compat functions #####################################################
+from cubicweb.appobject import objectify_selector, AndSelector, OrSelector, Selector
+
+objectify_selector = deprecated('objectify_selector has been moved to appobject module')(objectify_selector)
+
+Selector = class_moved(Selector)
+
+@deprecated('use & operator (binary and)')
def chainall(*selectors, **kwargs):
"""return a selector chaining given selectors. If one of
the selectors fail, selection will fail, else the returned score
@@ -688,6 +464,7 @@
selector.__name__ = kwargs['name']
return selector
+@deprecated('use | operator (binary or)')
def chainfirst(*selectors, **kwargs):
"""return a selector chaining given selectors. If all
the selectors fail, selection will fail, else the returned score