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)}) |
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')) |