appobject.py
brancholdstable
changeset 5422 0865e1e90674
parent 5421 8167de96c523
child 5423 e15abfdcce38
child 5424 8ecbcbff9777
equal deleted inserted replaced
4985:02b52bf9f5f8 5422:0865e1e90674
     1 """Base class for dynamically loaded objects accessible through the vregistry.
     1 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     2 
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     3 You'll also find some convenience classes to build selectors.
     3 #
     4 
     4 # This file is part of CubicWeb.
     5 :organization: Logilab
     5 #
     6 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
     7 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     7 # terms of the GNU Lesser General Public License as published by the Free
     8 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """
       
    19 .. _appobject:
       
    20 
       
    21 The `AppObject` class
       
    22 ---------------------
       
    23 
       
    24 The AppObject class is the base class for all dynamically loaded objects
       
    25 (application objects) accessible through the vregistry.
       
    26 
       
    27 We can find a certain number of attributes and methods defined in this class and
       
    28 common to all the application objects.
       
    29 
       
    30 .. autoclass:: AppObject
     9 """
    31 """
    10 __docformat__ = "restructuredtext en"
    32 __docformat__ = "restructuredtext en"
    11 
    33 
    12 import types
    34 import types
    13 from logging import getLogger
    35 from logging import getLogger
    14 from warnings import warn
    36 from warnings import warn
    15 
    37 
    16 from logilab.common.deprecation import deprecated
    38 from logilab.common.deprecation import deprecated
       
    39 from logilab.common.decorators import classproperty
    17 from logilab.common.logging_ext import set_log_methods
    40 from logilab.common.logging_ext import set_log_methods
    18 
    41 
    19 
    42 
    20 # selector base classes and operations ########################################
    43 # selector base classes and operations ########################################
    21 
    44 
    22 def objectify_selector(selector_func):
    45 def objectify_selector(selector_func):
    23     """convenience decorator for simple selectors where a class definition
    46     """Most of the time, a simple score function is enough to build a selector.
    24     would be overkill::
    47     The :func:`objectify_selector` decorator turn it into a proper selector
       
    48     class::
    25 
    49 
    26         @objectify_selector
    50         @objectify_selector
    27         def one(cls, *args, **kwargs):
    51         def one(cls, req, rset=None, **kwargs):
    28             return 1
    52             return 1
       
    53 
       
    54         class MyView(View):
       
    55             __select__ = View.__select__ & one()
    29 
    56 
    30     """
    57     """
    31     return type(selector_func.__name__, (Selector,),
    58     return type(selector_func.__name__, (Selector,),
    32                 {'__doc__': selector_func.__doc__,
    59                 {'__doc__': selector_func.__doc__,
    33                  '__call__': lambda self, *a, **kw: selector_func(*a, **kw)})
    60                  '__call__': lambda self, *a, **kw: selector_func(*a, **kw)})
    46     return selector
    73     return selector
    47 
    74 
    48 
    75 
    49 class Selector(object):
    76 class Selector(object):
    50     """base class for selector classes providing implementation
    77     """base class for selector classes providing implementation
    51     for operators ``&`` and ``|``
    78     for operators ``&``, ``|`` and  ``~``
    52 
    79 
    53     This class is only here to give access to binary operators, the
    80     This class is only here to give access to binary operators, the
    54     selector logic itself should be implemented in the __call__ method
    81     selector logic itself should be implemented in the __call__ method
    55 
    82 
    56 
    83 
   202 class AppObject(object):
   229 class AppObject(object):
   203     """This is the base class for CubicWeb application objects which are
   230     """This is the base class for CubicWeb application objects which are
   204     selected according to a context (usually at least a request and a result
   231     selected according to a context (usually at least a request and a result
   205     set).
   232     set).
   206 
   233 
   207     Concrete application objects classes are designed to be loaded by the
       
   208     vregistry and should be accessed through it, not by direct instantiation.
       
   209 
       
   210     The following attributes should be set on concret appobject classes:
   234     The following attributes should be set on concret appobject classes:
   211     :__registry__:
   235 
       
   236     :attr:`__registry__`
   212       name of the registry for this object (string like 'views',
   237       name of the registry for this object (string like 'views',
   213       'templates'...)
   238       'templates'...)
   214     :__regid__:
   239 
       
   240     :attr:`__regid__`
   215       object's identifier in the registry (string like 'main',
   241       object's identifier in the registry (string like 'main',
   216       'primary', 'folder_box')
   242       'primary', 'folder_box')
   217     :__select__:
   243 
       
   244     :attr:`__select__`
   218       class'selector
   245       class'selector
   219 
   246 
   220     Moreover, the `__abstract__` attribute may be set to True to indicate
   247     Moreover, the `__abstract__` attribute may be set to True to indicate that a
   221     that a appobject is abstract and should not be registered.
   248     class is abstract and should not be registered.
   222 
   249 
   223     At selection time, the following attributes are set on the instance:
   250     At selection time, the following attributes are set on the instance:
   224 
   251 
   225     :_cw:
   252     :attr:`_cw`
   226       current request
   253       current request
   227     :cw_extra_kwargs:
   254     :attr:`cw_extra_kwargs`
   228       other received arguments
   255       other received arguments
   229 
   256 
   230     only if rset is found in arguments (in which case rset/row/col will be
   257     And also the following, only if `rset` is found in arguments (in which case
   231     removed from cwextra_kwargs):
   258     rset/row/col will be removed from `cwextra_kwargs`):
   232 
   259 
   233     :cw_rset:
   260     :attr:`cw_rset`
   234       context result set or None
   261       context result set or None
   235     :cw_row:
   262 
       
   263     :attr:`cw_row`
   236       if a result set is set and the context is about a particular cell in the
   264       if a result set is set and the context is about a particular cell in the
   237       result set, and not the result set as a whole, specify the row number we
   265       result set, and not the result set as a whole, specify the row number we
   238       are interested in, else None
   266       are interested in, else None
   239     :cw_col:
   267 
       
   268     :attr:`cw_col`
   240       if a result set is set and the context is about a particular cell in the
   269       if a result set is set and the context is about a particular cell in the
   241       result set, and not the result set as a whole, specify the col number we
   270       result set, and not the result set as a whole, specify the col number we
   242       are interested in, else None
   271       are interested in, else None
       
   272 
       
   273 
       
   274     .. Note::
       
   275 
       
   276       * do not inherit directly from this class but from a more specific class
       
   277         such as `AnyEntity`, `EntityView`, `AnyRsetView`, `Action`...
       
   278 
       
   279       * to be recordable, a subclass has to define its registry (attribute
       
   280         `__registry__`) and its identifier (attribute `__regid__`). Usually
       
   281         you don't have to take care of the registry since it's set by the base
       
   282         class, only the identifier `id`
       
   283 
       
   284       * application objects are designed to be loaded by the vregistry and
       
   285         should be accessed through it, not by direct instantiation, besides
       
   286         to use it as base classe.
       
   287 
       
   288 
       
   289       * When we inherit from `AppObject` (even not directly), you *always* have
       
   290         to use **super()** to get the methods and attributes of the superclasses,
       
   291         and not use the class identifier.
       
   292 
       
   293         For example, instead of writting::
       
   294 
       
   295           class Truc(PrimaryView):
       
   296               def f(self, arg1):
       
   297                   PrimaryView.f(self, arg1)
       
   298 
       
   299         You must write::
       
   300 
       
   301           class Truc(PrimaryView):
       
   302               def f(self, arg1):
       
   303                   super(Truc, self).f(arg1)
       
   304 
   243     """
   305     """
   244     __registry__ = None
   306     __registry__ = None
   245     __regid__ = None
   307     __regid__ = None
   246     __select__ = yes()
   308     __select__ = yes()
       
   309 
       
   310     @classproperty
       
   311     def __registries__(cls):
       
   312         if cls.__registry__ is None:
       
   313             return ()
       
   314         return (cls.__registry__,)
   247 
   315 
   248     @classmethod
   316     @classmethod
   249     def __registered__(cls, registry):
   317     def __registered__(cls, registry):
   250         """called by the registry when the appobject has been registered.
   318         """called by the registry when the appobject has been registered.
   251 
   319 
   256         try: # XXX < 3.6 bw compat
   324         try: # XXX < 3.6 bw compat
   257             pdefs = cls.property_defs
   325             pdefs = cls.property_defs
   258         except AttributeError:
   326         except AttributeError:
   259             pdefs = getattr(cls, 'cw_property_defs', {})
   327             pdefs = getattr(cls, 'cw_property_defs', {})
   260         else:
   328         else:
   261             warn('property_defs is deprecated, use cw_property_defs in %s'
   329             warn('[3.6] property_defs is deprecated, use cw_property_defs in %s'
   262                  % cls, DeprecationWarning)
   330                  % cls, DeprecationWarning)
   263         for propid, pdef in pdefs.items():
   331         for propid, pdef in pdefs.items():
   264             pdef = pdef.copy() # may be shared
   332             pdef = pdef.copy() # may be shared
   265             pdef['default'] = getattr(cls, propid, pdef['default'])
   333             pdef['default'] = getattr(cls, propid, pdef['default'])
   266             pdef['sitewide'] = getattr(cls, 'site_wide', pdef.get('sitewide'))
   334             pdef['sitewide'] = getattr(cls, 'site_wide', pdef.get('sitewide'))