# HG changeset patch # User Adrien Di Mascio # Date 1249391298 -7200 # Node ID f84ba1a66abb7ce910eaeb8acd81b26f9c52c16b # Parent ff6114c2c416b7e169b69ef17f1ec2bcef448f5a# Parent 4747145ff69cf6e3c0842221e6221c2cd0ac851c merge diff -r ff6114c2c416 -r f84ba1a66abb appobject.py --- a/appobject.py Tue Aug 04 15:06:09 2009 +0200 +++ b/appobject.py Tue Aug 04 15:08:18 2009 +0200 @@ -1,4 +1,6 @@ -"""Base class for dynamically loaded objects manipulated in the web interface +"""Base class for dynamically loaded objects accessible through the vregistry. + +You'll also find some convenience classes to build selectors. :organization: Logilab :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. @@ -7,20 +9,23 @@ """ __docformat__ = "restructuredtext en" +import types +from logging import getLogger from datetime import datetime, timedelta, time from logilab.common.decorators import classproperty from logilab.common.deprecation import deprecated +from logilab.common.logging_ext import set_log_methods from rql.nodes import VariableRef, SubQuery from rql.stmts import Union, Select from cubicweb import Unauthorized, NoSelectableObject -from cubicweb.vregistry import VObject, AndSelector -from cubicweb.selectors import yes from cubicweb.utils import UStringIO, ustrftime, strptime, todate, todatetime ONESECOND = timedelta(0, 1, 0) +CACHE_REGISTRY = {} + class Cache(dict): def __init__(self): @@ -29,14 +34,200 @@ self.cache_creation_date = _now self.latest_cache_lookup = _now -CACHE_REGISTRY = {} + +# selector base classes and operations ######################################## + +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 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: -class AppRsetObject(VObject): - """This is the base class for CubicWeb application objects - which are selected according to a request and result set. + 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 + + +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 + - Classes are kept in the vregistry and instantiation is done at selection - time. +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__() + + +class yes(Selector): + """return arbitrary score + + default score of 0.5 so any other selector take precedence + """ + def __init__(self, score=0.5): + self.score = score + + def __call__(self, *args, **kwargs): + return self.score + + +# the base class for all appobjects ############################################ + +class AppObject(object): + """This is the base class for CubicWeb application objects which are + selected according to a context (usually at least a request and a result + set). + + Concrete application objects classes are designed to be loaded by the + vregistry and should be accessed through it, not by direct instantiation. + + The following attributes should be set on concret appobject classes: + :__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 appobject is abstract and should not be registered. At registration time, the following attributes are set on the class: :vreg: @@ -46,20 +237,64 @@ :config: the instance's configuration - At instantiation time, the following attributes are set on the instance: + At selection time, the following attributes are set on the instance: :req: current request :rset: - result set on which the object is applied + context result set or None + :row: + if a result set is set and the context is about a particular cell in the + result set, and not the result set as a whole, specify the row number we + are interested in, else None + :col: + if a result set is set and the context is about a particular cell in the + result set, and not the result set as a whole, specify the col number we + are interested in, else None """ + __registry__ = None + id = None __select__ = yes() @classmethod - def registered(cls, vreg): - super(AppRsetObject, cls).registered(vreg) - cls.vreg = vreg - cls.schema = vreg.schema - cls.config = vreg.config + def classid(cls): + """returns a unique identifier for the appobject""" + 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 + + @classmethod + def registered(cls, registry): + """called by the registry when the appobject 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 + appobject is returned without any transformation. + """ + cls.build___select__() + cls.vreg = registry.vreg + cls.schema = registry.schema + cls.config = registry.config cls.register_properties() return cls @@ -67,15 +302,6 @@ def vreg_initialization_completed(cls): pass - @classmethod - def selected(cls, *args, **kwargs): - """by default web app objects are usually instantiated on - selection according to a request, a result set, and optional - row and col - """ - assert len(args) <= 2 - return cls(*args, **kwargs) - # Eproperties definition: # key: id of the property (the actual CWProperty key is build using # .. @@ -111,7 +337,7 @@ return selector def __init__(self, req=None, rset=None, row=None, col=None, **extra): - super(AppRsetObject, self).__init__() + super(AppObject, self).__init__() self.req = req self.rset = rset self.row = row @@ -151,8 +377,8 @@ # try to get page boundaries from the navigation component # XXX we should probably not have a ref to this component here (eg in # cubicweb.common) - nav = self.vreg.select_object('components', 'navigation', self.req, - rset=self.rset) + nav = self.vreg['components'].select_object('navigation', self.req, + rset=self.rset) if nav: start, stop = nav.page_boundaries() rql = self._limit_offset_rql(stop - start, start) @@ -188,10 +414,11 @@ rqlst.parent = None return rql - def view(self, __vid, rset=None, __fallback_vid=None, **kwargs): + def view(self, __vid, rset=None, __fallback_oid=None, __registry='views', + **kwargs): """shortcut to self.vreg.view method avoiding to pass self.req""" - return self.vreg.render(__vid, self.req, __fallback_vid, rset=rset, - **kwargs) + return self.vreg[__registry].render(__vid, self.req, __fallback_oid, + rset=rset, **kwargs) def initialize_varmaker(self): varmaker = self.req.get_page_data('rql_varmaker') @@ -341,22 +568,4 @@ if first in ('insert', 'set', 'delete'): raise Unauthorized(self.req._('only select queries are authorized')) - -class AppObject(AppRsetObject): - """base class for application objects which are not selected - according to a result set, only by their identifier. - - Those objects may not have req, rset and cursor set. - """ - - @classmethod - def selected(cls, *args, **kwargs): - """by default web app objects are usually instantiated on - selection - """ - return cls(*args, **kwargs) - - def __init__(self, req=None, rset=None, **kwargs): - self.req = req - self.rset = rset - self.__dict__.update(kwargs) +set_log_methods(AppObject, getLogger('cubicweb.appobject')) diff -r ff6114c2c416 -r f84ba1a66abb common/test/unittest_migration.py --- a/common/test/unittest_migration.py Tue Aug 04 15:06:09 2009 +0200 +++ b/common/test/unittest_migration.py Tue Aug 04 15:08:18 2009 +0200 @@ -37,8 +37,8 @@ self.config = MigrTestConfig('data') from yams.schema import Schema self.config.load_schema = lambda expand_cubes=False: Schema('test') - self.config.__class__.cubicweb_vobject_path = frozenset() - self.config.__class__.cube_vobject_path = frozenset() + self.config.__class__.cubicweb_appobject_path = frozenset() + self.config.__class__.cube_appobject_path = frozenset() def test_filter_scripts_base(self): self.assertListEquals(filter_scripts(self.config, SMIGRDIR, (2,3,0), (2,4,0)), diff -r ff6114c2c416 -r f84ba1a66abb cwconfig.py --- a/cwconfig.py Tue Aug 04 15:06:09 2009 +0200 +++ b/cwconfig.py Tue Aug 04 15:08:18 2009 +0200 @@ -142,7 +142,7 @@ name = None # log messages format (see logging module documentation for available keys) log_format = '%(asctime)s - (%(name)s) %(levelname)s: %(message)s' - # nor remove vobjects based on unused interface + # nor remove appobjects based on unused interface cleanup_interface_sobjects = True if os.environ.get('APYCOT_ROOT'): @@ -169,14 +169,7 @@ {'type' : 'string', 'default': '', 'help': 'Pyro name server\'s host. If not set, will be detected by a \ -broadcast query', - 'group': 'pyro-name-server', 'inputlevel': 1, - }), - ('pyro-ns-port', - {'type' : 'int', - 'default': None, - 'help': 'Pyro name server\'s listening port. If not set, default \ -port will be used.', +broadcast query. It may contains port information using : notation.', 'group': 'pyro-name-server', 'inputlevel': 1, }), ('pyro-ns-group', @@ -419,8 +412,8 @@ except Exception, ex: cls.warning("can't init cube %s: %s", cube, ex) - cubicweb_vobject_path = set(['entities']) - cube_vobject_path = set(['entities']) + cubicweb_appobject_path = set(['entities']) + cube_appobject_path = set(['entities']) @classmethod def build_vregistry_path(cls, templpath, evobjpath=None, tvobjpath=None): @@ -430,13 +423,13 @@ :param evobjpath: optional list of sub-directories (or files without the .py ext) of the cubicweb library that should be tested and added to the output list - if they exists. If not give, default to `cubicweb_vobject_path` class + if they exists. If not give, default to `cubicweb_appobject_path` class attribute. :param tvobjpath: optional list of sub-directories (or files without the .py ext) of directories given in `templpath` that should be tested and added to the output list if they exists. If not give, default to - `cube_vobject_path` class attribute. + `cube_appobject_path` class attribute. """ vregpath = cls.build_vregistry_cubicweb_path(evobjpath) vregpath += cls.build_vregistry_cube_path(templpath, tvobjpath) @@ -446,7 +439,7 @@ def build_vregistry_cubicweb_path(cls, evobjpath=None): vregpath = [] if evobjpath is None: - evobjpath = cls.cubicweb_vobject_path + evobjpath = cls.cubicweb_appobject_path for subdir in evobjpath: path = join(CW_SOFTWARE_ROOT, subdir) if exists(path): @@ -457,7 +450,7 @@ def build_vregistry_cube_path(cls, templpath, tvobjpath=None): vregpath = [] if tvobjpath is None: - tvobjpath = cls.cube_vobject_path + tvobjpath = cls.cube_appobject_path for directory in templpath: for subdir in tvobjpath: path = join(directory, subdir) diff -r ff6114c2c416 -r f84ba1a66abb cwvreg.py --- a/cwvreg.py Tue Aug 04 15:06:09 2009 +0200 +++ b/cwvreg.py Tue Aug 04 15:08:18 2009 +0200 @@ -8,14 +8,16 @@ __docformat__ = "restructuredtext en" _ = unicode -from logilab.common.decorators import cached, clear_cache +from logilab.common.decorators import cached, clear_cache, monkeypatch from logilab.common.deprecation import deprecated from rql import RQLHelper from cubicweb import (ETYPE_NAME_MAP, Binary, UnknownProperty, UnknownEid, + ObjectNotFound, NoSelectableObject, RegistryNotFound, RegistryOutOfDate) -from cubicweb.vregistry import VRegistry, ObjectNotFound, NoSelectableObject +from cubicweb.utils import dump_class +from cubicweb.vregistry import VRegistry, Registry from cubicweb.rtags import RTAGS @@ -33,14 +35,171 @@ if impl: return sorted(impl.expected_ifaces) except AttributeError: - pass # old-style vobject classes with no accepts_interfaces + pass # old-style appobject classes with no accepts_interfaces except: print 'bad selector %s on %s' % (obj.__select__, obj) raise return () -class CubicWebRegistry(VRegistry): +class CWRegistry(Registry): + def __init__(self, vreg): + super(CWRegistry, self).__init__(vreg.config) + self.vreg = vreg + self.schema = vreg.schema + + def initialization_completed(self): + # call vreg_initialization_completed on appobjects and print + # registry content + for appobjects in self.itervalues(): + for appobject in appobjects: + appobject.vreg_initialization_completed() + + def render(self, __oid, req, __fallback_oid=None, rset=None, **kwargs): + """select object, or fallback object if specified and the first one + isn't selectable, then render it + """ + try: + obj = self.select(__oid, req, rset=rset, **kwargs) + except NoSelectableObject: + if __fallback_oid is None: + raise + obj = self.select(__fallback_oid, req, **kwargs) + return obj.render(**kwargs) + + def select_vobject(self, oid, *args, **kwargs): + selected = self.select_object(oid, *args, **kwargs) + if selected and selected.propval('visible'): + return selected + return None + + def possible_vobjects(self, *args, **kwargs): + """return an ordered list of possible app objects in a given registry, + supposing they support the 'visible' and 'order' properties (as most + visualizable objects) + """ + return sorted([x for x in self.possible_objects(*args, **kwargs) + if x.propval('visible')], + key=lambda x: x.propval('order')) + + +VRegistry.REGISTRY_FACTORY[None] = CWRegistry + + +class ETypeRegistry(CWRegistry): + + def initialization_completed(self): + """on registration completed, clear etype_class internal cache + """ + super(ETypeRegistry, self).initialization_completed() + # clear etype cache if you don't want to run into deep weirdness + clear_cache(self, 'etype_class') + + def register(self, obj, **kwargs): + oid = kwargs.get('oid') or obj.id + if oid != 'Any' and not oid in self.schema: + self.error('don\'t register %s, %s type not defined in the ' + 'schema', obj, obj.id) + return + kwargs['clear'] = True + super(ETypeRegistry, self).register(obj, **kwargs) + + @cached + def etype_class(self, etype): + """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. + """ + etype = str(etype) + if etype == 'Any': + return self.select('Any', 'Any') + eschema = self.schema.eschema(etype) + baseschemas = [eschema] + eschema.ancestors() + # browse ancestors from most specific to most generic and try to find an + # associated custom entity class + for baseschema in baseschemas: + try: + btype = ETYPE_NAME_MAP[baseschema] + except KeyError: + btype = str(baseschema) + try: + objects = self[btype] + assert len(objects) == 1, objects + cls = objects[0] + break + except ObjectNotFound: + pass + else: + # no entity class for any of the ancestors, fallback to the default + # one + objects = self['Any'] + assert len(objects) == 1, objects + cls = objects[0] + if cls.id == etype: + cls.__initialize__() + return cls + cls = dump_class(cls, etype) + cls.id = etype + cls.__initialize__() + return cls + +VRegistry.REGISTRY_FACTORY['etypes'] = ETypeRegistry + + +class ViewsRegistry(CWRegistry): + + def main_template(self, req, oid='main-template', **kwargs): + """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 + """ + res = self.render(oid, req, **kwargs) + if isinstance(res, unicode): + return res.encode(req.encoding) + assert isinstance(res, str) + return res + + def possible_views(self, req, rset=None, **kwargs): + """return an iterator on possible views for this result set + + views returned are classes, not instances + """ + for vid, views in self.items(): + if vid[0] == '_': + continue + try: + view = self.select_best(views, req, rset=rset, **kwargs) + if view.linkable(): + yield view + except NoSelectableObject: + continue + except Exception: + self.exception('error while trying to select %s view for %s', + vid, rset) + +VRegistry.REGISTRY_FACTORY['views'] = ViewsRegistry + + +class ActionsRegistry(CWRegistry): + + def possible_actions(self, req, rset=None, **kwargs): + if rset is None: + actions = self.possible_vobjects(req, rset=rset, **kwargs) + else: + actions = rset.possible_actions(**kwargs) # cached implementation + result = {} + for action in actions: + result.setdefault(action.category, []).append(action) + return result + +VRegistry.REGISTRY_FACTORY['actions'] = ActionsRegistry + + + +class CubicWebVRegistry(VRegistry): """Central registry for the cubicweb instance, extending the generic VRegistry with some cubicweb specific stuff. @@ -66,28 +225,38 @@ if initlog: # first init log service config.init_log(debug=debug) - super(CubicWebRegistry, self).__init__(config) + super(CubicWebVRegistry, self).__init__(config) self.schema = None self.reset() self.initialized = False + def setdefault(self, regid): + try: + return self[regid] + except RegistryNotFound: + self[regid] = self.registry_class(regid)(self) + return self[regid] + def items(self): - return [item for item in self._registries.items() + return [item for item in super(CubicWebVRegistry, self).items() if not item[0] in ('propertydefs', 'propertyvalues')] + def iteritems(self): + return (item for item in super(CubicWebVRegistry, self).iteritems() + if not item[0] in ('propertydefs', 'propertyvalues')) def values(self): - return [value for key, value in self._registries.items() - if not key in ('propertydefs', 'propertyvalues')] + return [value for key, value in self.items()] + def itervalues(self): + return (value for key, value in self.items()) def reset(self): - self._registries = {} - self._lastmodifs = {} + super(CubicWebVRegistry, self).reset() self._needs_iface = {} # two special registries, propertydefs which care all the property # definitions, and propertyvals which contains values for those # properties - self._registries['propertydefs'] = {} - self._registries['propertyvalues'] = self.eprop_values = {} + self['propertydefs'] = {} + self['propertyvalues'] = self.eprop_values = {} for key, propdef in self.config.eproperty_definitions(): self.register_property(key, **propdef) @@ -108,9 +277,7 @@ tests """ self.schema = schema - for registry, regcontent in self._registries.items(): - if registry in ('propertydefs', 'propertyvalues'): - continue + for registry, regcontent in self.items(): for objects in regcontent.values(): for obj in objects: obj.schema = schema @@ -126,13 +293,7 @@ self._needs_iface[obj] = ifaces def register(self, obj, **kwargs): - if kwargs.get('registryname', obj.__registry__) == 'etypes': - if obj.id != 'Any' and not obj.id in self.schema: - self.error('don\'t register %s, %s type not defined in the ' - 'schema', obj, obj.id) - return - kwargs['clear'] = True - super(CubicWebRegistry, self).register(obj, **kwargs) + super(CubicWebVRegistry, self).register(obj, **kwargs) # XXX bw compat ifaces = use_interfaces(obj) if ifaces: @@ -153,166 +314,92 @@ for cubesdir in self.config.cubes_search_path(): if cubesdir != self.config.CUBES_DIR: extrapath[cubesdir] = 'cubes' - if super(CubicWebRegistry, self).register_objects(path, force_reload, + if super(CubicWebVRegistry, self).register_objects(path, force_reload, extrapath): self.initialization_completed() - # call vreg_initialization_completed on appobjects and print - # registry content - for registry, objects in self.items(): - self.debug('available in registry %s: %s', registry, - sorted(objects)) - for appobjects in objects.itervalues(): - for appobject in appobjects: - appobject.vreg_initialization_completed() # don't check rtags if we don't want to cleanup_interface_sobjects for rtag in RTAGS: rtag.init(self.schema, check=self.config.cleanup_interface_sobjects) def initialization_completed(self): - # clear etype cache if you don't want to run into deep weirdness - clear_cache(self, 'etype_class') + for regname, reg in self.items(): + self.debug('available in registry %s: %s', regname, sorted(reg)) + reg.initialization_completed() # we may want to keep interface dependent objects (e.g.for i18n # catalog generation) if self.config.cleanup_interface_sobjects: - # remove vobjects that don't support any available interface + # remove appobjects that don't support any available interface implemented_interfaces = set() if 'Any' in self.get('etypes', ()): for etype in self.schema.entities(): - cls = self.etype_class(etype) + cls = self['etypes'].etype_class(etype) for iface in cls.__implements__: implemented_interfaces.update(iface.__mro__) implemented_interfaces.update(cls.__mro__) for obj, ifaces in self._needs_iface.items(): ifaces = frozenset(isinstance(iface, basestring) and iface in self.schema - and self.etype_class(iface) + and self['etypes'].etype_class(iface) or iface for iface in ifaces) if not ('Any' in ifaces or ifaces & implemented_interfaces): - self.debug('kicking vobject %s (no implemented ' + self.debug('kicking appobject %s (no implemented ' 'interface among %s)', obj, ifaces) self.unregister(obj) # clear needs_iface so we don't try to remove some not-anymore-in # objects on automatic reloading self._needs_iface.clear() + def parse(self, session, rql, args=None): + rqlst = self.rqlhelper.parse(rql) + def type_from_eid(eid, session=session): + return session.describe(eid)[0] + try: + self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args) + except UnknownEid: + for select in rqlst.children: + select.solutions = [] + return rqlst + + @property @cached + def rqlhelper(self): + return RQLHelper(self.schema, + special_relations={'eid': 'uid', 'has_text': 'fti'}) + + + @deprecated('use vreg["etypes"].etype_class(etype)') def etype_class(self, etype): - """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 class registered for 'Any' - """ - etype = str(etype) - if etype == 'Any': - return self.select('etypes', 'Any', 'Any') - eschema = self.schema.eschema(etype) - baseschemas = [eschema] + eschema.ancestors() - # browse ancestors from most specific to most generic and - # try to find an associated custom entity class - for baseschema in baseschemas: - try: - btype = ETYPE_NAME_MAP[baseschema] - except KeyError: - btype = str(baseschema) - try: - cls = self.select('etypes', btype, etype) - break - except ObjectNotFound: - pass - else: - # no entity class for any of the ancestors, fallback to the default - # one - cls = self.select('etypes', 'Any', etype) - return cls - - def render(self, __oid, req, __fallback_oid=None, __registry='views', - rset=None, **kwargs): - """select object, or fallback object if specified and the first one - isn't selectable, then render it - """ - try: - obj = self.select(__registry, __oid, req, rset=rset, **kwargs) - except NoSelectableObject: - if __fallback_oid is None: - raise - obj = self.select(__registry, __fallback_oid, req, rset=rset, - **kwargs) - return obj.render(**kwargs) - - def main_template(self, req, oid='main-template', **context): - """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 - """ - res = self.render(oid, req, **context) - if isinstance(res, unicode): - return res.encode(req.encoding) - assert isinstance(res, str) - return res + return self["etypes"].etype_class(etype) - def select_vobject(self, registry, oid, *args, **kwargs): - selected = self.select_object(registry, oid, *args, **kwargs) - if selected and selected.propval('visible'): - return selected - return None + @deprecated('use vreg["views"].main_template(*args, **kwargs)') + def main_template(self, req, oid='main-template', **context): + return self["views"].main_template(req, oid, **context) + @deprecated('use vreg[registry].possible_vobjects(*args, **kwargs)') def possible_vobjects(self, registry, *args, **kwargs): - """return an ordered list of possible app objects in a given registry, - supposing they support the 'visible' and 'order' properties (as most - visualizable objects) - """ - return [x for x in sorted(self.possible_objects(registry, *args, **kwargs), - key=lambda x: x.propval('order')) - if x.propval('visible')] + return self[registry].possible_vobjects(*args, **kwargs) + @deprecated('use vreg["actions"].possible_actions(*args, **kwargs)') def possible_actions(self, req, rset=None, **kwargs): - if rset is None: - actions = self.possible_vobjects('actions', req, rset=rset, **kwargs) - else: - actions = rset.possible_actions(**kwargs) # cached implementation - result = {} - for action in actions: - result.setdefault(action.category, []).append(action) - return result - - def possible_views(self, req, rset=None, **kwargs): - """return an iterator on possible views for this result set + return self["actions"].possible_actions(req, rest=rset, **kwargs) - views returned are classes, not instances - """ - for vid, views in self.registry('views').items(): - if vid[0] == '_': - continue - try: - view = self.select_best(views, req, rset=rset, **kwargs) - if view.linkable(): - yield view - except NoSelectableObject: - continue - except Exception: - self.exception('error while trying to select %s view for %s', - vid, rset) - - @deprecated("use .select_object('boxes', ...)") + @deprecated("use vreg['boxes'].select_object(...)") def select_box(self, oid, *args, **kwargs): - """return the most specific view according to the result set""" - return self.select_object('boxes', oid, *args, **kwargs) + return self['boxes'].select_object(oid, *args, **kwargs) - @deprecated("use .select_object('components', ...)") + @deprecated("use vreg['components'].select_object(...)") def select_component(self, cid, *args, **kwargs): - """return the most specific component according to the result set""" - return self.select_object('components', cid, *args, **kwargs) + return self['components'].select_object(cid, *args, **kwargs) - @deprecated("use .select_object('actions', ...)") + @deprecated("use vreg['actions'].select_object(...)") def select_action(self, oid, *args, **kwargs): - """return the most specific view according to the result set""" - return self.select_object('actions', oid, *args, **kwargs) + return self['actions'].select_object(oid, *args, **kwargs) - @deprecated("use .select('views', ...)") + @deprecated("use vreg['views'].select(...)") def select_view(self, __vid, req, rset=None, **kwargs): - """return the most specific view according to the result set""" - return self.select('views', __vid, req, rset=rset, **kwargs) + return self['views'].select(__vid, req, rset=rset, **kwargs) # properties handling ##################################################### @@ -326,7 +413,7 @@ def register_property(self, key, type, help, default=None, vocabulary=None, sitewide=False): """register a given property""" - properties = self._registries['propertydefs'] + properties = self['propertydefs'] assert type in YAMS_TO_PY properties[key] = {'type': type, 'vocabulary': vocabulary, 'default': default, 'help': help, @@ -338,7 +425,7 @@ boolean) """ try: - return self._registries['propertydefs'][key] + return self['propertydefs'][key] except KeyError: if key.startswith('system.version.'): soft = key.split('.')[-1] @@ -349,9 +436,9 @@ def property_value(self, key): try: - return self._registries['propertyvalues'][key] + return self['propertyvalues'][key] except KeyError: - return self._registries['propertydefs'][key]['default'] + return self['propertydefs'][key]['default'] def typed_value(self, key, value): """value is an unicode string, return it correctly typed. Let potential @@ -374,7 +461,7 @@ """init the property values registry using the given set of couple (key, value) """ self.initialized = True - values = self._registries['propertyvalues'] + values = self['propertyvalues'] for key, val in propvalues: try: values[key] = self.typed_value(key, val) @@ -385,61 +472,6 @@ self.warning('%s (you should probably delete that property ' 'from the database)', ex) - def parse(self, session, rql, args=None): - rqlst = self.rqlhelper.parse(rql) - def type_from_eid(eid, session=session): - return session.describe(eid)[0] - try: - self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args) - except UnknownEid: - for select in rqlst.children: - select.solutions = [] - return rqlst - - @property - @cached - def rqlhelper(self): - return RQLHelper(self.schema, - special_relations={'eid': 'uid', 'has_text': 'fti'}) - - -class MulCnxCubicWebRegistry(CubicWebRegistry): - """special registry to be used when an application has to deal with - connections to differents repository. This class add some additional wrapper - trying to hide buggy class attributes since classes are not designed to be - shared among multiple registries. - """ - def etype_class(self, etype): - """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 class registered for 'Any' - """ - usercls = super(MulCnxCubicWebRegistry, self).etype_class(etype) - if etype == 'Any': - return usercls - usercls.e_schema = self.schema.eschema(etype) - return usercls - - def select_best(self, vobjects, *args, **kwargs): - """return an instance of the most specific object according - to parameters - - raise NoSelectableObject if no object apply - """ - for vobjectcls in vobjects: - self._fix_cls_attrs(vobjectcls) - selected = super(MulCnxCubicWebRegistry, self).select_best( - vobjects, *args, **kwargs) - # redo the same thing on the instance so it won't use equivalent class - # attributes (which may change) - self._fix_cls_attrs(selected) - return selected - - def _fix_cls_attrs(self, vobject): - vobject.vreg = self - vobject.schema = self.schema - vobject.config = self.config - from datetime import datetime, date, time, timedelta diff -r ff6114c2c416 -r f84ba1a66abb dbapi.py --- a/dbapi.py Tue Aug 04 15:06:09 2009 +0200 +++ b/dbapi.py Tue Aug 04 15:08:18 2009 +0200 @@ -16,9 +16,11 @@ from itertools import count from logilab.common.logging_ext import set_log_methods +from logilab.common.decorators import monkeypatch +from logilab.common.deprecation import deprecated + from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn -from cubicweb.cwvreg import CubicWebRegistry, MulCnxCubicWebRegistry -from cubicweb.cwconfig import CubicWebNoAppConfiguration +from cubicweb import cwvreg, cwconfig _MARKER = object() @@ -28,6 +30,54 @@ except KeyError: return '' +def _fix_cls_attrs(reg, appobject): + appobject.vreg = reg.vreg + appobject.schema = reg.schema + appobject.config = reg.config + +def multiple_connections_fix(): + """some monkey patching necessary when an application has to deal with + several connections to different repositories. It tries to hide buggy class + attributes since classes are not designed to be shared among multiple + registries. + """ + defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None] + orig_select_best = defaultcls.orig_select_best = defaultcls.select_best + @monkeypatch(defaultcls) + def select_best(self, appobjects, *args, **kwargs): + """return an instance of the most specific object according + to parameters + + raise NoSelectableObject if no object apply + """ + for appobjectcls in appobjects: + _fix_cls_attrs(self, appobjectcls) + selected = orig_select_best(self, appobjects, *args, **kwargs) + # redo the same thing on the instance so it won't use equivalent class + # attributes (which may change) + _fix_cls_attrs(self, selected) + return selected + + etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes'] + orig_etype_class = etypescls.orig_etype_class = etypescls.etype_class + @monkeypatch(defaultcls) + def etype_class(self, etype): + """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 class registered for 'Any' + """ + usercls = orig_etype_class(self, etype) + if etype == 'Any': + return usercls + usercls.e_schema = self.schema.eschema(etype) + return usercls + +def multiple_connections_unfix(): + defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None] + defaultcls.select_best = defaultcls.orig_select_best + etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes'] + etypescls.etype_class = etypescls.orig_etype_class + class ConnectionProperties(object): def __init__(self, cnxtype=None, lang=None, close=True, log=False): self.cnxtype = cnxtype or 'pyro' @@ -51,24 +101,14 @@ from cubicweb.server.repository import Repository return Repository(config, vreg=vreg) else: # method == 'pyro' - from Pyro import core, naming - from Pyro.errors import NamingError, ProtocolError - core.initClient(banner=0) - nsid = ':%s.%s' % (config['pyro-ns-group'], database) - locator = naming.NameServerLocator() # resolve the Pyro object + from logilab.common.pyro_ext import ns_get_proxy try: - nshost, nsport = config['pyro-ns-host'], config['pyro-ns-port'] - uri = locator.getNS(nshost, nsport).resolve(nsid) - except ProtocolError: - raise ConnectionError('Could not connect to the Pyro name server ' - '(host: %s:%i)' % (nshost, nsport)) - except NamingError: - raise ConnectionError('Could not get repository for %s ' - '(not registered in Pyro), ' - 'you may have to restart your server-side ' - 'instance' % nsid) - return core.getProxyForURI(uri) + return ns_get_proxy(database, + defaultnsgroup=config['pyro-ns-group'], + nshost=config['pyro-ns-host']) + except Exception, ex: + raise ConnectionError(str(ex)) def repo_connect(repo, login, password, cnxprops=None): """Constructor to create a new connection to the CubicWeb repository. @@ -82,22 +122,18 @@ cnx.vreg = repo.vreg return cnx -def connect(database=None, login=None, password=None, host=None, - group=None, cnxprops=None, port=None, setvreg=True, mulcnx=True, - initlog=True): +def connect(database=None, login=None, password=None, host=None, group=None, + cnxprops=None, setvreg=True, mulcnx=True, initlog=True): """Constructor for creating a connection to the CubicWeb repository. Returns a Connection object. - When method is 'pyro' and setvreg is True, use a special registry class - (MulCnxCubicWebRegistry) made to deal with connections to differents instances - in the same process unless specified otherwise by setting the mulcnx to - False. + When method is 'pyro', setvreg is True, try to deal with connections to + differents instances in the same process unless specified otherwise by + setting the mulcnx to False. """ - config = CubicWebNoAppConfiguration() + config = cwconfig.CubicWebNoAppConfiguration() if host: config.global_set_option('pyro-ns-host', host) - if port: - config.global_set_option('pyro-ns-port', port) if group: config.global_set_option('pyro-ns-group', group) cnxprops = cnxprops or ConnectionProperties() @@ -107,9 +143,8 @@ vreg = repo.vreg elif setvreg: if mulcnx: - vreg = MulCnxCubicWebRegistry(config, initlog=initlog) - else: - vreg = CubicWebRegistry(config, initlog=initlog) + multiple_connections_fix() + vreg = cwvreg.CubicWebVRegistry(config, initlog=initlog) schema = repo.get_schema() for oldetype, newetype in ETYPE_NAME_MAP.items(): if oldetype in schema: @@ -126,7 +161,7 @@ """usefull method for testing and scripting to get a dbapi.Connection object connected to an in-memory repository instance """ - if isinstance(config, CubicWebRegistry): + if isinstance(config, cwvreg.CubicWebVRegistry): vreg = config config = None else: @@ -401,7 +436,7 @@ raise ProgrammingError('Closed connection') return self._repo.get_schema() - def load_vobjects(self, cubes=_MARKER, subpath=None, expand=True, + def load_appobjects(self, cubes=_MARKER, subpath=None, expand=True, force_reload=None): config = self.vreg.config if cubes is _MARKER: @@ -434,11 +469,13 @@ if self._repo.config.instance_hooks: hm.register_hooks(config.load_hooks(self.vreg)) + load_vobjects = deprecated()(load_appobjects) + def use_web_compatible_requests(self, baseurl, sitetitle=None): """monkey patch DBAPIRequest to fake a cw.web.request, so you should able to call html views using rset from a simple dbapi connection. - You should call `load_vobjects` at some point to register those views. + You should call `load_appobjects` at some point to register those views. """ from cubicweb.web.request import CubicWebRequestBase as cwrb DBAPIRequest.build_ajax_replace_url = cwrb.build_ajax_replace_url.im_func @@ -476,8 +513,9 @@ if req is None: req = self.request() rset = req.eid_rset(eid, 'CWUser') - user = self.vreg.etype_class('CWUser')(req, rset, row=0, groups=groups, - properties=properties) + user = self.vreg['etypes'].etype_class('CWUser')(req, rset, row=0, + groups=groups, + properties=properties) user['login'] = login # cache login return user diff -r ff6114c2c416 -r f84ba1a66abb devtools/__init__.py --- a/devtools/__init__.py Tue Aug 04 15:06:09 2009 +0200 +++ b/devtools/__init__.py Tue Aug 04 15:08:18 2009 +0200 @@ -142,8 +142,8 @@ class BaseApptestConfiguration(TestServerConfiguration, TwistedConfiguration): repo_method = 'inmemory' options = merge_options(TestServerConfiguration.options + TwistedConfiguration.options) - cubicweb_vobject_path = TestServerConfiguration.cubicweb_vobject_path | TwistedConfiguration.cubicweb_vobject_path - cube_vobject_path = TestServerConfiguration.cube_vobject_path | TwistedConfiguration.cube_vobject_path + cubicweb_appobject_path = TestServerConfiguration.cubicweb_appobject_path | TwistedConfiguration.cubicweb_appobject_path + cube_appobject_path = TestServerConfiguration.cube_appobject_path | TwistedConfiguration.cube_appobject_path def available_languages(self, *args): return ('en', 'fr', 'de') diff -r ff6114c2c416 -r f84ba1a66abb devtools/_apptest.py --- a/devtools/_apptest.py Tue Aug 04 15:06:09 2009 +0200 +++ b/devtools/_apptest.py Tue Aug 04 15:08:18 2009 +0200 @@ -14,7 +14,7 @@ import yams.schema from cubicweb.dbapi import repo_connect, ConnectionProperties, ProgrammingError -from cubicweb.cwvreg import CubicWebRegistry +from cubicweb.cwvreg import CubicWebVRegistry from cubicweb.web.application import CubicWebPublisher from cubicweb.web import Redirect @@ -79,7 +79,7 @@ source = config.sources()['system'] if verbose: print "init test database ..." - self.vreg = vreg = CubicWebRegistry(config) + self.vreg = vreg = CubicWebVRegistry(config) self.admlogin = source['db-user'] # restore database <=> init database self.restore_database() @@ -191,7 +191,7 @@ optional_args = {} optional_args['vid'] = vid req = self.create_request(rql=rql, **optional_args) - return self.vreg.main_template(req, template) + return self.vreg['views'].main_template(req, template) def call_edit(self, req): """shortcut for self.app.edit()""" @@ -207,7 +207,7 @@ def iter_possible_views(self, req, rset): """returns a list of possible vids for """ - for view in self.vreg.possible_views(req, rset): + for view in self.vreg['views'].possible_views(req, rset): if view.category == 'startupview': continue yield view.id @@ -216,7 +216,7 @@ def iter_startup_views(self, req): """returns the list of startup views""" - for view in self.vreg.possible_views(req, None): + for view in self.vreg['views'].possible_views(req, None): if view.category != 'startupview': continue yield view.id @@ -233,7 +233,7 @@ if verbose: print "init test database ..." source = config.sources()['system'] - self.vreg = CubicWebRegistry(config) + self.vreg = CubicWebVRegistry(config) self.cnx = init_test_database(driver=source['db-driver'], vreg=self.vreg)[1] if verbose: diff -r ff6114c2c416 -r f84ba1a66abb devtools/apptest.py --- a/devtools/apptest.py Tue Aug 04 15:06:09 2009 +0200 +++ b/devtools/apptest.py Tue Aug 04 15:08:18 2009 +0200 @@ -175,7 +175,7 @@ def etype_instance(self, etype, req=None): req = req or self.request() - e = self.env.vreg.etype_class(etype)(req, None, None) + e = self.env.vreg['etypes'].etype_class(etype)(req) e.eid = None return e @@ -224,21 +224,21 @@ self.vreg.config.global_set_option(optname, value) def pviews(self, req, rset): - return sorted((a.id, a.__class__) for a in self.vreg.possible_views(req, rset)) + return sorted((a.id, a.__class__) for a in self.vreg['views'].possible_views(req, rset=rset)) def pactions(self, req, rset, skipcategories=('addrelated', 'siteactions', 'useractions')): - return [(a.id, a.__class__) for a in self.vreg.possible_vobjects('actions', req, rset=rset) + return [(a.id, a.__class__) for a in self.vreg['actions'].possible_vobjects(req, rset=rset) if a.category not in skipcategories] def pactions_by_cats(self, req, rset, categories=('addrelated',)): - return [(a.id, a.__class__) for a in self.vreg.possible_vobjects('actions', req, rset=rset) + return [(a.id, a.__class__) for a in self.vreg['actions'].possible_vobjects(req, rset=rset) if a.category in categories] paddrelactions = deprecated()(pactions_by_cats) def pactionsdict(self, req, rset, skipcategories=('addrelated', 'siteactions', 'useractions')): res = {} - for a in self.vreg.possible_vobjects('actions', req, rset=rset): + for a in self.vreg['actions'].possible_vobjects(req, rset=rset): if a.category not in skipcategories: res.setdefault(a.category, []).append(a.__class__) return res @@ -249,7 +249,7 @@ dump = simplejson.dumps args = [dump(arg) for arg in args] req = self.request(fname=fname, pageid='123', arg=args) - ctrl = self.vreg.select('controllers', 'json', req) + ctrl = self.vreg['controllers'].select('json', req) return ctrl.publish(), req # default test setup and teardown ######################################### @@ -294,7 +294,7 @@ def setUp(self): super(ControllerTC, self).setUp() self.req = self.request() - self.ctrl = self.vreg.select('controllers', 'edit', self.req) + self.ctrl = self.vreg['controllers'].select('edit', self.req) def publish(self, req): assert req is self.ctrl.req @@ -308,7 +308,7 @@ def expect_redirect_publish(self, req=None): if req is not None: - self.ctrl = self.vreg.select('controllers', 'edit', req) + self.ctrl = self.vreg['controllers'].select('edit', req) else: req = self.req try: diff -r ff6114c2c416 -r f84ba1a66abb devtools/devctl.py --- a/devtools/devctl.py Tue Aug 04 15:06:09 2009 +0200 +++ b/devtools/devctl.py Tue Aug 04 15:08:18 2009 +0200 @@ -29,8 +29,8 @@ class DevCubeConfiguration(ServerConfiguration, WebConfiguration): """dummy config to get full library schema and entities""" creating = True - cubicweb_vobject_path = ServerConfiguration.cubicweb_vobject_path | WebConfiguration.cubicweb_vobject_path - cube_vobject_path = ServerConfiguration.cube_vobject_path | WebConfiguration.cube_vobject_path + cubicweb_appobject_path = ServerConfiguration.cubicweb_appobject_path | WebConfiguration.cubicweb_appobject_path + cube_appobject_path = ServerConfiguration.cube_appobject_path | WebConfiguration.cube_appobject_path def __init__(self, cube): super(DevCubeConfiguration, self).__init__(cube) @@ -90,7 +90,7 @@ notice that relation definitions description and static vocabulary should be marked using '_' and extracted using xgettext """ - from cubicweb.cwvreg import CubicWebRegistry + from cubicweb.cwvreg import CubicWebVRegistry cube = cubedir and split(cubedir)[-1] libconfig = DevDepConfiguration(cube) libconfig.cleanup_interface_sobjects = False @@ -102,7 +102,7 @@ config = libconfig libconfig = None schema = config.load_schema(remove_unused_rtypes=False) - vreg = CubicWebRegistry(config) + vreg = CubicWebVRegistry(config) # set_schema triggers objects registrations vreg.set_schema(schema) w(DEFAULT_POT_HEAD) @@ -187,8 +187,8 @@ #cube = (cube and 'cubes.%s.' % cube or 'cubicweb.') done = set() if libconfig is not None: - from cubicweb.cwvreg import CubicWebRegistry - libvreg = CubicWebRegistry(libconfig) + from cubicweb.cwvreg import CubicWebVRegistry + libvreg = CubicWebVRegistry(libconfig) libvreg.set_schema(libschema) # trigger objects registration # prefill done set list(_iter_vreg_objids(libvreg, done)) diff -r ff6114c2c416 -r f84ba1a66abb devtools/fake.py --- a/devtools/fake.py Tue Aug 04 15:06:09 2009 +0200 +++ b/devtools/fake.py Tue Aug 04 15:08:18 2009 +0200 @@ -35,26 +35,21 @@ def sources(self): return {} -class FakeVReg(object): +class FakeVReg(dict): def __init__(self, schema=None, config=None): self.schema = schema self.config = config or FakeConfig() self.properties = {'ui.encoding': 'UTF8', 'ui.language': 'en', } + self.update({ + 'controllers' : {'login': []}, + 'views' : {}, + }) def property_value(self, key): return self.properties[key] - _registries = { - 'controllers' : [Mock(id='view'), Mock(id='login'), - Mock(id='logout'), Mock(id='edit')], - 'views' : [Mock(id='primary'), Mock(id='oneline'), Mock(id='list')], - } - - def registry_objects(self, name, oid=None): - return self._registries[name] - def etype_class(self, etype): class Entity(dict): e_schema = self.schema[etype] diff -r ff6114c2c416 -r f84ba1a66abb devtools/testlib.py --- a/devtools/testlib.py Tue Aug 04 15:06:09 2009 +0200 +++ b/devtools/testlib.py Tue Aug 04 15:08:18 2009 +0200 @@ -185,7 +185,8 @@ req = req or rset and rset.req or self.request() req.form['vid'] = vid kwargs['rset'] = rset - view = self.vreg.select('views', vid, req, **kwargs) + viewsreg = self.vreg['views'] + view = viewsreg.select(vid, req, **kwargs) # set explicit test description if rset is not None: self.set_description("testing %s, mod=%s (%s)" % ( @@ -197,9 +198,9 @@ viewfunc = view.render else: kwargs['view'] = view - templateview = self.vreg.select('views', template, req, **kwargs) - viewfunc = lambda **k: self.vreg.main_template(req, template, - **kwargs) + templateview = viewsreg.select(template, req, **kwargs) + viewfunc = lambda **k: viewsreg.main_template(req, template, + **kwargs) kwargs.pop('rset') return self._test_view(viewfunc, view, template, kwargs) @@ -272,7 +273,8 @@ req = rset.req only_once_vids = ('primary', 'secondary', 'text') req.data['ex'] = ValueError("whatever") - for vid, views in self.vreg.registry('views').items(): + viewsvreg = self.vreg['views'] + for vid, views in viewsvreg.items(): if vid[0] == '_': continue if rset.rowcount > 1 and vid in only_once_vids: @@ -282,7 +284,7 @@ and not issubclass(view, NotificationView)] if views: try: - view = self.vreg.select_best(views, req, rset=rset) + view = viewsvreg.select_best(views, req, rset=rset) if view.linkable(): yield view else: @@ -295,19 +297,19 @@ def list_actions_for(self, rset): """returns the list of actions that can be applied on `rset`""" req = rset.req - for action in self.vreg.possible_objects('actions', req, rset=rset): + for action in self.vreg['actions'].possible_objects(req, rset=rset): yield action def list_boxes_for(self, rset): """returns the list of boxes that can be applied on `rset`""" req = rset.req - for box in self.vreg.possible_objects('boxes', req, rset=rset): + for box in self.vreg['boxes'].possible_objects(req, rset=rset): yield box def list_startup_views(self): """returns the list of startup views""" req = self.request() - for view in self.vreg.possible_views(req, None): + for view in self.vreg['views'].possible_views(req, None): if view.category == 'startupview': yield view.id else: @@ -375,9 +377,9 @@ rset2 = rset.limit(limit=1, offset=row) yield rset2 -def not_selected(vreg, vobject): +def not_selected(vreg, appobject): try: - vreg._selected[vobject.__class__] -= 1 + vreg._selected[appobject.__class__] -= 1 except (KeyError, AttributeError): pass @@ -385,26 +387,29 @@ from cubicweb.devtools.apptest import TestEnvironment env = testclass._env = TestEnvironment('data', configcls=testclass.configcls, requestcls=testclass.requestcls) - vreg = env.vreg - vreg._selected = {} - orig_select_best = vreg.__class__.select_best - def instr_select_best(self, *args, **kwargs): - selected = orig_select_best(self, *args, **kwargs) + for reg in env.vreg.values(): + reg._selected = {} try: - self._selected[selected.__class__] += 1 - except KeyError: - self._selected[selected.__class__] = 1 - except AttributeError: - pass # occurs on vreg used to restore database - return selected - vreg.__class__.select_best = instr_select_best + orig_select_best = reg.__class__.__orig_select_best + except: + orig_select_best = reg.__class__.select_best + def instr_select_best(self, *args, **kwargs): + selected = orig_select_best(self, *args, **kwargs) + try: + self._selected[selected.__class__] += 1 + except KeyError: + self._selected[selected.__class__] = 1 + except AttributeError: + pass # occurs on reg used to restore database + return selected + reg.__class__.select_best = instr_select_best + reg.__class__.__orig_select_best = orig_select_best def print_untested_objects(testclass, skipregs=('hooks', 'etypes')): - vreg = testclass._env.vreg - for registry, vobjectsdict in vreg.items(): - if registry in skipregs: + for regname, reg in testclass._env.vreg.iteritems(): + if regname in skipregs: continue - for vobjects in vobjectsdict.values(): - for vobject in vobjects: - if not vreg._selected.get(vobject): - print 'not tested', registry, vobject + for appobjects in reg.itervalues(): + for appobject in appobjects: + if not reg._selected.get(appobject): + print 'not tested', regname, appobject diff -r ff6114c2c416 -r f84ba1a66abb entities/__init__.py --- a/entities/__init__.py Tue Aug 04 15:06:09 2009 +0200 +++ b/entities/__init__.py Tue Aug 04 15:08:18 2009 +0200 @@ -14,7 +14,6 @@ from cubicweb import Unauthorized, typed_eid from cubicweb.entity import Entity -from cubicweb.utils import dump_class from cubicweb.interfaces import IBreadCrumbs, IFeed @@ -26,19 +25,6 @@ id = 'Any' __implements__ = (IBreadCrumbs, IFeed) - @classmethod - def selected(cls, etype): - """the special Any entity is used as the default factory, so - the actual class has to be constructed at selection time once we - have an actual entity'type - """ - if cls.id == etype: - return cls - usercls = dump_class(cls, etype) - usercls.id = etype - usercls.__initialize__() - return usercls - fetch_attrs = ('modification_date',) @classmethod def fetch_order(cls, attr, var): diff -r ff6114c2c416 -r f84ba1a66abb entities/test/unittest_base.py --- a/entities/test/unittest_base.py Tue Aug 04 15:06:09 2009 +0200 +++ b/entities/test/unittest_base.py Tue Aug 04 15:08:18 2009 +0200 @@ -263,21 +263,24 @@ class InterfaceTC(EnvBasedTC): def test_nonregr_subclasses_and_mixins_interfaces(self): + self.failUnless(implements(CWUser, IWorkflowable)) class MyUser(CWUser): __implements__ = (IMileStone,) self.vreg._loadedmods[__name__] = {} - self.vreg.register_vobject_class(MyUser) - self.failUnless(implements(CWUser, IWorkflowable)) - self.failUnless(implements(MyUser, IMileStone)) - self.failUnless(implements(MyUser, IWorkflowable)) + self.vreg.register_appobject_class(MyUser) + self.vreg['etypes'].initialization_completed() + MyUser_ = self.vreg['etypes'].etype_class('CWUser') + self.failUnless(MyUser is MyUser_) + self.failUnless(implements(MyUser_, IMileStone)) + self.failUnless(implements(MyUser_, IWorkflowable)) class SpecializedEntityClassesTC(EnvBasedTC): def select_eclass(self, etype): # clear selector cache - clear_cache(self.vreg, 'etype_class') - return self.vreg.etype_class(etype) + clear_cache(self.vreg['etypes'], 'etype_class') + return self.vreg['etypes'].etype_class(etype) def test_etype_class_selection_and_specialization(self): # no specific class for Subdivisions, the default one should be selected @@ -290,7 +293,7 @@ for etype in ('Company', 'Division', 'SubDivision'): class Foo(AnyEntity): id = etype - self.vreg.register_vobject_class(Foo) + self.vreg.register_appobject_class(Foo) eclass = self.select_eclass('SubDivision') if etype == 'SubDivision': self.failUnless(eclass is Foo) diff -r ff6114c2c416 -r f84ba1a66abb entity.py --- a/entity.py Tue Aug 04 15:06:09 2009 +0200 +++ b/entity.py Tue Aug 04 15:08:18 2009 +0200 @@ -20,7 +20,7 @@ from cubicweb import Unauthorized from cubicweb.rset import ResultSet from cubicweb.selectors import yes -from cubicweb.appobject import AppRsetObject +from cubicweb.appobject import AppObject from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint, bw_normalize_etype from cubicweb.common.uilib import printable_value, soup2xhtml @@ -132,7 +132,7 @@ return super(_metaentity, mcs).__new__(mcs, name, bases, classdict) -class Entity(AppRsetObject, dict): +class Entity(AppObject, dict): """an entity instance has e_schema automagically set on the class and instances has access to their issuing cursor. @@ -167,15 +167,6 @@ # class attributes set automatically at registration time e_schema = None - @classmethod - def registered(cls, registry): - """build class using descriptor at registration time""" - assert cls.id is not None - super(Entity, cls).registered(registry) - if cls.id != 'Any': - cls.__initialize__() - return cls - MODE_TAGS = set(('link', 'create')) CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata')) @classmethod @@ -265,7 +256,7 @@ continue if card == '?': restrictions[-1] += '?' # left outer join if not mandatory - destcls = cls.vreg.etype_class(desttype) + destcls = cls.vreg['etypes'].etype_class(desttype) destcls._fetch_restrictions(var, varmaker, destcls.fetch_attrs, selection, orderby, restrictions, user, ordermethod, visited=visited) @@ -277,8 +268,9 @@ @classmethod @cached def parent_classes(cls): - parents = [cls.vreg.etype_class(e.type) for e in cls.e_schema.ancestors()] - parents.append(cls.vreg.etype_class('Any')) + parents = [cls.vreg['etypes'].etype_class(e.type) + for e in cls.e_schema.ancestors()] + parents.append(cls.vreg['etypes'].etype_class('Any')) return parents @classmethod @@ -299,7 +291,7 @@ return mainattr, needcheck def __init__(self, req, rset=None, row=None, col=0): - AppRsetObject.__init__(self, req, rset, row, col) + AppObject.__init__(self, req, rset, row, col) dict.__init__(self) self._related_cache = {} if rset is not None: @@ -364,10 +356,10 @@ def has_perm(self, action): return self.e_schema.has_perm(self.req, action, self.eid) - def view(self, vid, **kwargs): + def view(self, vid, __registry='views', **kwargs): """shortcut to apply a view on this entity""" - return self.vreg.render(vid, self.req, rset=self.rset, - row=self.row, col=self.col, **kwargs) + return self.vreg[__registry].render(vid, self.req, rset=self.rset, + row=self.row, col=self.col, **kwargs) def absolute_url(self, *args, **kwargs): """return an absolute url to view this entity""" @@ -702,13 +694,13 @@ if len(targettypes) > 1: fetchattrs_list = [] for ttype in targettypes: - etypecls = self.vreg.etype_class(ttype) + etypecls = self.vreg['etypes'].etype_class(ttype) fetchattrs_list.append(set(etypecls.fetch_attrs)) fetchattrs = reduce(set.intersection, fetchattrs_list) rql = etypecls.fetch_rql(self.req.user, [restriction], fetchattrs, settype=False) else: - etypecls = self.vreg.etype_class(targettypes[0]) + etypecls = self.vreg['etypes'].etype_class(targettypes[0]) rql = etypecls.fetch_rql(self.req.user, [restriction], settype=False) # optimisation: remove ORDERBY if cardinality is 1 or ? (though # greater_card return 1 for those both cases) @@ -764,7 +756,7 @@ else: restriction += [cstr.restriction for cstr in constraints if isinstance(cstr, RQLConstraint)] - etypecls = self.vreg.etype_class(targettype) + etypecls = self.vreg['etypes'].etype_class(targettype) rql = etypecls.fetch_rql(self.req.user, restriction, mainvar=searchedvar, ordermethod=ordermethod) # ensure we have an order defined diff -r ff6114c2c416 -r f84ba1a66abb etwist/server.py --- a/etwist/server.py Tue Aug 04 15:06:09 2009 +0200 +++ b/etwist/server.py Tue Aug 04 15:08:18 2009 +0200 @@ -109,7 +109,7 @@ self.pyro_listen_timeout = 0.02 start_task(1, self.pyro_loop_event) self.appli.repo.start_looping_tasks() - self.url_rewriter = self.appli.vreg.select_object('components', 'urlrewriter') + self.url_rewriter = self.appli.vreg['components'].select_object('urlrewriter') interval = min(config['cleanup-session-time'] or 120, config['cleanup-anonymous-session-time'] or 720) / 2. start_task(interval, self.appli.session_handler.clean_sessions) @@ -330,7 +330,7 @@ def _gc_debug(): import gc from pprint import pprint - from cubicweb.vregistry import VObject + from cubicweb.appobject import AppObject gc.collect() count = 0 acount = 0 @@ -338,7 +338,7 @@ for obj in gc.get_objects(): if isinstance(obj, CubicWebTwistedRequestAdapter): count += 1 - elif isinstance(obj, VObject): + elif isinstance(obj, AppObject): acount += 1 else: try: diff -r ff6114c2c416 -r f84ba1a66abb etwist/twconfig.py --- a/etwist/twconfig.py Tue Aug 04 15:06:09 2009 +0200 +++ b/etwist/twconfig.py Tue Aug 04 15:08:18 2009 +0200 @@ -87,8 +87,8 @@ options = merge_options(TwistedConfiguration.options + ServerConfiguration.options) - cubicweb_vobject_path = TwistedConfiguration.cubicweb_vobject_path | ServerConfiguration.cubicweb_vobject_path - cube_vobject_path = TwistedConfiguration.cube_vobject_path | ServerConfiguration.cube_vobject_path + cubicweb_appobject_path = TwistedConfiguration.cubicweb_appobject_path | ServerConfiguration.cubicweb_appobject_path + cube_appobject_path = TwistedConfiguration.cube_appobject_path | ServerConfiguration.cube_appobject_path def pyro_enabled(self): """tell if pyro is activated for the in memory repository""" return self['pyro-server'] diff -r ff6114c2c416 -r f84ba1a66abb goa/db.py --- a/goa/db.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/db.py Tue Aug 04 15:08:18 2009 +0200 @@ -274,8 +274,8 @@ def view(self, vid, __registry='views', **kwargs): """shortcut to apply a view on this entity""" - return self.vreg.render(__registry, vid, self.req, rset=self.rset, - row=self.row, col=self.col, **kwargs) + return self.vreg[__registry]render(vid, self.req, rset=self.rset, + row=self.row, col=self.col, **kwargs) @classmethod def _rest_attr_info(cls): diff -r ff6114c2c416 -r f84ba1a66abb goa/goaconfig.py --- a/goa/goaconfig.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/goaconfig.py Tue Aug 04 15:08:18 2009 +0200 @@ -17,8 +17,8 @@ from cubicweb.goa.dbmyams import load_schema UNSUPPORTED_OPTIONS = set(('connections-pool-size', - 'pyro-port', 'pyro-id', 'pyro-instance-id', - 'pyro-ns-host', 'pyro-ns-port', 'pyro-ns-group', + 'pyro-host', 'pyro-id', 'pyro-instance-id', + 'pyro-ns-host', 'pyro-ns-group', 'https-url', 'host', 'pid-file', 'uid', 'base-url', 'log-file', 'smtp-host', 'smtp-port', 'embed-allowed', @@ -81,9 +81,9 @@ options = [(optname, optdict) for optname, optdict in options if not optname in UNSUPPORTED_OPTIONS] - cubicweb_vobject_path = WebConfiguration.cubicweb_vobject_path | ServerConfiguration.cubicweb_vobject_path - cubicweb_vobject_path = list(cubicweb_vobject_path) + ['goa/appobjects'] - cube_vobject_path = WebConfiguration.cube_vobject_path | ServerConfiguration.cube_vobject_path + cubicweb_appobject_path = WebConfiguration.cubicweb_appobject_path | ServerConfiguration.cubicweb_appobject_path + cubicweb_appobject_path = list(cubicweb_appobject_path) + ['goa/appobjects'] + cube_appobject_path = WebConfiguration.cube_appobject_path | ServerConfiguration.cube_appobject_path # use file system schema bootstrap_schema = read_instance_schema = False diff -r ff6114c2c416 -r f84ba1a66abb goa/goavreg.py --- a/goa/goavreg.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/goavreg.py Tue Aug 04 15:08:18 2009 +0200 @@ -11,7 +11,7 @@ from os.path import join, isdir from cubicweb import CW_SOFTWARE_ROOT -from cubicweb.cwvreg import CubicWebRegistry +from cubicweb.cwvreg import CubicWebVRegistry def _pkg_name(cube, module): @@ -19,7 +19,7 @@ return module return 'cubes.%s.%s' % (cube, module) -class GAERegistry(CubicWebRegistry): +class GAEVRegistry(CubicWebVRegistry): def set_schema(self, schema): """disable reload hooks of cubicweb registry set_schema method""" @@ -59,7 +59,7 @@ self.load_module(obj) def _auto_load(self, path, loadschema, cube=None): - vobjpath = self.config.cube_vobject_path + vobjpath = self.config.cube_appobject_path for filename in listdir(path): if filename[-3:] == '.py' and filename[:-3] in vobjpath: self._import(_pkg_name(cube, filename[:-3])) diff -r ff6114c2c416 -r f84ba1a66abb goa/skel/main.py --- a/goa/skel/main.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/skel/main.py Tue Aug 04 15:08:18 2009 +0200 @@ -22,8 +22,8 @@ config = GAEConfiguration('toto', APPLROOT) # dynamic objects registry -from cubicweb.goa.goavreg import GAERegistry -vreg = GAERegistry(config, debug=goa.MODE == 'dev') +from cubicweb.goa.goavreg import GAEVregistry +vreg = GAEVregistry(config, debug=goa.MODE == 'dev') # trigger automatic classes registration (metaclass magic), should be done # before schema loading diff -r ff6114c2c416 -r f84ba1a66abb goa/test/unittest_views.py --- a/goa/test/unittest_views.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/test/unittest_views.py Tue Aug 04 15:08:18 2009 +0200 @@ -46,10 +46,10 @@ self.blog.put(self.req) def test_hcal(self): - self.vreg.render('views', 'hcal', self.req, rset=self.blog.rset) + self.vreg['views'].render('hcal', self.req, rset=self.blog.rset) def test_django_index(self): - self.vreg.render('views', 'index', self.req, rset=None) + self.vreg'views'].render('index', self.req, rset=None) for vid in ('primary', 'oneline', 'incontext', 'outofcontext', 'text'): setattr(SomeViewsTC, 'test_%s'%vid, lambda self, vid=vid: self.blog.view(vid)) diff -r ff6114c2c416 -r f84ba1a66abb goa/testlib.py --- a/goa/testlib.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/testlib.py Tue Aug 04 15:08:18 2009 +0200 @@ -42,7 +42,7 @@ from cubicweb.devtools.fake import FakeRequest -from cubicweb.goa.goavreg import GAERegistry +from cubicweb.goa.goavreg import GAEVregistry from cubicweb.goa.goaconfig import GAEConfiguration from cubicweb.goa.dbinit import (create_user, create_groups, fix_entities, init_persistent_schema, insert_versions) @@ -115,7 +115,7 @@ self.config.init_log(logging.CRITICAL) self.schema = self.config.load_schema(self.MODEL_CLASSES, self.load_schema_hook) - self.vreg = GAERegistry(self.config) + self.vreg = GAEVregistry(self.config) self.vreg.schema = self.schema self.vreg.load_module(db) from cubicweb.goa.appobjects import sessions diff -r ff6114c2c416 -r f84ba1a66abb goa/tools/laxctl.py --- a/goa/tools/laxctl.py Tue Aug 04 15:06:09 2009 +0200 +++ b/goa/tools/laxctl.py Tue Aug 04 15:08:18 2009 +0200 @@ -28,11 +28,11 @@ # apply monkey patches first from cubicweb.goa import do_monkey_patch do_monkey_patch() - from cubicweb.goa.goavreg import GAERegistry + from cubicweb.goa.goavreg import GAEVregistry from cubicweb.goa.goaconfig import GAEConfiguration #WebConfiguration.ext_resources['JAVASCRIPTS'].append('DATADIR/goa.js') config = GAEConfiguration('toto', applroot) - vreg = GAERegistry(config) + vreg = GAEVregistry(config) vreg.set_schema(config.load_schema()) return vreg diff -r ff6114c2c416 -r f84ba1a66abb rset.py --- a/rset.py Tue Aug 04 15:06:09 2009 +0200 +++ b/rset.py Tue Aug 04 15:08:18 2009 +0200 @@ -83,8 +83,8 @@ try: return self._rsetactions[key] except KeyError: - actions = self.vreg.possible_vobjects('actions', self.req, - rset=self, **kwargs) + actions = self.vreg['actions'].possible_vobjects( + self.req, rset=self, **kwargs) self._rsetactions[key] = actions return actions @@ -370,12 +370,21 @@ # XXX should we consider updating a cached entity with possible # new attributes found in this resultset ? try: - return req.entity_cache(eid) + entity = req.entity_cache(eid) + if entity.rset is None: + # entity has no rset set, this means entity has been cached by + # the repository (req is a repository session) which had no rset + # info. Add id. + entity.rset = self + entity.row = row + entity.col = col + return entity except KeyError: pass # build entity instance etype = self.description[row][col] - entity = self.vreg.etype_class(etype)(req, self, row, col) + entity = self.vreg['etypes'].etype_class(etype)(req, rset=self, + row=row, col=col) entity.set_eid(eid) # cache entity req.set_entity_cache(entity) diff -r ff6114c2c416 -r f84ba1a66abb schemas/base.py --- a/schemas/base.py Tue Aug 04 15:06:09 2009 +0200 +++ b/schemas/base.py Tue Aug 04 15:08:18 2009 +0200 @@ -242,7 +242,7 @@ The target application is responsible for updating timestamp when necessary to invalidate the cache (typically in hooks). - Also, checkout the AppRsetObject.get_cache() method. + Also, checkout the AppObject.get_cache() method. """ permissions = { 'read': ('managers', 'users', 'guests'), diff -r ff6114c2c416 -r f84ba1a66abb schemaviewer.py --- a/schemaviewer.py Tue Aug 04 15:06:09 2009 +0200 +++ b/schemaviewer.py Tue Aug 04 15:08:18 2009 +0200 @@ -19,7 +19,7 @@ self.req = req if req is not None: self.req.add_css('cubicweb.schema.css') - self._possible_views = req.vreg.possible_views + self._possible_views = req.vreg['views'].possible_views if not encoding: encoding = req.encoding else: diff -r ff6114c2c416 -r f84ba1a66abb selectors.py --- a/selectors.py Tue Aug 04 15:06:09 2009 +0200 +++ b/selectors.py Tue Aug 04 15:08:18 2009 +0200 @@ -53,8 +53,8 @@ from cubicweb import (Unauthorized, NoSelectableObject, NotAnEntity, role, typed_eid) -from cubicweb.vregistry import (NoSelectableObject, Selector, - chainall, objectify_selector) +# even if not used, let yes here so it's importable through this module +from cubicweb.appobject import Selector, objectify_selector, yes from cubicweb.cwconfig import CubicWebConfiguration from cubicweb.schema import split_expression @@ -165,7 +165,7 @@ if isinstance(iface, basestring): # entity type try: - iface = vreg.etype_class(iface) + iface = vreg['etypes'].etype_class(iface) except KeyError: continue # entity type not in the schema score += score_interface(cls_or_inst, cls, iface) @@ -212,7 +212,7 @@ def score(self, cls, req, etype): if etype in BASE_TYPES: return 0 - return self.score_class(cls.vreg.etype_class(etype), req) + return self.score_class(cls.vreg['etypes'].etype_class(etype), req) def score_class(self, eclass, req): raise NotImplementedError() @@ -274,17 +274,6 @@ # very basic selectors ######################################################## -class yes(Selector): - """return arbitrary score - - default score of 0.5 so any other selector take precedence - """ - def __init__(self, score=0.5): - self.score = score - - def __call__(self, *args, **kwargs): - return self.score - @objectify_selector @lltrace def none_rset(cls, req, rset=None, **kwargs): @@ -570,9 +559,9 @@ self.registry = registry self.oid = oid - def __call__(self, cls, req, rset=None, *args, **kwargs): + def __call__(self, cls, req, **kwargs): try: - cls.vreg.select(self.registry, self.oid, req, rset=rset, **kwargs) + cls.vreg[self.registry].select(self.oid, req, **kwargs) return 1 except NoSelectableObject: return 0 @@ -630,7 +619,7 @@ req.form['etype'] = etype except KeyError: return 0 - return self.score_class(cls.vreg.etype_class(etype), req) + return self.score_class(cls.vreg['etypes'].etype_class(etype), req) class entity_implements(ImplementsMixIn, EntitySelector): @@ -975,6 +964,7 @@ # XXX DEPRECATED ############################################################## +from cubicweb.vregistry import chainall yes_selector = deprecated()(yes) norset_selector = deprecated()(none_rset) @@ -1040,7 +1030,7 @@ accept_selector = deprecated()(accept) accept_one = deprecated()(chainall(one_line_rset, accept, - name='accept_one')) + name='accept_one')) accept_one_selector = deprecated()(accept_one) diff -r ff6114c2c416 -r f84ba1a66abb server/repository.py --- a/server/repository.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/repository.py Tue Aug 04 15:08:18 2009 +0200 @@ -33,7 +33,7 @@ BadConnectionId, Unauthorized, ValidationError, ExecutionError, typed_eid, CW_MIGRATION_MAP) -from cubicweb.cwvreg import CubicWebRegistry +from cubicweb.cwvreg import CubicWebVRegistry from cubicweb.schema import VIRTUAL_RTYPES, CubicWebSchema from cubicweb import server from cubicweb.server.utils import RepoThread, LoopTask @@ -137,7 +137,7 @@ def __init__(self, config, vreg=None, debug=False): self.config = config if vreg is None: - vreg = CubicWebRegistry(config, debug) + vreg = CubicWebVRegistry(config, debug) self.vreg = vreg self.pyro_registered = False self.info('starting repository from %s', self.config.apphome) @@ -428,7 +428,7 @@ def _build_user(self, session, eid): """return a CWUser entity for user with the given eid""" - cls = self.vreg.etype_class('CWUser') + cls = self.vreg['etypes'].etype_class('CWUser') rql = cls.fetch_rql(session.user, ['X eid %(x)s']) rset = session.execute(rql, {'x': eid}, 'x') assert len(rset) == 1, rset @@ -532,7 +532,7 @@ {'login': login})): raise ValidationError(None, {'login': errmsg % login}) # we have to create the user - user = self.vreg.etype_class('CWUser')(session, None) + user = self.vreg['etypes'].etype_class('CWUser')(session, None) if isinstance(password, unicode): # password should *always* be utf8 encoded password = password.encode('UTF8') @@ -1038,13 +1038,15 @@ entity.eid, attr, value) return entity.eid - def glob_update_entity(self, session, entity): + def glob_update_entity(self, session, entity, edited_attributes): """replace an entity in the repository the type and the eid of an entity must not be changed """ etype = str(entity.e_schema) if server.DEBUG & server.DBG_REPO: - print 'UPDATE entity', etype, entity.eid, dict(entity) + print 'UPDATE entity', etype, entity.eid, \ + dict(entity), edited_attributes + entity.edited_attributes = edited_attributes entity.check() eschema = entity.e_schema session.set_entity_cache(entity) @@ -1164,36 +1166,16 @@ def pyro_register(self, host=''): """register the repository as a pyro object""" - from Pyro import core - port = self.config['pyro-port'] - nshost, nsgroup = self.config['pyro-ns-host'], self.config['pyro-ns-group'] - nsgroup = ':' + nsgroup - core.initServer(banner=0) - daemon = core.Daemon(host=host, port=port) - daemon.useNameServer(self.pyro_nameserver(nshost, nsgroup)) - # use Delegation approach - impl = core.ObjBase() - impl.delegateTo(self) - nsid = self.config['pyro-id'] or self.config.appid - daemon.connect(impl, '%s.%s' % (nsgroup, nsid)) + from logilab.common.pyro_ext import register_object + appid = self.config['pyro-id'] or self.config.appid + daemon = register_object(self, appid, self.config['pyro-ns-group'], + self.config['pyro-host'], + self.config['pyro-ns-host']) msg = 'repository registered as a pyro object using group %s and id %s' - self.info(msg, nsgroup, nsid) + self.info(msg, self.config['pyro-ns-group'], appid) self.pyro_registered = True return daemon - def pyro_nameserver(self, host=None, group=None): - """locate and bind the the name server to the daemon""" - from Pyro import naming, errors - # locate the name server - nameserver = naming.NameServerLocator().getNS(host) - if group is not None: - # make sure our namespace group exists - try: - nameserver.createGroup(group) - except errors.NamingError: - pass - return nameserver - # multi-sources planner helpers ########################################### @cached @@ -1217,21 +1199,9 @@ def pyro_unregister(config): """unregister the repository from the pyro name server""" - nshost, nsgroup = config['pyro-ns-host'], config['pyro-ns-group'] + from logilab.common.pyro_ext import ns_unregister appid = config['pyro-id'] or config.appid - from Pyro import core, naming, errors - core.initClient(banner=False) - try: - nameserver = naming.NameServerLocator().getNS(nshost) - except errors.PyroError, ex: - # name server not responding - config.error('can\'t locate pyro name server: %s', ex) - return - try: - nameserver.unregister(':%s.%s' % (nsgroup, appid)) - config.info('%s unregistered from pyro name server', appid) - except errors.NamingError: - config.warning('%s already unregistered from pyro name server', appid) + ns_unregister(appid, config['pyro-ns-group'], config['pyro-ns-host']) from logging import getLogger diff -r ff6114c2c416 -r f84ba1a66abb server/serverconfig.py --- a/server/serverconfig.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/serverconfig.py Tue Aug 04 15:08:18 2009 +0200 @@ -85,8 +85,8 @@ SCHEMAS_LIB_DIR = '/usr/share/cubicweb/schemas/' BACKUP_DIR = '/var/lib/cubicweb/backup/' - cubicweb_vobject_path = CubicWebConfiguration.cubicweb_vobject_path | set(['sobjects']) - cube_vobject_path = CubicWebConfiguration.cube_vobject_path | set(['sobjects', 'hooks']) + cubicweb_appobject_path = CubicWebConfiguration.cubicweb_appobject_path | set(['sobjects']) + cube_appobject_path = CubicWebConfiguration.cube_appobject_path | set(['sobjects', 'hooks']) options = merge_options(( # ctl configuration @@ -165,10 +165,12 @@ 'group': 'email', 'inputlevel': 2, }), # pyro server.serverconfig - ('pyro-port', + ('pyro-host', {'type' : 'int', 'default': None, - 'help': 'Pyro server port. If not set, it will be choosen randomly', + 'help': 'Pyro server host, if not detectable correctly through \ +gethostname(). It may contains port information using : notation, \ +and if not set, it will be choosen randomly', 'group': 'pyro-server', 'inputlevel': 2, }), ('pyro-id', # XXX reuse pyro-instance-id @@ -265,7 +267,7 @@ def load_hooks(self, vreg): hooks = {} try: - apphookdefs = vreg.registry_objects('hooks') + apphookdefs = vreg['hooks'].all_objects() except RegistryNotFound: return hooks for hookdef in apphookdefs: diff -r ff6114c2c416 -r f84ba1a66abb server/session.py --- a/server/session.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/session.py Tue Aug 04 15:08:18 2009 +0200 @@ -142,10 +142,6 @@ """return the original parent session if any, else self""" return self - def etype_class(self, etype): - """return an entity class for the given entity type""" - return self.vreg.etype_class(etype) - def system_sql(self, sql, args=None, rollback_on_failure=True): """return a sql cursor on the system database""" if not sql.split(None, 1)[0].upper() == 'SELECT': @@ -555,6 +551,11 @@ description.append(tuple(row_descr)) return description + @deprecated("use vreg['etypes'].etype_class(etype)") + def etype_class(self, etype): + """return an entity class for the given entity type""" + return self.vreg['etypes'].etype_class(etype) + @deprecated('use direct access to session.transaction_data') def query_data(self, key, default=None, setdefault=False, pop=False): if setdefault: diff -r ff6114c2c416 -r f84ba1a66abb server/sources/__init__.py --- a/server/sources/__init__.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/sources/__init__.py Tue Aug 04 15:08:18 2009 +0200 @@ -325,7 +325,7 @@ This method must return the an Entity instance representation of this entity. """ - entity = self.repo.vreg.etype_class(etype)(session, None) + entity = self.repo.vreg['etypes'].etype_class(etype)(session) entity.set_eid(eid) return entity diff -r ff6114c2c416 -r f84ba1a66abb server/sources/pyrorql.py --- a/server/sources/pyrorql.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/sources/pyrorql.py Tue Aug 04 15:08:18 2009 +0200 @@ -79,14 +79,7 @@ {'type' : 'string', 'default': None, 'help': 'Pyro name server\'s host. If not set, default to the value \ -from all_in_one.conf.', - 'group': 'pyro-source', 'inputlevel': 1, - }), - ('pyro-ns-port', - {'type' : 'int', - 'default': None, - 'help': 'Pyro name server\'s listening port. If not set, default to \ -the value from all_in_one.conf.', +from all_in_one.conf. It may contains port information using : notation.', 'group': 'pyro-source', 'inputlevel': 1, }), ('pyro-ns-group', @@ -214,13 +207,12 @@ def _get_connection(self): """open and return a connection to the source""" nshost = self.config.get('pyro-ns-host') or self.repo.config['pyro-ns-host'] - nsport = self.config.get('pyro-ns-port') or self.repo.config['pyro-ns-port'] nsgroup = self.config.get('pyro-ns-group') or self.repo.config['pyro-ns-group'] #cnxprops = ConnectionProperties(cnxtype=self.config['cnx-type']) return dbapi.connect(database=self.config['pyro-ns-id'], login=self.config['cubicweb-user'], password=self.config['cubicweb-password'], - host=nshost, port=nsport, group=nsgroup, + host=nshost, group=nsgroup, setvreg=False) #cnxprops=cnxprops) def get_connection(self): diff -r ff6114c2c416 -r f84ba1a66abb server/ssplanner.py --- a/server/ssplanner.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/ssplanner.py Tue Aug 04 15:08:18 2009 +0200 @@ -114,9 +114,10 @@ # each variable in main variables is a new entity to insert to_build = {} session = plan.session + etype_class = session.vreg['etypes'].etype_class for etype, var in rqlst.main_variables: # need to do this since entity class is shared w. web client code ! - to_build[var.name] = session.etype_class(etype)(session, None, None) + to_build[var.name] = etype_class(etype)(session) plan.add_entity_def(to_build[var.name]) # add constant values to entity def, mark variables to be selected to_select = plan.relation_definitions(rqlst, to_build) @@ -481,6 +482,7 @@ repo = session.repo edefs = {} # insert relations + attributes = [relation.r_type for relation in self.attribute_relations] for row in self.execute_child(): for relation in self.attribute_relations: lhs, rhs = relation.get_variable_parts() @@ -488,7 +490,7 @@ try: edef = edefs[eid] except KeyError: - edefs[eid] = edef = session.eid_rset(eid).get_entity(0, 0) + edefs[eid] = edef = session.entity_from_eid(eid) if isinstance(rhs, Constant): # add constant values to entity def value = rhs.eval(plan.args) @@ -502,6 +504,6 @@ # update entities result = [] for eid, edef in edefs.iteritems(): - repo.glob_update_entity(session, edef) + repo.glob_update_entity(session, edef, attributes) result.append( (eid,) ) return result diff -r ff6114c2c416 -r f84ba1a66abb server/test/unittest_repository.py --- a/server/test/unittest_repository.py Tue Aug 04 15:06:09 2009 +0200 +++ b/server/test/unittest_repository.py Tue Aug 04 15:08:18 2009 +0200 @@ -20,7 +20,7 @@ from cubicweb import BadConnectionId, RepositoryError, ValidationError, UnknownEid, AuthenticationError from cubicweb.schema import CubicWebSchema, RQLConstraint -from cubicweb.dbapi import connect, repo_connect +from cubicweb.dbapi import connect, repo_connect, multiple_connections_unfix from cubicweb.devtools.apptest import RepositoryBasedTC from cubicweb.devtools.repotest import tuplify from cubicweb.server import repository @@ -276,13 +276,17 @@ def _pyro_client(self, done): cnx = connect(self.repo.config.appid, u'admin', 'gingkow') - # check we can get the schema - schema = cnx.get_schema() - self.assertEquals(schema.__hashmode__, None) - cu = cnx.cursor() - rset = cu.execute('Any U,G WHERE U in_group G') - cnx.close() - done.append(True) + try: + # check we can get the schema + schema = cnx.get_schema() + self.assertEquals(schema.__hashmode__, None) + cu = cnx.cursor() + rset = cu.execute('Any U,G WHERE U in_group G') + cnx.close() + done.append(True) + finally: + # connect monkey path some method by default, remove them + multiple_connections_unfix() def test_internal_api(self): repo = self.repo @@ -367,7 +371,7 @@ self.assertRaises(UnknownEid, self.repo.type_from_eid, -2, self.session) def test_add_delete_info(self): - entity = self.repo.vreg.etype_class('Personne')(self.session, None, None) + entity = self.repo.vreg['etypes'].etype_class('Personne')(self.session) entity.eid = -1 entity.complete = lambda x: None self.repo.add_info(self.session, entity, self.repo.sources_by_uri['system']) diff -r ff6114c2c416 -r f84ba1a66abb sobjects/notification.py --- a/sobjects/notification.py Tue Aug 04 15:06:09 2009 +0200 +++ b/sobjects/notification.py Tue Aug 04 15:08:18 2009 +0200 @@ -76,8 +76,8 @@ return rset = entity.related('wf_info_for') try: - view = session.vreg.select('views', 'notif_status_change', - session, rset=rset, row=0) + view = session.vreg['views'].select('notif_status_change', session, + rset=rset, row=0) except RegistryException: return comment = entity.printable_value('comment', format='text/plain') @@ -100,7 +100,7 @@ rset = session.eid_rset(fromeid) vid = 'notif_%s_%s' % (self.event, rtype) try: - view = session.vreg.select('views', vid, session, rset=rset, row=0) + view = session.vreg['views'].select(vid, session, rset=rset, row=0) except RegistryException: return RenderAndSendNotificationView(session, view=view) @@ -117,7 +117,7 @@ rset = entity.as_rset() vid = 'notif_%s' % self.event try: - view = session.vreg.select('views', vid, session, rset=rset, row=0) + view = session.vreg['views'].select(vid, session, rset=rset, row=0) except RegistryException: return RenderAndSendNotificationView(session, view=view) @@ -138,7 +138,7 @@ msgid_timestamp = True def recipients(self): - finder = self.vreg.select('components', 'recipients_finder', self.req, + finder = self.vreg['components'].select('recipients_finder', self.req, rset=self.rset) return finder.recipients() diff -r ff6114c2c416 -r f84ba1a66abb sobjects/supervising.py --- a/sobjects/supervising.py Tue Aug 04 15:06:09 2009 +0200 +++ b/sobjects/supervising.py Tue Aug 04 15:08:18 2009 +0200 @@ -31,12 +31,16 @@ SupervisionMailOp(session) def _call(self, *args): - if self._event() == 'update_entity' and args[0].e_schema == 'CWUser': - updated = set(args[0].iterkeys()) - if not (updated - frozenset(('eid', 'modification_date', 'last_login_time'))): - # don't record last_login_time update which are done - # automatically at login time + if self._event() == 'update_entity': + if args[0].eid in self.session.transaction_data.get('neweids', ()): return False + if args[0].e_schema == 'CWUser': + updated = set(args[0].iterkeys()) + if not (updated - frozenset(('eid', 'modification_date', + 'last_login_time'))): + # don't record last_login_time update which are done + # automatically at login time + return False self.session.transaction_data.setdefault('pendingchanges', []).append( (self._event(), args)) return True @@ -218,8 +222,8 @@ of changes """ def _get_view(self): - return self.session.vreg.select('components', 'supervision_notif', - self.session) + return self.session.vreg['components'].select('supervision_notif', + self.session) def _prepare_email(self): session = self.session diff -r ff6114c2c416 -r f84ba1a66abb sobjects/test/data/schema.py --- a/sobjects/test/data/schema.py Tue Aug 04 15:06:09 2009 +0200 +++ b/sobjects/test/data/schema.py Tue Aug 04 15:08:18 2009 +0200 @@ -5,6 +5,8 @@ :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses """ +from yams.buildobjs import RelationDefinition + class comments(RelationDefinition): subject = 'Comment' object = 'Card' diff -r ff6114c2c416 -r f84ba1a66abb sobjects/test/unittest_notification.py --- a/sobjects/test/unittest_notification.py Tue Aug 04 15:06:09 2009 +0200 +++ b/sobjects/test/unittest_notification.py Tue Aug 04 15:08:18 2009 +0200 @@ -56,8 +56,8 @@ self.execute('INSERT CWProperty X: X pkey "ui.language", X value "fr", X for_user U ' 'WHERE U eid %(x)s', {'x': urset[0][0]}) self.commit() # commit so that admin get its properties updated - finder = self.vreg.select('components', 'recipients_finder', self.request(), - rset=urset) + finder = self.vreg['components'].select('recipients_finder', + self.request(), rset=urset) self.set_option('default-recipients-mode', 'none') self.assertEquals(finder.recipients(), []) self.set_option('default-recipients-mode', 'users') @@ -73,8 +73,9 @@ req = self.session() u = self.create_user('toto', req=req) assert u.req + assert u.rset self.execute('SET X in_state S WHERE X eid %s, S name "deactivated"' % u.eid) - v = self.vreg.select('views', 'notif_status_change', req, rset=u.rset, row=0) + v = self.vreg['views'].select('notif_status_change', req, rset=u.rset, row=0) content = v.render(row=0, comment='yeah', previous_state='activated', current_state='deactivated') diff -r ff6114c2c416 -r f84ba1a66abb test/unittest_entity.py --- a/test/unittest_entity.py Tue Aug 04 15:06:09 2009 +0200 +++ b/test/unittest_entity.py Tue Aug 04 15:08:18 2009 +0200 @@ -121,9 +121,9 @@ def test_fetch_rql(self): user = self.user() - Personne = self.vreg.etype_class('Personne') - Societe = self.vreg.etype_class('Societe') - Note = self.vreg.etype_class('Note') + Personne = self.vreg['etypes'].etype_class('Personne') + Societe = self.vreg['etypes'].etype_class('Societe') + Note = self.vreg['etypes'].etype_class('Note') peschema = Personne.e_schema seschema = Societe.e_schema peschema.subject_relation('travaille').set_rproperty(peschema, seschema, 'cardinality', '1*') @@ -175,8 +175,8 @@ def test_related_rql(self): from cubicweb.entities import fetch_config - Personne = self.vreg.etype_class('Personne') - Note = self.vreg.etype_class('Note') + Personne = self.vreg['etypes'].etype_class('Personne') + Note = self.vreg['etypes'].etype_class('Note') Personne.fetch_attrs, Personne.fetch_order = fetch_config(('nom', 'type')) Note.fetch_attrs, Note.fetch_order = fetch_config(('type',)) aff = self.add_entity('Personne', nom=u'pouet') diff -r ff6114c2c416 -r f84ba1a66abb test/unittest_rtags.py --- a/test/unittest_rtags.py Tue Aug 04 15:06:09 2009 +0200 +++ b/test/unittest_rtags.py Tue Aug 04 15:08:18 2009 +0200 @@ -39,7 +39,7 @@ # __rtags__ = { # ('evaluee', 'Note', 'subject') : set(('inlineview',)), # } -# self.vreg.register_vobject_class(Personne2) +# self.vreg.register_appobject_class(Personne2) # rtags = Personne2.rtags # self.assertEquals(rtags.rtag('evaluee', 'Note', 'subject'), set(('inlineview', 'link'))) # self.assertEquals(rtags.is_inlined('evaluee', 'Note', 'subject'), True) diff -r ff6114c2c416 -r f84ba1a66abb test/unittest_selectors.py --- a/test/unittest_selectors.py Tue Aug 04 15:06:09 2009 +0200 +++ b/test/unittest_selectors.py Tue Aug 04 15:08:18 2009 +0200 @@ -9,7 +9,7 @@ from logilab.common.testlib import TestCase, unittest_main from cubicweb.devtools.testlib import EnvBasedTC -from cubicweb.vregistry import Selector, AndSelector, OrSelector +from cubicweb.appobject import Selector, AndSelector, OrSelector from cubicweb.selectors import implements, match_user_groups from cubicweb.interfaces import IDownloadable from cubicweb.web import action @@ -91,7 +91,7 @@ class ImplementsSelectorTC(EnvBasedTC): def test_etype_priority(self): req = self.request() - cls = self.vreg.etype_class('File') + cls = self.vreg['etypes'].etype_class('File') anyscore = implements('Any').score_class(cls, req) idownscore = implements(IDownloadable).score_class(cls, req) self.failUnless(idownscore > anyscore, (idownscore, anyscore)) @@ -99,7 +99,7 @@ self.failUnless(filescore > idownscore, (filescore, idownscore)) def test_etype_inheritance_no_yams_inheritance(self): - cls = self.vreg.etype_class('Personne') + cls = self.vreg['etypes'].etype_class('Personne') self.failIf(implements('Societe').score_class(cls, self.request())) @@ -111,7 +111,7 @@ category = 'foo' __select__ = match_user_groups('owners') self.vreg._loadedmods[__name__] = {} - self.vreg.register_vobject_class(SomeAction) + self.vreg.register_appobject_class(SomeAction) self.failUnless(SomeAction in self.vreg['actions']['yo'], self.vreg['actions']) try: # login as a simple user diff -r ff6114c2c416 -r f84ba1a66abb test/unittest_vregistry.py --- a/test/unittest_vregistry.py Tue Aug 04 15:06:09 2009 +0200 +++ b/test/unittest_vregistry.py Tue Aug 04 15:08:18 2009 +0200 @@ -10,8 +10,8 @@ from os.path import join from cubicweb import CW_SOFTWARE_ROOT as BASE -from cubicweb.vregistry import VObject -from cubicweb.cwvreg import CubicWebRegistry, UnknownProperty +from cubicweb.appobject import AppObject +from cubicweb.cwvreg import CubicWebVRegistry, UnknownProperty from cubicweb.devtools import TestServerConfiguration from cubicweb.interfaces import IMileStone @@ -27,7 +27,7 @@ def setUp(self): config = TestServerConfiguration('data') - self.vreg = CubicWebRegistry(config) + self.vreg = CubicWebVRegistry(config) config.bootstrap_cubes() self.vreg.schema = config.load_schema() @@ -43,7 +43,7 @@ def test___selectors__compat(self): myselector1 = lambda *args: 1 myselector2 = lambda *args: 1 - class AnAppObject(VObject): + class AnAppObject(AppObject): __selectors__ = (myselector1, myselector2) AnAppObject.build___select__() self.assertEquals(AnAppObject.__select__(AnAppObject), 2) @@ -53,7 +53,7 @@ self.failUnless(self.vreg.property_info('system.version.cubicweb')) self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key') - def test_load_subinterface_based_vobjects(self): + def test_load_subinterface_based_appobjects(self): self.vreg.reset() self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')]) # check progressbar was kicked @@ -62,7 +62,7 @@ __implements__ = (IMileStone,) self.vreg.reset() self.vreg._loadedmods[__name__] = {} - self.vreg.register_vobject_class(MyCard) + self.vreg.register_appobject_class(MyCard) self.vreg.register_objects([join(BASE, 'entities', '__init__.py'), join(BASE, 'web', 'views', 'iprogress.py')]) # check progressbar isn't kicked diff -r ff6114c2c416 -r f84ba1a66abb utils.py --- a/utils.py Tue Aug 04 15:06:09 2009 +0200 +++ b/utils.py Tue Aug 04 15:08:18 2009 +0200 @@ -321,7 +321,7 @@ class AcceptMixIn(object): - """Mixin class for vobjects defining the 'accepts' attribute describing + """Mixin class for appobjects defining the 'accepts' attribute describing a set of supported entity type (Any by default). """ # XXX deprecated, no more necessary diff -r ff6114c2c416 -r f84ba1a66abb view.py --- a/view.py Tue Aug 04 15:06:09 2009 +0200 +++ b/view.py Tue Aug 04 15:08:18 2009 +0200 @@ -18,7 +18,7 @@ from cubicweb import NotAnEntity from cubicweb.selectors import yes, non_final_entity, nonempty_rset, none_rset from cubicweb.selectors import require_group_compat, accepts_compat -from cubicweb.appobject import AppRsetObject +from cubicweb.appobject import AppObject from cubicweb.utils import UStringIO, HTMLStream from cubicweb.schema import display_name @@ -73,7 +73,7 @@ # base view object ############################################################ -class View(AppRsetObject): +class View(AppObject): """abstract view class, used as base for every renderable object such as views, templates, some components...web @@ -93,7 +93,7 @@ time to a write function to use. """ __registry__ = 'views' - registered = require_group_compat(AppRsetObject.registered) + registered = require_group_compat(AppObject.registered) templatable = True need_navigation = True diff -r ff6114c2c416 -r f84ba1a66abb vregistry.py --- a/vregistry.py Tue Aug 04 15:06:09 2009 +0200 +++ b/vregistry.py Tue Aug 04 15:08:18 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,15 +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 cubicweb import CW_SOFTWARE_ROOT, set_log_methods +from logilab.common.deprecation import deprecated, class_moved +from logilab.common.logging_ext import 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 @@ -58,179 +61,117 @@ 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__) +class Registry(dict): - # XXX bw compat code - @classmethod - def build___select__(cls): - for klass in cls.mro(): - if klass.__name__ == 'AppRsetObject': - 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 - + def __init__(self, config): + super(Registry, self).__init__() + self.config = config -class VRegistry(object): - """class responsible to register, propose and select the various - elements used to build the web interface. Currently, we have templates, - views, actions and components. - """ - - def __init__(self, config):#, cache_size=1000): - self.config = config - # dictionnary of registry (themself dictionnary) by name - self._registries = {} - self._lastmodifs = {} - - def reset(self): - self._registries = {} - self._lastmodifs = {} - if uicfg is not None: - reload(uicfg) - - def __getitem__(self, key): - return self._registries[key] - - def get(self, key, default=None): - return self._registries.get(key, default) - - def items(self): - return self._registries.items() - - def values(self): - return self._registries.values() - - def __contains__(self, key): - return key in self._registries - - def registry(self, name): + def __getitem__(self, name): """return the registry (dictionary of class objects) associated to this name """ try: - return self._registries[name] + return super(Registry, self).__getitem__(name) except KeyError: - raise RegistryNotFound(name), None, sys.exc_info()[-1] + raise ObjectNotFound(name), None, sys.exc_info()[-1] + + def register(self, obj, oid=None, clear=False): + """base method to add an object in the registry""" + assert not '__abstract__' in obj.__dict__ + oid = oid or obj.id + assert oid + if clear: + appobjects = self[oid] = [] + else: + appobjects = self.setdefault(oid, []) + # registered() is technically a classmethod but is not declared + # as such because we need to compose registered in some cases + 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 registry_objects(self, name, oid=None): - """returns objects registered with the given oid in the given registry. - If no oid is given, return all objects in this registry + def register_and_replace(self, obj, replaced): + # XXXFIXME this is a duplication of unregister() + # remove register_and_replace in favor of unregister + register + # or simplify by calling unregister then register here + if hasattr(replaced, 'classid'): + replaced = replaced.classid() + registered_objs = self.get(obj.id, ()) + for index, registered in enumerate(registered_objs): + if registered.classid() == replaced: + del registered_objs[index] + break + else: + self.warning('trying to replace an unregistered view %s by %s', + replaced, obj) + self.register(obj) + + def unregister(self, obj): + oid = obj.classid() + for registered in self.get(obj.id, ()): + # use classid() to compare classes because vreg will probably + # have its own version of the class, loaded through execfile + if registered.classid() == oid: + # XXX automatic reloading management + self[obj.id].remove(registered) + break + else: + self.warning('can\'t remove %s, no id %s in the registry', + oid, obj.id) + + def all_objects(self): + """return a list containing all objects in this registry. """ - registry = self.registry(name) - if oid is not None: - try: - return registry[oid] - except KeyError: - raise ObjectNotFound(oid), None, sys.exc_info()[-1] result = [] - for objs in registry.values(): + for objs in self.values(): result += objs return result # dynamic selection methods ################################################ - def object_by_id(self, registry, oid, *args, **kwargs): - """return object in . + def object_by_id(self, oid, *args, **kwargs): + """return object with the given oid. Only one object is expected to be + found. raise `ObjectNotFound` if not object with id in raise `AssertionError` if there is more than one object there """ - objects = self.registry_objects(registry, oid) + objects = self[oid] assert len(objects) == 1, objects - return objects[0].selected(*args, **kwargs) + return objects[0](*args, **kwargs) - def select(self, registry, oid, *args, **kwargs): - """return the most specific object in . according to - the given context + def select(self, oid, *args, **kwargs): + """return the most specific object among those with the given oid + according to the given context. raise `ObjectNotFound` if not object with id in raise `NoSelectableObject` if not object apply """ - return self.select_best(self.registry_objects(registry, oid), - *args, **kwargs) + return self.select_best(self[oid], *args, **kwargs) - def select_object(self, registry, oid, *args, **kwargs): - """return the most specific object in . according to - the given context, or None if no object apply + def select_object(self, oid, *args, **kwargs): + """return the most specific object among those with the given oid + according to the given context, or None if no object applies. """ try: - return self.select(registry, oid, *args, **kwargs) + return self.select(oid, *args, **kwargs) except (NoSelectableObject, ObjectNotFound): return None - def possible_objects(self, registry, *args, **kwargs): - """return an iterator on possible objects in for the given + def possible_objects(self, *args, **kwargs): + """return an iterator on possible objects in this registry for the given context """ - for vobjects in self.registry(registry).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 @@ -240,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', @@ -258,11 +199,92 @@ 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 winners[0].selected(*args, **kwargs) + # return the result of calling the appobject + return winners[0](*args, **kwargs) + + +class VRegistry(dict): + """class responsible to register, propose and select the various + elements used to build the web interface. Currently, we have templates, + views, actions and components. + """ + + def __init__(self, config): + super(VRegistry, self).__init__() + self.config = config + + def reset(self, force_reload=None): + self.clear() + self._lastmodifs = {} + # don't reload uicfg when appobjects modules won't be reloaded as well + if uicfg is not None: + if force_reload is None: + force_reload = self.config.mode == 'dev' + if force_reload: + reload(uicfg) + + def __getitem__(self, name): + """return the registry (dictionary of class objects) associated to + this name + """ + try: + return super(VRegistry, self).__getitem__(name) + except KeyError: + raise RegistryNotFound(name), None, sys.exc_info()[-1] + + # dynamic selection methods ################################################ + + @deprecated('use vreg[registry].object_by_id(oid, *args, **kwargs)') + def object_by_id(self, registry, oid, *args, **kwargs): + """return object in . + + raise `ObjectNotFound` if not object with id in + raise `AssertionError` if there is more than one object there + """ + return self[registry].object_by_id(oid) + + @deprecated('use vreg[registry].select(oid, *args, **kwargs)') + def select(self, registry, oid, *args, **kwargs): + """return the most specific object in . according to + the given context + + raise `ObjectNotFound` if not object with id in + raise `NoSelectableObject` if not object apply + """ + return self[registry].select(oid, *args, **kwargs) + + @deprecated('use vreg[registry].select_object(oid, *args, **kwargs)') + def select_object(self, registry, oid, *args, **kwargs): + """return the most specific object in . according to + the given context, or None if no object apply + """ + return self[registry].select_object(oid, *args, **kwargs) + + @deprecated('use vreg[registry].possible_objects(*args, **kwargs)') + def possible_objects(self, registry, *args, **kwargs): + """return an iterator on possible objects in for the given + context + """ + return self[registry].possible_objects(*args, **kwargs) # methods for explicit (un)registration ################################### + # default class, when no specific class set + REGISTRY_FACTORY = {None: Registry} + + def registry_class(self, regid): + try: + return self.REGISTRY_FACTORY[regid] + except KeyError: + return self.REGISTRY_FACTORY[None] + + def setdefault(self, regid): + try: + return self[regid] + except KeyError: + self[regid] = self.registry_class(regid)(self.config) + return self[regid] + # def clear(self, key): # regname, oid = key.split('.') # self[regname].pop(oid, None) @@ -282,62 +304,23 @@ """base method to add an object in the registry""" assert not '__abstract__' in obj.__dict__ registryname = registryname or obj.__registry__ - oid = oid or obj.id - assert oid - registry = self._registries.setdefault(registryname, {}) - if clear: - vobjects = registry[oid] = [] - else: - vobjects = registry.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) + registry = self.setdefault(registryname) + registry.register(obj, oid=oid, clear=clear) try: - vname = vobject.__name__ + vname = obj.__name__ except AttributeError: - vname = vobject.__class__.__name__ - self.debug('registered vobject %s in registry %s with id %s', + vname = obj.__class__.__name__ + self.debug('registered appobject %s in registry %s with id %s', vname, registryname, oid) self._loadedmods[obj.__module__]['%s.%s' % (obj.__module__, oid)] = obj def unregister(self, obj, registryname=None): - registryname = registryname or obj.__registry__ - registry = self.registry(registryname) - removed_id = obj.classid() - for registered in registry.get(obj.id, ()): - # use classid() to compare classes because vreg will probably - # have its own version of the class, loaded through execfile - if registered.classid() == removed_id: - # XXX automatic reloading management - registry[obj.id].remove(registered) - break - else: - self.warning('can\'t remove %s, no id %s in the %s registry', - removed_id, obj.id, registryname) + self[registryname or obj.__registry__].unregister(obj) def register_and_replace(self, obj, replaced, registryname=None): - # XXXFIXME this is a duplication of unregister() - # remove register_and_replace in favor of unregister + register - # or simplify by calling unregister then register here - if hasattr(replaced, 'classid'): - replaced = replaced.classid() - registryname = registryname or obj.__registry__ - registry = self.registry(registryname) - registered_objs = registry.get(obj.id, ()) - for index, registered in enumerate(registered_objs): - if registered.classid() == replaced: - del registry[obj.id][index] - break - else: - self.warning('trying to replace an unregistered view %s by %s', - replaced, obj) - self.register(obj, registryname=registryname) + self[registryname or obj.__registry__].register_and_replace(obj, replaced) - # intialization methods ################################################### + # initialization methods ################################################### def init_registration(self, path, extrapath=None): # compute list of all modules that have to be loaded @@ -421,7 +404,7 @@ return # skip non registerable object try: - if not issubclass(obj, VObject): + if not issubclass(obj, AppObject): return except TypeError: return @@ -435,20 +418,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] == '_' @@ -460,169 +443,19 @@ self.register(cls) # init logging -set_log_methods(VObject, getLogger('cubicweb')) -set_log_methods(VRegistry, 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__() +set_log_methods(VRegistry, getLogger('cubicweb.vreg')) +set_log_methods(Registry, getLogger('cubicweb.registry')) # 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 @@ -635,6 +468,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 diff -r ff6114c2c416 -r f84ba1a66abb web/action.py --- a/web/action.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/action.py Tue Aug 04 15:08:18 2009 +0200 @@ -11,12 +11,12 @@ from cubicweb.selectors import (partial_relation_possible, match_search_state, one_line_rset, partial_may_add_relation, yes, accepts_compat, condition_compat, deprecate) -from cubicweb.appobject import AppRsetObject +from cubicweb.appobject import AppObject _ = unicode -class Action(AppRsetObject): +class Action(AppObject): """abstract action. Handle the .search_states attribute to match request search state. """ diff -r ff6114c2c416 -r f84ba1a66abb web/application.py --- a/web/application.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/application.py Tue Aug 04 15:08:18 2009 +0200 @@ -41,7 +41,7 @@ if self.session_time: assert self.cleanup_session_time < self.session_time assert self.cleanup_anon_session_time < self.session_time - self.authmanager = self.vreg.select('components', 'authmanager') + self.authmanager = self.vreg['components'].select('authmanager') def clean_sessions(self): """cleanup sessions which has not been unused since a given amount of @@ -112,7 +112,7 @@ SESSION_VAR = '__session' def __init__(self, appli): - self.session_manager = appli.vreg.select('components', 'sessionmanager') + self.session_manager = appli.vreg['components'].select('sessionmanager') global SESSION_MANAGER SESSION_MANAGER = self.session_manager if not 'last_login_time' in appli.vreg.schema: @@ -220,7 +220,7 @@ super(CubicWebPublisher, self).__init__() # connect to the repository and get instance's schema if vreg is None: - vreg = cwvreg.CubicWebRegistry(config, debug=debug) + vreg = cwvreg.CubicWebVRegistry(config, debug=debug) self.vreg = vreg self.info('starting web instance from %s', config.apphome) self.repo = config.repository(vreg) @@ -239,7 +239,7 @@ self.publish = self.main_publish # instantiate session and url resolving helpers self.session_handler = session_handler_fact(self) - self.url_resolver = vreg.select('components', 'urlpublisher') + self.url_resolver = vreg['components'].select('urlpublisher') def connect(self, req): """return a connection for a logged user object according to existing @@ -275,7 +275,7 @@ @deprecated("use vreg.select('controllers', ...)") def select_controller(self, oid, req): try: - return self.vreg.select('controllers', oid, req=req, appli=self) + return self.vreg['controllers'].select(oid, req=req, appli=self) except NoSelectableObject: raise Unauthorized(req._('not authorized')) @@ -304,8 +304,8 @@ try: ctrlid, rset = self.url_resolver.process(req, path) try: - controller = self.vreg.select('controllers', ctrlid, req, - appli=self) + controller = self.vreg['controllers'].select(ctrlid, req, + appli=self) except NoSelectableObject: raise Unauthorized(req._('not authorized')) req.update_search_state() @@ -375,28 +375,28 @@ if tb: req.data['excinfo'] = excinfo req.form['vid'] = 'error' - errview = self.vreg.select('views', 'error', req) + errview = self.vreg['views'].select('error', req) template = self.main_template_id(req) - content = self.vreg.main_template(req, template, view=errview) + content = self.vreg['views'].main_template(req, template, view=errview) except: - content = self.vreg.main_template(req, 'error-template') + content = self.vreg['views'].main_template(req, 'error-template') raise StatusResponse(500, content) def need_login_content(self, req): - return self.vreg.main_template(req, 'login') + return self.vreg['views'].main_template(req, 'login') def loggedout_content(self, req): - return self.vreg.main_template(req, 'loggedout') + return self.vreg['views'].main_template(req, 'loggedout') def notfound_content(self, req): req.form['vid'] = '404' - view = self.vreg.select('views', '404', req) + view = self.vreg['views'].select('404', req) template = self.main_template_id(req) - return self.vreg.main_template(req, template, view=view) + return self.vreg['views'].main_template(req, template, view=view) def main_template_id(self, req): template = req.form.get('__template', req.property_value('ui.main-template')) - if template not in self.vreg.registry('views'): + if template not in self.vreg['views']: template = 'main-template' return template diff -r ff6114c2c416 -r f84ba1a66abb web/controller.py --- a/web/controller.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/controller.py Tue Aug 04 15:08:18 2009 +0200 @@ -71,6 +71,7 @@ registered = require_group_compat(AppObject.registered) def __init__(self, *args, **kwargs): + self.appli = kwargs.pop('appli', None) super(Controller, self).__init__(*args, **kwargs) # attributes use to control after edition redirection self._after_deletion_path = None @@ -92,7 +93,7 @@ self.ensure_ro_rql(rql) if not isinstance(rql, unicode): rql = unicode(rql, self.req.encoding) - pp = self.vreg.select_object('components', 'magicsearch', self.req) + pp = self.vreg['components'].select_object('magicsearch', self.req) if pp is not None: self.rset = pp.process_query(rql, self.req) return self.rset diff -r ff6114c2c416 -r f84ba1a66abb web/facet.py --- a/web/facet.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/facet.py Tue Aug 04 15:08:18 2009 +0200 @@ -24,7 +24,7 @@ from cubicweb.schema import display_name from cubicweb.utils import datetime2ticks, make_uid, ustrftime from cubicweb.selectors import match_context_prop, partial_relation_possible -from cubicweb.appobject import AppRsetObject +from cubicweb.appobject import AppObject from cubicweb.web.htmlwidgets import HTMLWidget ## rqlst manipulation functions used by facets ################################ @@ -64,8 +64,8 @@ def get_facet(req, facetid, rqlst, mainvar): - return req.vreg.object_by_id('facets', facetid, req, rqlst=rqlst, - filtered_variable=mainvar) + return req.vreg['facets'].object_by_id(facetid, req, rqlst=rqlst, + filtered_variable=mainvar) def filter_hiddens(w, **kwargs): @@ -241,7 +241,7 @@ ## base facet classes ######################################################### -class AbstractFacet(AppRsetObject): +class AbstractFacet(AppObject): __abstract__ = True __registry__ = 'facets' property_defs = { @@ -259,22 +259,18 @@ needs_update = False start_unfolded = True - @classmethod - def selected(cls, req, rset=None, rqlst=None, context=None, - filtered_variable=None): + def __init__(self, req, rset=None, rqlst=None, filtered_variable=None, + **kwargs): + super(AbstractFacet, self).__init__(req, rset, **kwargs) assert rset is not None or rqlst is not None assert filtered_variable - instance = super(AbstractFacet, cls).selected(req, rset) - #instance = AppRsetObject.selected(req, rset) - #instance.__class__ = cls # facet retreived using `object_by_id` from an ajax call if rset is None: - instance.init_from_form(rqlst=rqlst) + self.init_from_form(rqlst=rqlst) # facet retreived from `select` using the result set to filter else: - instance.init_from_rset() - instance.filtered_variable = filtered_variable - return instance + self.init_from_rset() + self.filtered_variable = filtered_variable def init_from_rset(self): self.rqlst = self.rset.syntax_tree().children[0] diff -r ff6114c2c416 -r f84ba1a66abb web/form.py --- a/web/form.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/form.py Tue Aug 04 15:08:18 2009 +0200 @@ -7,7 +7,7 @@ """ __docformat__ = "restructuredtext en" -from cubicweb.appobject import AppRsetObject +from cubicweb.appobject import AppObject from cubicweb.view import NOINDEX, NOFOLLOW from cubicweb.common import tags from cubicweb.web import stdmsgs, httpcache, formfields @@ -202,6 +202,6 @@ found """ -class Form(FormMixIn, AppRsetObject): +class Form(FormMixIn, AppObject): __metaclass__ = metafieldsform __registry__ = 'forms' diff -r ff6114c2c416 -r f84ba1a66abb web/request.py --- a/web/request.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/request.py Tue Aug 04 15:08:18 2009 +0200 @@ -539,8 +539,7 @@ def from_controller(self): """return the id (string) of the controller issuing the request""" controller = self.relative_path(False).split('/', 1)[0] - registered_controllers = (ctrl.id for ctrl in - self.vreg.registry_objects('controllers')) + registered_controllers = self.vreg['controllers'].keys() if controller in registered_controllers: return controller return 'view' diff -r ff6114c2c416 -r f84ba1a66abb web/test/test_views.py --- a/web/test/test_views.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/test_views.py Tue Aug 04 15:08:18 2009 +0200 @@ -52,7 +52,7 @@ def test_js_added_only_once(self): self.vreg._loadedmods[__name__] = {} - self.vreg.register_vobject_class(SomeView) + self.vreg.register_appobject_class(SomeView) rset = self.execute('CWUser X') source = self.view('someview', rset).source self.assertEquals(source.count('spam.js'), 1) diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_application.py --- a/web/test/unittest_application.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_application.py Tue Aug 04 15:08:18 2009 +0200 @@ -7,16 +7,17 @@ :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses """ -from logilab.common.testlib import TestCase, unittest_main import base64, Cookie - import sys from urllib import unquote + +from logilab.common.testlib import TestCase, unittest_main from logilab.common.decorators import clear_cache +from cubicweb.devtools.apptest import EnvBasedTC +from cubicweb.devtools.fake import FakeRequest from cubicweb.web import Redirect, AuthenticationError, ExplicitLogin, INTERNAL_FIELD_VALUE from cubicweb.web.views.basecontrollers import ViewController -from cubicweb.devtools._apptest import FakeRequest class FakeMapping: """emulates a mapping module""" @@ -133,9 +134,6 @@ for i in (12, 13, 14)]) -from cubicweb.devtools.apptest import EnvBasedTC - - class ApplicationTC(EnvBasedTC): def publish(self, req, path='view'): diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_form.py --- a/web/test/unittest_form.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_form.py Tue Aug 04 15:08:18 2009 +0200 @@ -91,7 +91,7 @@ e.req = self.req geid = self.execute('CWGroup X WHERE X name "users"')[0][0] self.req.form['__linkto'] = 'in_group:%s:subject' % geid - form = self.vreg.select('forms', 'edition', self.req, entity=e) + form = self.vreg['forms'].select('edition', self.req, entity=e) form.content_type = 'text/html' pageinfo = self._check_html(form.form_render(), form, template=None) inputs = pageinfo.find_tag('select', False) @@ -101,8 +101,8 @@ def test_reledit_composite_field(self): rset = self.execute('INSERT BlogEntry X: X title "cubicweb.org", X content "hop"') - form = self.vreg.select_object('views', 'reledit', self.request(), - rset=rset, row=0, rtype='content') + form = self.vreg['views'].select('reledit', self.request(), + rset=rset, row=0, rtype='content') data = form.render(row=0, rtype='content') self.failUnless('edits-content' in data) self.failUnless('edits-content_format' in data) diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_magicsearch.py --- a/web/test/unittest_magicsearch.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_magicsearch.py Tue Aug 04 15:08:18 2009 +0200 @@ -44,7 +44,7 @@ super(QueryTranslatorTC, self).setUp() self.req = self.env.create_request() self.vreg.config.translations = {'en': _translate} - proc = self.vreg.select('components', 'magicsearch', self.req) + proc = self.vreg['components'].select('magicsearch', self.req) self.proc = [p for p in proc.processors if isinstance(p, QueryTranslator)][0] def test_basic_translations(self): @@ -69,7 +69,7 @@ super(QSPreProcessorTC, self).setUp() self.vreg.config.translations = {'en': _translate} self.req = self.request() - proc = self.vreg.select('components', 'magicsearch', self.req) + proc = self.vreg['components'].select('magicsearch', self.req) self.proc = [p for p in proc.processors if isinstance(p, QSPreProcessor)][0] self.proc.req = self.req @@ -187,7 +187,7 @@ super(ProcessorChainTC, self).setUp() self.vreg.config.translations = {'en': _translate} self.req = self.request() - self.proc = self.vreg.select('components', 'magicsearch', self.req) + self.proc = self.vreg['components'].select('magicsearch', self.req) def test_main_preprocessor_chain(self): """tests QUERY_PROCESSOR""" diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_actions.py --- a/web/test/unittest_views_actions.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_actions.py Tue Aug 04 15:08:18 2009 +0200 @@ -13,19 +13,19 @@ def test_view_action(self): req = self.request(__message='bla bla bla', vid='rss', rql='CWUser X') rset = self.execute('CWUser X') - vaction = [action for action in self.vreg.possible_vobjects('actions', req, rset=rset) + vaction = [action for action in self.vreg['actions'].possible_vobjects(req, rset=rset) if action.id == 'view'][0] self.assertEquals(vaction.url(), 'http://testing.fr/cubicweb/view?rql=CWUser%20X') def test_sendmail_action(self): req = self.request() rset = self.execute('Any X WHERE X login "admin"', req=req) - self.failUnless([action for action in self.vreg.possible_vobjects('actions', req, rset=rset) + self.failUnless([action for action in self.vreg['actions'].possible_vobjects(req, rset=rset) if action.id == 'sendemail']) self.login('anon') req = self.request() rset = self.execute('Any X WHERE X login "anon"', req=req) - self.failIf([action for action in self.vreg.possible_vobjects('actions', req, rset=rset) + self.failIf([action for action in self.vreg['actions'].possible_vobjects(req, rset=rset) if action.id == 'sendemail']) if __name__ == '__main__': diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_basecontrollers.py --- a/web/test/unittest_views_basecontrollers.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_basecontrollers.py Tue Aug 04 15:08:18 2009 +0200 @@ -496,7 +496,7 @@ # updated (which is what happened before this test) req = self.request() req.form['url'] = 'http://intranet.logilab.fr/' - controller = self.vreg.select('controllers', 'embed', req) + controller = self.vreg['controllers'].select('embed', req) result = controller.publish(rset=None) @@ -504,7 +504,7 @@ def test_usable_by_guets(self): req = self.request() - self.vreg.select('controllers', 'reportbug', req) + self.vreg['controllers'].select('reportbug', req) class SendMailControllerTC(EnvBasedTC): @@ -512,7 +512,7 @@ def test_not_usable_by_guets(self): self.login('anon') req = self.request() - self.assertRaises(NoSelectableObject, self.env.vreg.select, 'controllers', 'sendmail', req) + self.assertRaises(NoSelectableObject, self.env.vreg['controllers'].select, 'sendmail', req) @@ -520,7 +520,7 @@ def ctrl(self, req=None): req = req or self.request(url='http://whatever.fr/') - return self.vreg.select('controllers', 'json', req) + return self.vreg['controllers'].select('json', req) def setup_database(self): self.pytag = self.add_entity('Tag', name=u'python') diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_basetemplates.py --- a/web/test/unittest_views_basetemplates.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_basetemplates.py Tue Aug 04 15:08:18 2009 +0200 @@ -13,7 +13,7 @@ def _login_labels(self): valid = self.content_type_validators.get('text/html', DTDValidator)() - page = valid.parse_string(self.vreg.main_template(self.request(), 'login')) + page = valid.parse_string(self.vreg['views'].main_template(self.request(), 'login')) return page.find_tag('label') def test_label(self): diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_baseviews.py --- a/web/test/unittest_views_baseviews.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_baseviews.py Tue Aug 04 15:08:18 2009 +0200 @@ -91,7 +91,7 @@ rset = self.execute('Any X, D, CD, NOW - CD WHERE X is State, X description D, X creation_date CD, X eid %(x)s', {'x': e.eid}, 'x') req = self.request() - view = self.vreg.select('views', 'table', req, rset=rset) + view = self.vreg['views'].select('table', req, rset=rset) return e, rset, view def test_headers(self): diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_editforms.py --- a/web/test/unittest_views_editforms.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_editforms.py Tue Aug 04 15:08:18 2009 +0200 @@ -18,8 +18,8 @@ def test_custom_widget(self): AEF.rfields_kwargs.tag_subject_of(('CWUser', 'login', '*'), {'widget': AutoCompletionWidget(autocomplete_initfunc='get_logins')}) - form = self.vreg.select('forms', 'edition', self.request(), - entity=self.user()) + form = self.vreg['forms'].select('edition', self.request(), + entity=self.user()) field = form.field_by_name('login') self.assertIsInstance(field.widget, AutoCompletionWidget) AEF.rfields_kwargs.del_rtag('CWUser', 'login', '*', 'subject') @@ -116,10 +116,10 @@ def test_edition_form(self): rset = self.execute('CWUser X LIMIT 1') - form = self.vreg.select('forms', 'edition', rset.req, rset=rset, + form = self.vreg['forms'].select('edition', rset.req, rset=rset, row=0, col=0) # should be also selectable by specifying entity - self.vreg.select('forms', 'edition', rset.req, + self.vreg['forms'].select('edition', rset.req, entity=rset.get_entity(0, 0)) self.failIf(any(f for f in form.fields if f is None)) diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_navigation.py --- a/web/test/unittest_views_navigation.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_navigation.py Tue Aug 04 15:08:18 2009 +0200 @@ -19,31 +19,31 @@ def test_navigation_selection(self): rset = self.execute('Any X,N WHERE X name N') req = self.request() - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) self.assertIsInstance(navcomp, PageNavigation) req.set_search_state('W:X:Y:Z') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) self.assertIsInstance(navcomp, PageNavigation) req.set_search_state('normal') rset = self.execute('Any X,N ORDERBY N WHERE X name N') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) self.assertIsInstance(navcomp, SortedNavigation) req.set_search_state('W:X:Y:Z') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) self.assertIsInstance(navcomp, SortedNavigation) req.set_search_state('normal') rset = self.execute('Any X,N LIMIT 10 WHERE X name N') - navcomp = self.vreg.select_object('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select_object('navigation', req, rset=rset) self.assertEquals(navcomp, None) req.set_search_state('W:X:Y:Z') - navcomp = self.vreg.select_object('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select_object('navigation', req, rset=rset) self.assertEquals(navcomp, None) req.set_search_state('normal') rset = self.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N WHERE RDEF relation_type RT, RT name N') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) self.assertIsInstance(navcomp, SortedNavigation) req.set_search_state('W:X:Y:Z') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) self.assertIsInstance(navcomp, SortedNavigation) @@ -51,22 +51,22 @@ rset = self.execute('Any X,N ORDERBY N WHERE X name N') req = self.request() req.set_search_state('W:X:Y:Z') - navcomp = self.vreg.select('components', 'navigation', rset.req, rset=rset) + navcomp = self.vreg['components'].select('navigation', rset.req, rset=rset) html = navcomp.render() rset = self.execute('Any RDEF ORDERBY RT WHERE RDEF relation_type RT') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) html = navcomp.render() rset = self.execute('Any RDEF ORDERBY RDEF WHERE RDEF relation_type RT') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) html = navcomp.render() rset = self.execute('CWAttribute RDEF ORDERBY RDEF') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) html = navcomp.render() rset = self.execute('Any RDEF ORDERBY N WHERE RDEF relation_type RT, RT name N') - navcomp = self.vreg.select('components', 'navigation', req, rset=rset) + navcomp = self.vreg['components'].select('navigation', req, rset=rset) html = navcomp.render() rset = self.execute('Any N, COUNT(RDEF) GROUPBY N ORDERBY N WHERE RDEF relation_type RT, RT name N') - navcomp = self.vreg.select('components', 'navigation', rset.req, rset=rset) + navcomp = self.vreg['components'].select('navigation', rset.req, rset=rset) html = navcomp.render() @@ -77,12 +77,12 @@ view = mock_object(is_primary=lambda x: True) rset = self.execute('CWUser X LIMIT 1') req = self.request() - objs = self.vreg.possible_vobjects('contentnavigation', req, rset=rset, + objs = self.vreg['contentnavigation'].possible_vobjects(req, rset=rset, view=view, context='navtop') # breadcrumbs should be in headers by default clsids = set(obj.id for obj in objs) self.failUnless('breadcrumbs' in clsids) - objs = self.vreg.possible_vobjects('contentnavigation', req, rset=rset, + objs = self.vreg['contentnavigation'].possible_vobjects(req, rset=rset, view=view, context='navbottom') # breadcrumbs should _NOT_ be in footers by default clsids = set(obj.id for obj in objs) @@ -91,12 +91,12 @@ 'P value "navbottom"') # breadcrumbs should now be in footers req.cnx.commit() - objs = self.vreg.possible_vobjects('contentnavigation', req, rset=rset, + objs = self.vreg['contentnavigation'].possible_vobjects(req, rset=rset, view=view, context='navbottom') clsids = [obj.id for obj in objs] self.failUnless('breadcrumbs' in clsids) - objs = self.vreg.possible_vobjects('contentnavigation', req, rset=rset, + objs = self.vreg['contentnavigation'].possible_vobjects(req, rset=rset, view=view, context='navtop') clsids = [obj.id for obj in objs] diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_views_pyviews.py --- a/web/test/unittest_views_pyviews.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_views_pyviews.py Tue Aug 04 15:08:18 2009 +0200 @@ -4,9 +4,9 @@ class PyViewsTC(EnvBasedTC): def test_pyvaltable(self): - content = self.vreg.render('pyvaltable', self.request(), - pyvalue=[[1, 'a'], [2, 'b']], - headers=['num', 'char']) + content = self.vreg['views'].render('pyvaltable', self.request(), + pyvalue=[[1, 'a'], [2, 'b']], + headers=['num', 'char']) self.assertEquals(content.strip(), ''' @@ -14,8 +14,8 @@
numchar
1a
''') def test_pyvallist(self): - content = self.vreg.render('pyvallist', self.request(), - pyvalue=[1, 'a']) + content = self.vreg['views'].render('pyvallist', self.request(), + pyvalue=[1, 'a']) self.assertEquals(content.strip(), '''
  • 1
  • a
  • diff -r ff6114c2c416 -r f84ba1a66abb web/test/unittest_viewselector.py --- a/web/test/unittest_viewselector.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/test/unittest_viewselector.py Tue Aug 04 15:08:18 2009 +0200 @@ -35,7 +35,7 @@ self.add_entity('Tag', name=u'x') def pactions(self, req, rset): - resdict = self.vreg.possible_actions(req, rset) + resdict = self.vreg['actions'].possible_actions(req, rset) for cat, actions in resdict.items(): resdict[cat] = [(a.id, a.__class__) for a in actions] return resdict @@ -132,26 +132,26 @@ assert self.vreg['views']['propertiesform'] rset1, req1 = self.env.get_rset_and_req('CWUser X WHERE X login "admin"') rset2, req2 = self.env.get_rset_and_req('CWUser X WHERE X login "anon"') - self.failUnless(self.vreg.select('views', 'propertiesform', req1, rset=None)) - self.failUnless(self.vreg.select('views', 'propertiesform', req1, rset=rset1)) - self.failUnless(self.vreg.select('views', 'propertiesform', req2, rset=rset2)) + self.failUnless(self.vreg['views'].select('propertiesform', req1, rset=None)) + self.failUnless(self.vreg['views'].select('propertiesform', req1, rset=rset1)) + self.failUnless(self.vreg['views'].select('propertiesform', req2, rset=rset2)) def test_propertiesform_anon(self): self.login('anon') rset1, req1 = self.env.get_rset_and_req('CWUser X WHERE X login "admin"') rset2, req2 = self.env.get_rset_and_req('CWUser X WHERE X login "anon"') - self.assertRaises(NoSelectableObject, self.vreg.select, 'views', 'propertiesform', req1, rset=None) - self.assertRaises(NoSelectableObject, self.vreg.select, 'views', 'propertiesform', req1, rset=rset1) - self.assertRaises(NoSelectableObject, self.vreg.select, 'views', 'propertiesform', req1, rset=rset2) + self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'propertiesform', req1, rset=None) + self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'propertiesform', req1, rset=rset1) + self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'propertiesform', req1, rset=rset2) def test_propertiesform_jdoe(self): self.create_user('jdoe') self.login('jdoe') rset1, req1 = self.env.get_rset_and_req('CWUser X WHERE X login "admin"') rset2, req2 = self.env.get_rset_and_req('CWUser X WHERE X login "jdoe"') - self.failUnless(self.vreg.select('views', 'propertiesform', req1, rset=None)) - self.assertRaises(NoSelectableObject, self.vreg.select, 'views', 'propertiesform', req1, rset=rset1) - self.failUnless(self.vreg.select('views', 'propertiesform', req2, rset=rset2)) + self.failUnless(self.vreg['views'].select('propertiesform', req1, rset=None)) + self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'propertiesform', req1, rset=rset1) + self.failUnless(self.vreg['views'].select('propertiesform', req2, rset=rset2)) def test_possible_views_multiple_different_types(self): rset, req = self.env.get_rset_and_req('Any X') @@ -267,103 +267,103 @@ req = self.request() # creation form req.form['etype'] = 'CWGroup' - self.assertIsInstance(self.vreg.select('views', 'creation', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('creation', req, rset=rset), editforms.CreationFormView) del req.form['etype'] # custom creation form class CWUserCreationForm(editforms.CreationFormView): __select__ = specified_etype_implements('CWUser') self.vreg._loadedmods[__name__] = {} - self.vreg.register_vobject_class(CWUserCreationForm) + self.vreg.register_appobject_class(CWUserCreationForm) req.form['etype'] = 'CWUser' - self.assertIsInstance(self.vreg.select('views', 'creation', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('creation', req, rset=rset), CWUserCreationForm) def test_select_view(self): # no entity rset = None req = self.request() - self.assertIsInstance(self.vreg.select('views', 'index', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('index', req, rset=rset), startup.IndexView) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'primary', req, rset=rset) + self.vreg['views'].select, 'primary', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'table', req, rset=rset) + self.vreg['views'].select, 'table', req, rset=rset) # no entity rset, req = self.env.get_rset_and_req('Any X WHERE X eid 999999') self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'index', req, rset=rset) + self.vreg['views'].select, 'index', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'creation', req, rset=rset) + self.vreg['views'].select, 'creation', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'primary', req, rset=rset) + self.vreg['views'].select, 'primary', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'table', req, rset=rset) + self.vreg['views'].select, 'table', req, rset=rset) # one entity rset, req = self.env.get_rset_and_req('CWGroup X WHERE X name "managers"') - self.assertIsInstance(self.vreg.select('views', 'primary', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('primary', req, rset=rset), primary.PrimaryView) - self.assertIsInstance(self.vreg.select('views', 'list', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('list', req, rset=rset), baseviews.ListView) - self.assertIsInstance(self.vreg.select('views', 'edition', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('edition', req, rset=rset), editforms.EditionFormView) - self.assertIsInstance(self.vreg.select('views', 'table', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('table', req, rset=rset), tableview.TableView) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'creation', req, rset=rset) + self.vreg['views'].select, 'creation', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'index', req, rset=rset) + self.vreg['views'].select, 'index', req, rset=rset) # list of entities of the same type rset, req = self.env.get_rset_and_req('CWGroup X') - self.assertIsInstance(self.vreg.select('views', 'primary', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('primary', req, rset=rset), primary.PrimaryView) - self.assertIsInstance(self.vreg.select('views', 'list', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('list', req, rset=rset), baseviews.ListView) - self.assertIsInstance(self.vreg.select('views', 'table', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('table', req, rset=rset), tableview.TableView) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'creation', req, rset=rset) + self.vreg['views'].select, 'creation', req, rset=rset) # list of entities of different types rset, req = self.env.get_rset_and_req('Any X') - self.assertIsInstance(self.vreg.select('views', 'primary', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('primary', req, rset=rset), primary.PrimaryView) - self.assertIsInstance(self.vreg.select('views', 'list', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('list', req, rset=rset), baseviews.ListView) - self.assertIsInstance(self.vreg.select('views', 'table', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('table', req, rset=rset), tableview.TableView) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'creation', req, rset=rset) + self.vreg['views'].select, 'creation', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'index', req, rset=rset) + self.vreg['views'].select, 'index', req, rset=rset) # whatever rset, req = self.env.get_rset_and_req('Any N, X WHERE X in_group Y, Y name N') - self.assertIsInstance(self.vreg.select('views', 'table', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('table', req, rset=rset), tableview.TableView) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'index', req, rset=rset) + self.vreg['views'].select, 'index', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'creation', req, rset=rset) + self.vreg['views'].select, 'creation', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'primary', req, rset=rset) + self.vreg['views'].select, 'primary', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'list', req, rset=rset) + self.vreg['views'].select, 'list', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'edition', req, rset=rset) + self.vreg['views'].select, 'edition', req, rset=rset) # mixed query rset, req = self.env.get_rset_and_req('Any U,G WHERE U is CWUser, G is CWGroup') self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'edition', req, rset=rset) + self.vreg['views'].select, 'edition', req, rset=rset) self.failUnlessRaises(NoSelectableObject, - self.vreg.select, 'views', 'creation', req, rset=rset) - self.assertIsInstance(self.vreg.select('views', 'table', req, rset=rset), + self.vreg['views'].select, 'creation', req, rset=rset) + self.assertIsInstance(self.vreg['views'].select('table', req, rset=rset), tableview.TableView) def test_interface_selector(self): image = self.add_entity('Image', name=u'bim.png', data=Binary('bim')) # image primary view priority rset, req = self.env.get_rset_and_req('Image X WHERE X name "bim.png"') - self.assertIsInstance(self.vreg.select('views', 'primary', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('primary', req, rset=rset), idownloadable.IDownloadablePrimaryView) @@ -371,12 +371,12 @@ image = self.add_entity('Image', name=u'bim.png', data=Binary('bim')) # image primary view priority rset, req = self.env.get_rset_and_req('Image X WHERE X name "bim.png"') - self.assertIsInstance(self.vreg.select('views', 'image', req, rset=rset), + self.assertIsInstance(self.vreg['views'].select('image', req, rset=rset), idownloadable.ImageView) fileobj = self.add_entity('File', name=u'bim.txt', data=Binary('bim')) # image primary view priority rset, req = self.env.get_rset_and_req('File X WHERE X name "bim.txt"') - self.assertRaises(NoSelectableObject, self.vreg.select, 'views', 'image', req, rset=rset) + self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'image', req, rset=rset) @@ -387,7 +387,7 @@ else: rset, req = self.env.get_rset_and_req(rql) try: - self.vreg.render(vid, req, rset=rset, **args) + self.vreg['views'].render(vid, req, rset=rset, **args) except: print vid, rset, args raise @@ -431,11 +431,11 @@ def setUp(self): super(RQLActionTC, self).setUp() self.vreg._loadedmods[__name__] = {} - self.vreg.register_vobject_class(CWETypeRQLAction) + self.vreg.register_appobject_class(CWETypeRQLAction) def tearDown(self): super(RQLActionTC, self).tearDown() - del self.vreg._registries['actions']['testaction'] + del self.vreg['actions']['testaction'] def test(self): rset, req = self.env.get_rset_and_req('CWEType X WHERE X name "CWEType"') diff -r ff6114c2c416 -r f84ba1a66abb web/views/actions.py --- a/web/views/actions.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/views/actions.py Tue Aug 04 15:08:18 2009 +0200 @@ -8,7 +8,7 @@ __docformat__ = "restructuredtext en" _ = unicode -from cubicweb.vregistry import objectify_selector +from cubicweb.appobject import objectify_selector from cubicweb.selectors import (EntitySelector, one_line_rset, two_lines_rset, one_etype_rset, relation_possible, nonempty_rset, non_final_entity, diff -r ff6114c2c416 -r f84ba1a66abb web/views/basecomponents.py --- a/web/views/basecomponents.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/views/basecomponents.py Tue Aug 04 15:08:18 2009 +0200 @@ -90,7 +90,7 @@ def call(self): if not self.req.cnx.anonymous_connection: # display useractions and siteactions - actions = self.vreg.possible_actions(self.req, self.rset) + actions = self.vreg['actions'].possible_actions(self.req, rset=self.rset) box = MenuWidget('', 'userActionsBox', _class='', islist=False) menu = PopupBoxMenu(self.req.user.login, isitem=False) box.append(menu) diff -r ff6114c2c416 -r f84ba1a66abb web/views/basecontrollers.py --- a/web/views/basecontrollers.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/views/basecontrollers.py Tue Aug 04 15:08:18 2009 +0200 @@ -100,7 +100,8 @@ self.add_to_breadcrumbs(view) self.validate_cache(view) template = self.appli.main_template_id(self.req) - return self.vreg.main_template(self.req, template, rset=rset, view=view) + return self.vreg['views'].main_template(self.req, template, + rset=rset, view=view) def _select_view_and_rset(self, rset): req = self.req @@ -119,12 +120,12 @@ req.set_message(req._("error while handling __method: %s") % req._(ex)) vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema) try: - view = self.vreg.select('views', vid, req, rset=rset) + view = self.vreg['views'].select(vid, req, rset=rset) except ObjectNotFound: self.warning("the view %s could not be found", vid) req.set_message(req._("The view %s could not be found") % vid) vid = vid_from_rset(req, rset, self.schema) - view = self.vreg.select('views', vid, req, rset=rset) + view = self.vreg['views'].select(vid, req, rset=rset) except NoSelectableObject: if rset: req.set_message(req._("The view %s can not be applied to this query") % vid) @@ -132,7 +133,7 @@ req.set_message(req._("You have no access to this view or it's not applyable to current data")) self.warning("the view %s can not be applied to this query", vid) vid = vid_from_rset(req, rset, self.schema) - view = self.vreg.select('views', vid, req, rset=rset) + view = self.vreg['views'].select(vid, req, rset=rset) return view, rset def add_to_breadcrumbs(self, view): @@ -183,7 +184,7 @@ def _validate_form(req, vreg): # XXX should use the `RemoteCallFailed` mechanism try: - ctrl = vreg.select('controllers', 'edit', req=req) + ctrl = vreg['controllers'].select('edit', req=req) except NoSelectableObject: return (False, {None: req._('not authorized')}) try: @@ -309,10 +310,10 @@ rset = None vid = req.form.get('vid') or vid_from_rset(req, rset, self.schema) try: - view = self.vreg.select('views', vid, req, rset=rset) + view = self.vreg['views'].select(vid, req, rset=rset) except NoSelectableObject: vid = req.form.get('fallbackvid', 'noresult') - view = self.vreg.select('views', vid, req, rset=rset) + view = self.vreg['views'].select(vid, req, rset=rset) divid = req.form.get('divid', 'pageContent') # we need to call pagination before with the stream set stream = view.set_stream() @@ -339,10 +340,10 @@ @xhtmlize def js_prop_widget(self, propkey, varname, tabindex=None): """specific method for CWProperty handling""" - entity = self.vreg.etype_class('CWProperty')(self.req, None, None) + entity = self.vreg['etypes'].etype_class('CWProperty')(self.req) entity.eid = varname entity['pkey'] = propkey - form = self.vreg.select('forms', 'edition', self.req, entity=entity) + form = self.vreg['forms'].select('edition', self.req, entity=entity) form.form_build_context() vfield = form.field_by_name('value') renderer = FormRenderer(self.req) @@ -355,7 +356,7 @@ rset = self._exec(rql) else: rset = None - comp = self.vreg.select(registry, compid, self.req, rset=rset) + comp = self.vreg[registry].select(compid, self.req, rset=rset) if extraargs is None: extraargs = {} else: # we receive unicode keys which is not supported by the **syntax @@ -367,8 +368,9 @@ @check_pageid @xhtmlize def js_inline_creation_form(self, peid, ttype, rtype, role): - view = self.vreg.select('views', 'inline-creation', self.req, - etype=ttype, peid=peid, rtype=rtype, role=role) + view = self.vreg['views'].select('inline-creation', self.req, + etype=ttype, peid=peid, rtype=rtype, + role=role) return view.render(etype=ttype, peid=peid, rtype=rtype, role=role) @jsonize diff -r ff6114c2c416 -r f84ba1a66abb web/views/basetemplates.py --- a/web/views/basetemplates.py Tue Aug 04 15:06:09 2009 +0200 +++ b/web/views/basetemplates.py Tue Aug 04 15:08:18 2009 +0200 @@ -10,7 +10,7 @@ from logilab.mtconverter import xml_escape -from cubicweb.vregistry import objectify_selector +from cubicweb.appobject import objectify_selector from cubicweb.selectors import match_kwargs from cubicweb.view import View, MainTemplate, NOINDEX, NOFOLLOW from cubicweb.utils import make_uid, UStringIO @@ -113,8 +113,8 @@ if vtitle: w(u'

    %s

    \n' % xml_escape(vtitle)) # display entity type restriction component - etypefilter = self.vreg.select_vobject('components', 'etypenavigation', - self.req, rset=self.rset) + etypefilter = self.vreg['components'].select_vobject( + 'etypenavigation', self.req, rset=self.rset) if etypefilter: etypefilter.render(w=w) self.nav_html = UStringIO() @@ -154,12 +154,12 @@ w(u'
    \n') self.nav_column(view, 'left') w(u'
    \n') - rqlcomp = self.vreg.select_object('components', 'rqlinput', self.req, - rset=self.rset) + rqlcomp = self.vreg['components'].select_object('rqlinput', self.req, + rset=self.rset) if rqlcomp: rqlcomp.render(w=self.w, view=view) - msgcomp = self.vreg.select_object('components', 'applmessages', - self.req, rset=self.rset) + msgcomp = self.vreg['components'].select_object('applmessages', + self.req, rset=self.rset) if msgcomp: msgcomp.render(w=self.w) self.content_header(view) @@ -173,8 +173,8 @@ self.w(u'') def nav_column(self, view, context): - boxes = list(self.vreg.possible_vobjects('boxes', self.req, rset=self.rset, - view=view, context=context)) + boxes = list(self.vreg['boxes'].possible_vobjects( + self.req, rset=self.rset, view=view, context=context)) if boxes: self.w(u'