6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses |
7 """ |
7 """ |
8 __docformat__ = "restructuredtext en" |
8 __docformat__ = "restructuredtext en" |
9 _ = unicode |
9 _ = unicode |
10 |
10 |
11 from logilab.common.decorators import cached, clear_cache, monkeypatch |
11 from logilab.common.decorators import cached, clear_cache |
12 from logilab.common.deprecation import deprecated |
12 from logilab.common.deprecation import deprecated |
13 from logilab.common.modutils import cleanup_sys_modules |
13 from logilab.common.modutils import cleanup_sys_modules |
14 |
14 |
15 from rql import RQLHelper |
15 from rql import RQLHelper |
16 |
16 |
17 from cubicweb import (ETYPE_NAME_MAP, Binary, UnknownProperty, UnknownEid, |
17 from cubicweb import (ETYPE_NAME_MAP, Binary, UnknownProperty, UnknownEid, |
18 ObjectNotFound, NoSelectableObject, RegistryNotFound, |
18 ObjectNotFound, NoSelectableObject, RegistryNotFound, |
19 RegistryOutOfDate, CW_EVENT_MANAGER, onevent) |
19 RegistryOutOfDate, CW_EVENT_MANAGER, onevent) |
20 from cubicweb.utils import dump_class |
20 from cubicweb.utils import dump_class |
21 from cubicweb.vregistry import VRegistry, Registry |
21 from cubicweb.vregistry import VRegistry, Registry, class_regid |
22 from cubicweb.rtags import RTAGS |
22 from cubicweb.rtags import RTAGS |
23 |
23 |
24 |
24 |
25 @onevent('before-registry-reload') |
25 @onevent('before-registry-reload') |
26 def clear_rtag_objects(): |
26 def clear_rtag_objects(): |
88 if __fallback_oid is None: |
81 if __fallback_oid is None: |
89 raise |
82 raise |
90 obj = self.select(__fallback_oid, req, rset=rset, **initargs) |
83 obj = self.select(__fallback_oid, req, rset=rset, **initargs) |
91 return obj.render(**kwargs) |
84 return obj.render(**kwargs) |
92 |
85 |
|
86 @deprecated('[3.6] use select_or_none and test for obj.cw_propval("visible")') |
93 def select_vobject(self, oid, *args, **kwargs): |
87 def select_vobject(self, oid, *args, **kwargs): |
94 selected = self.select_object(oid, *args, **kwargs) |
88 selected = self.select_or_none(oid, *args, **kwargs) |
95 if selected and selected.propval('visible'): |
89 if selected and selected.cw_propval('visible'): |
96 return selected |
90 return selected |
97 return None |
91 return None |
98 |
92 |
99 def possible_vobjects(self, *args, **kwargs): |
93 def poss_visible_objects(self, *args, **kwargs): |
100 """return an ordered list of possible app objects in a given registry, |
94 """return an ordered list of possible app objects in a given registry, |
101 supposing they support the 'visible' and 'order' properties (as most |
95 supposing they support the 'visible' and 'order' properties (as most |
102 visualizable objects) |
96 visualizable objects) |
103 """ |
97 """ |
104 return sorted([x for x in self.possible_objects(*args, **kwargs) |
98 return sorted([x for x in self.possible_objects(*args, **kwargs) |
105 if x.propval('visible')], |
99 if x.cw_propval('visible')], |
106 key=lambda x: x.propval('order')) |
100 key=lambda x: x.cw_propval('order')) |
|
101 possible_vobjects = deprecated('[3.6] use poss_visible_objects()')(poss_visible_objects) |
107 |
102 |
108 |
103 |
109 VRegistry.REGISTRY_FACTORY[None] = CWRegistry |
104 VRegistry.REGISTRY_FACTORY[None] = CWRegistry |
110 |
105 |
111 |
106 |
115 """on registration completed, clear etype_class internal cache |
110 """on registration completed, clear etype_class internal cache |
116 """ |
111 """ |
117 super(ETypeRegistry, self).initialization_completed() |
112 super(ETypeRegistry, self).initialization_completed() |
118 # clear etype cache if you don't want to run into deep weirdness |
113 # clear etype cache if you don't want to run into deep weirdness |
119 clear_cache(self, 'etype_class') |
114 clear_cache(self, 'etype_class') |
|
115 clear_cache(self, 'parent_classes') |
120 |
116 |
121 def register(self, obj, **kwargs): |
117 def register(self, obj, **kwargs): |
122 oid = kwargs.get('oid') or obj.id |
118 oid = kwargs.get('oid') or class_regid(obj) |
123 if oid != 'Any' and not oid in self.schema: |
119 if oid != 'Any' and not oid in self.schema: |
124 self.error('don\'t register %s, %s type not defined in the ' |
120 self.error('don\'t register %s, %s type not defined in the ' |
125 'schema', obj, obj.id) |
121 'schema', obj, oid) |
126 return |
122 return |
127 kwargs['clear'] = True |
123 kwargs['clear'] = True |
128 super(ETypeRegistry, self).register(obj, **kwargs) |
124 super(ETypeRegistry, self).register(obj, **kwargs) |
129 |
125 |
130 @cached |
126 @cached |
|
127 def parent_classes(self, etype): |
|
128 if etype == 'Any': |
|
129 return [self.etype_class('Any')] |
|
130 eschema = self.schema.eschema(etype) |
|
131 parents = [self.etype_class(e.type) for e in eschema.ancestors()] |
|
132 parents.append(self.etype_class('Any')) |
|
133 return parents |
|
134 |
|
135 @cached |
131 def etype_class(self, etype): |
136 def etype_class(self, etype): |
132 """return an entity class for the given entity type. |
137 """return an entity class for the given entity type. |
133 |
138 |
134 Try to find out a specific class for this kind of entity or default to a |
139 Try to find out a specific class for this kind of entity or default to a |
135 dump of the nearest parent class (in yams inheritance) registered. |
140 dump of the nearest parent class (in yams inheritance) registered. |
136 |
141 |
137 Fall back to 'Any' if not yams parent class found. |
142 Fall back to 'Any' if not yams parent class found. |
138 """ |
143 """ |
139 etype = str(etype) |
144 etype = str(etype) |
140 if etype == 'Any': |
145 if etype == 'Any': |
141 return self.select('Any', 'Any') |
146 objects = self['Any'] |
|
147 assert len(objects) == 1, objects |
|
148 return objects[0] |
142 eschema = self.schema.eschema(etype) |
149 eschema = self.schema.eschema(etype) |
143 baseschemas = [eschema] + eschema.ancestors() |
150 baseschemas = [eschema] + eschema.ancestors() |
144 # browse ancestors from most specific to most generic and try to find an |
151 # browse ancestors from most specific to most generic and try to find an |
145 # associated custom entity class |
152 # associated custom entity class |
146 cls = None |
|
147 for baseschema in baseschemas: |
153 for baseschema in baseschemas: |
148 try: |
154 try: |
149 btype = ETYPE_NAME_MAP[baseschema] |
155 btype = ETYPE_NAME_MAP[baseschema] |
150 except KeyError: |
156 except KeyError: |
151 btype = str(baseschema) |
157 btype = str(baseschema) |
152 if cls is None: |
158 try: |
153 try: |
159 objects = self[btype] |
154 objects = self[btype] |
160 assert len(objects) == 1, objects |
155 assert len(objects) == 1, objects |
161 if btype == etype: |
156 if btype == etype: |
162 cls = objects[0] |
157 cls = objects[0] |
163 else: |
158 else: |
164 # recurse to ensure issubclass(etype_class('Child'), |
159 cls = self.etype_class(btype) |
165 # etype_class('Parent')) |
160 except ObjectNotFound: |
166 cls = self.etype_class(btype) |
161 continue |
167 break |
162 else: |
168 except ObjectNotFound: |
163 # ensure parent classes are built first |
169 pass |
164 self.etype_class(btype) |
170 else: |
165 if cls is None: |
|
166 # no entity class for any of the ancestors, fallback to the default |
171 # no entity class for any of the ancestors, fallback to the default |
167 # one |
172 # one |
168 objects = self['Any'] |
173 objects = self['Any'] |
169 assert len(objects) == 1, objects |
174 assert len(objects) == 1, objects |
170 cls = objects[0] |
175 cls = objects[0] |
171 # make a copy event if cls.id == etype, else we may have pb for client |
176 # make a copy event if cls.__regid__ == etype, else we may have pb for |
172 # application using multiple connections to different repositories (eg |
177 # client application using multiple connections to different |
173 # shingouz) |
178 # repositories (eg shingouz) |
174 cls = dump_class(cls, etype) |
179 cls = dump_class(cls, etype) |
175 cls.id = etype |
180 cls.__regid__ = etype |
176 cls.__initialize__() |
181 cls.__initialize__(self.schema) |
177 return cls |
182 return cls |
178 |
183 |
179 VRegistry.REGISTRY_FACTORY['etypes'] = ETypeRegistry |
184 VRegistry.REGISTRY_FACTORY['etypes'] = ETypeRegistry |
180 |
185 |
181 |
186 |
182 class ViewsRegistry(CWRegistry): |
187 class ViewsRegistry(CWRegistry): |
183 |
188 |
184 def main_template(self, req, oid='main-template', **kwargs): |
189 def main_template(self, req, oid='main-template', rset=None, **kwargs): |
185 """display query by calling the given template (default to main), |
190 """display query by calling the given template (default to main), |
186 and returning the output as a string instead of requiring the [w]rite |
191 and returning the output as a string instead of requiring the [w]rite |
187 method as argument |
192 method as argument |
188 """ |
193 """ |
189 res = self.render(oid, req, **kwargs) |
194 obj = self.select(oid, req, rset=rset, **kwargs) |
|
195 res = obj.render(**kwargs) |
190 if isinstance(res, unicode): |
196 if isinstance(res, unicode): |
191 return res.encode(req.encoding) |
197 return res.encode(req.encoding) |
192 assert isinstance(res, str) |
198 assert isinstance(res, str) |
193 return res |
199 return res |
194 |
200 |
352 def register_objects(self, path, force_reload=None): |
358 def register_objects(self, path, force_reload=None): |
353 """overriden to remove objects requiring a missing interface""" |
359 """overriden to remove objects requiring a missing interface""" |
354 if force_reload is None: |
360 if force_reload is None: |
355 force_reload = self.config.debugmode |
361 force_reload = self.config.debugmode |
356 try: |
362 try: |
357 self._register_objects(path, force_reload) |
363 super(CubicWebVRegistry, self).register_objects( |
|
364 path, force_reload, self.config.extrapath) |
358 except RegistryOutOfDate: |
365 except RegistryOutOfDate: |
359 CW_EVENT_MANAGER.emit('before-registry-reload') |
366 CW_EVENT_MANAGER.emit('before-registry-reload') |
360 # modification detected, reset and reload |
367 # modification detected, reset and reload |
361 self.reset(path, force_reload) |
368 self.reset(path, force_reload) |
362 self._register_objects(path, force_reload) |
369 super(CubicWebVRegistry, self).register_objects( |
|
370 path, force_reload, self.config.extrapath) |
363 CW_EVENT_MANAGER.emit('after-registry-reload') |
371 CW_EVENT_MANAGER.emit('after-registry-reload') |
364 |
372 |
365 def _register_objects(self, path, force_reload=None): |
|
366 """overriden to remove objects requiring a missing interface""" |
|
367 extrapath = {} |
|
368 for cubesdir in self.config.cubes_search_path(): |
|
369 if cubesdir != self.config.CUBES_DIR: |
|
370 extrapath[cubesdir] = 'cubes' |
|
371 if super(CubicWebVRegistry, self).register_objects(path, force_reload, |
|
372 extrapath): |
|
373 self.initialization_completed() |
|
374 # don't check rtags if we don't want to cleanup_interface_sobjects |
|
375 for rtag in RTAGS: |
|
376 rtag.init(self.schema, |
|
377 check=self.config.cleanup_interface_sobjects) |
|
378 |
|
379 def initialization_completed(self): |
373 def initialization_completed(self): |
380 for regname, reg in self.iteritems(): |
374 """cw specific code once vreg initialization is completed: |
381 self.debug('available in registry %s: %s', regname, sorted(reg)) |
375 |
382 reg.initialization_completed() |
376 * remove objects requiring a missing interface, unless |
383 for appobjects in reg.itervalues(): |
377 config.cleanup_interface_sobjects is false |
384 for appobjectcls in appobjects: |
378 * init rtags |
385 appobjectcls.register_properties() |
379 """ |
386 # we may want to keep interface dependent objects (e.g.for i18n |
380 # we may want to keep interface dependent objects (e.g.for i18n |
387 # catalog generation) |
381 # catalog generation) |
388 if self.config.cleanup_interface_sobjects: |
382 if self.config.cleanup_interface_sobjects: |
389 # remove appobjects that don't support any available interface |
383 # remove appobjects that don't support any available interface |
390 implemented_interfaces = set() |
384 implemented_interfaces = set() |