123 else: |
125 else: |
124 select = AndSelector(*selectors) |
126 select = AndSelector(*selectors) |
125 cls.__select__ = select |
127 cls.__select__ = select |
126 |
128 |
127 |
129 |
128 class VRegistry(object): |
130 class Registry(dict): |
129 """class responsible to register, propose and select the various |
131 |
130 elements used to build the web interface. Currently, we have templates, |
132 def __init__(self, config): |
131 views, actions and components. |
133 super(Registry, self).__init__() |
132 """ |
|
133 |
|
134 def __init__(self, config):#, cache_size=1000): |
|
135 self.config = config |
134 self.config = config |
136 # dictionnary of registry (themself dictionnary) by name |
135 |
137 self._registries = {} |
136 def __getitem__(self, name): |
138 self._lastmodifs = {} |
|
139 |
|
140 def reset(self): |
|
141 self._registries = {} |
|
142 self._lastmodifs = {} |
|
143 |
|
144 def __getitem__(self, key): |
|
145 return self._registries[key] |
|
146 |
|
147 def get(self, key, default=None): |
|
148 return self._registries.get(key, default) |
|
149 |
|
150 def items(self): |
|
151 return self._registries.items() |
|
152 |
|
153 def values(self): |
|
154 return self._registries.values() |
|
155 |
|
156 def __contains__(self, key): |
|
157 return key in self._registries |
|
158 |
|
159 def registry(self, name): |
|
160 """return the registry (dictionary of class objects) associated to |
137 """return the registry (dictionary of class objects) associated to |
161 this name |
138 this name |
162 """ |
139 """ |
163 try: |
140 try: |
164 return self._registries[name] |
141 return super(Registry, self).__getitem__(name) |
165 except KeyError: |
142 except KeyError: |
166 raise RegistryNotFound(name), None, sys.exc_info()[-1] |
143 raise ObjectNotFound(name), None, sys.exc_info()[-1] |
167 |
144 |
168 def registry_objects(self, name, oid=None): |
145 def register(self, obj, oid=None, clear=False): |
169 """returns objects registered with the given oid in the given registry. |
146 """base method to add an object in the registry""" |
170 If no oid is given, return all objects in this registry |
147 assert not '__abstract__' in obj.__dict__ |
171 """ |
148 oid = oid or obj.id |
172 registry = self.registry(name) |
149 assert oid |
173 if oid is not None: |
150 if clear: |
174 try: |
151 vobjects = self[oid] = [] |
175 return registry[oid] |
152 else: |
176 except KeyError: |
153 vobjects = self.setdefault(oid, []) |
177 raise ObjectNotFound(oid), None, sys.exc_info()[-1] |
154 # registered() is technically a classmethod but is not declared |
|
155 # as such because we need to compose registered in some cases |
|
156 vobject = obj.registered.im_func(obj, self) |
|
157 assert not vobject in vobjects, \ |
|
158 'object %s is already registered' % vobject |
|
159 assert callable(vobject.__select__), vobject |
|
160 vobjects.append(vobject) |
|
161 |
|
162 def register_and_replace(self, obj, replaced): |
|
163 # XXXFIXME this is a duplication of unregister() |
|
164 # remove register_and_replace in favor of unregister + register |
|
165 # or simplify by calling unregister then register here |
|
166 if hasattr(replaced, 'classid'): |
|
167 replaced = replaced.classid() |
|
168 registered_objs = self.get(obj.id, ()) |
|
169 for index, registered in enumerate(registered_objs): |
|
170 if registered.classid() == replaced: |
|
171 del registered_objs[index] |
|
172 break |
|
173 else: |
|
174 self.warning('trying to replace an unregistered view %s by %s', |
|
175 replaced, obj) |
|
176 self.register(obj) |
|
177 |
|
178 def unregister(self, obj): |
|
179 oid = obj.classid() |
|
180 for registered in self.get(obj.id, ()): |
|
181 # use classid() to compare classes because vreg will probably |
|
182 # have its own version of the class, loaded through execfile |
|
183 if registered.classid() == oid: |
|
184 # XXX automatic reloading management |
|
185 self[obj.id].remove(registered) |
|
186 break |
|
187 else: |
|
188 self.warning('can\'t remove %s, no id %s in the registry', |
|
189 oid, obj.id) |
|
190 |
|
191 def all_objects(self): |
|
192 """return a list containing all objects in this registry. |
|
193 """ |
178 result = [] |
194 result = [] |
179 for objs in registry.values(): |
195 for objs in self.values(): |
180 result += objs |
196 result += objs |
181 return result |
197 return result |
182 |
198 |
183 # dynamic selection methods ################################################ |
199 # dynamic selection methods ################################################ |
184 |
200 |
185 def object_by_id(self, registry, oid, *args, **kwargs): |
201 def object_by_id(self, oid, *args, **kwargs): |
186 """return object in <registry>.<oid> |
202 """return object with the given oid. Only one object is expected to be |
|
203 found. |
187 |
204 |
188 raise `ObjectNotFound` if not object with id <oid> in <registry> |
205 raise `ObjectNotFound` if not object with id <oid> in <registry> |
189 raise `AssertionError` if there is more than one object there |
206 raise `AssertionError` if there is more than one object there |
190 """ |
207 """ |
191 objects = self.registry_objects(registry, oid) |
208 objects = self[oid] |
192 assert len(objects) == 1, objects |
209 assert len(objects) == 1, objects |
193 return objects[0].selected(*args, **kwargs) |
210 return objects[0].selected(*args, **kwargs) |
194 |
211 |
195 def select(self, registry, oid, *args, **kwargs): |
212 def select(self, oid, *args, **kwargs): |
196 """return the most specific object in <registry>.<oid> according to |
213 """return the most specific object among those with the given oid |
197 the given context |
214 according to the given context. |
198 |
215 |
199 raise `ObjectNotFound` if not object with id <oid> in <registry> |
216 raise `ObjectNotFound` if not object with id <oid> in <registry> |
200 raise `NoSelectableObject` if not object apply |
217 raise `NoSelectableObject` if not object apply |
201 """ |
218 """ |
202 return self.select_best(self.registry_objects(registry, oid), |
219 return self.select_best(self[oid], *args, **kwargs) |
203 *args, **kwargs) |
220 |
204 |
221 def select_object(self, oid, *args, **kwargs): |
205 def select_object(self, registry, oid, *args, **kwargs): |
222 """return the most specific object among those with the given oid |
206 """return the most specific object in <registry>.<oid> according to |
223 according to the given context, or None if no object applies. |
207 the given context, or None if no object apply |
224 """ |
208 """ |
225 try: |
209 try: |
226 return self.select(oid, *args, **kwargs) |
210 return self.select(registry, oid, *args, **kwargs) |
|
211 except (NoSelectableObject, ObjectNotFound): |
227 except (NoSelectableObject, ObjectNotFound): |
212 return None |
228 return None |
213 |
229 |
214 def possible_objects(self, registry, *args, **kwargs): |
230 def possible_objects(self, *args, **kwargs): |
215 """return an iterator on possible objects in <registry> for the given |
231 """return an iterator on possible objects in this registry for the given |
216 context |
232 context |
217 """ |
233 """ |
218 for vobjects in self.registry(registry).itervalues(): |
234 for vobjects in self.itervalues(): |
219 try: |
235 try: |
220 yield self.select_best(vobjects, *args, **kwargs) |
236 yield self.select_best(vobjects, *args, **kwargs) |
221 except NoSelectableObject: |
237 except NoSelectableObject: |
222 continue |
238 continue |
223 |
239 |
250 % (args, kwargs.keys(), |
266 % (args, kwargs.keys(), |
251 [repr(v) for v in winners])) |
267 [repr(v) for v in winners])) |
252 # return the result of the .selected method of the vobject |
268 # return the result of the .selected method of the vobject |
253 return winners[0].selected(*args, **kwargs) |
269 return winners[0].selected(*args, **kwargs) |
254 |
270 |
|
271 |
|
272 class VRegistry(dict): |
|
273 """class responsible to register, propose and select the various |
|
274 elements used to build the web interface. Currently, we have templates, |
|
275 views, actions and components. |
|
276 """ |
|
277 |
|
278 def __init__(self, config): |
|
279 super(VRegistry, self).__init__() |
|
280 self.config = config |
|
281 |
|
282 def reset(self): |
|
283 self.clear() |
|
284 self._lastmodifs = {} |
|
285 |
|
286 def __getitem__(self, name): |
|
287 """return the registry (dictionary of class objects) associated to |
|
288 this name |
|
289 """ |
|
290 try: |
|
291 return super(VRegistry, self).__getitem__(name) |
|
292 except KeyError: |
|
293 raise RegistryNotFound(name), None, sys.exc_info()[-1] |
|
294 |
|
295 # dynamic selection methods ################################################ |
|
296 |
|
297 @deprecated('use vreg[registry].object_by_id(oid, *args, **kwargs)') |
|
298 def object_by_id(self, registry, oid, *args, **kwargs): |
|
299 """return object in <registry>.<oid> |
|
300 |
|
301 raise `ObjectNotFound` if not object with id <oid> in <registry> |
|
302 raise `AssertionError` if there is more than one object there |
|
303 """ |
|
304 return self[registry].object_by_id(oid) |
|
305 |
|
306 @deprecated('use vreg[registry].select(oid, *args, **kwargs)') |
|
307 def select(self, registry, oid, *args, **kwargs): |
|
308 """return the most specific object in <registry>.<oid> according to |
|
309 the given context |
|
310 |
|
311 raise `ObjectNotFound` if not object with id <oid> in <registry> |
|
312 raise `NoSelectableObject` if not object apply |
|
313 """ |
|
314 return self[registry].select(oid, *args, **kwargs) |
|
315 |
|
316 @deprecated('use vreg[registry].select_object(oid, *args, **kwargs)') |
|
317 def select_object(self, registry, oid, *args, **kwargs): |
|
318 """return the most specific object in <registry>.<oid> according to |
|
319 the given context, or None if no object apply |
|
320 """ |
|
321 return self[registry].select_object(oid, *args, **kwargs) |
|
322 |
|
323 @deprecated('use vreg[registry].possible_objects(*args, **kwargs)') |
|
324 def possible_objects(self, registry, *args, **kwargs): |
|
325 """return an iterator on possible objects in <registry> for the given |
|
326 context |
|
327 """ |
|
328 return self[registry].possible_objects(*args, **kwargs) |
|
329 |
255 # methods for explicit (un)registration ################################### |
330 # methods for explicit (un)registration ################################### |
|
331 |
|
332 # default class, when no specific class set |
|
333 REGISTRY_FACTORY = {None: Registry} |
|
334 |
|
335 def registry_class(self, regid): |
|
336 try: |
|
337 return self.REGISTRY_FACTORY[regid] |
|
338 except KeyError: |
|
339 return self.REGISTRY_FACTORY[None] |
|
340 |
|
341 def setdefault(self, regid): |
|
342 try: |
|
343 return self[regid] |
|
344 except KeyError: |
|
345 self[regid] = self.registry_class(regid)(self.config) |
|
346 return self[regid] |
256 |
347 |
257 # def clear(self, key): |
348 # def clear(self, key): |
258 # regname, oid = key.split('.') |
349 # regname, oid = key.split('.') |
259 # self[regname].pop(oid, None) |
350 # self[regname].pop(oid, None) |
260 |
351 |
271 |
362 |
272 def register(self, obj, registryname=None, oid=None, clear=False): |
363 def register(self, obj, registryname=None, oid=None, clear=False): |
273 """base method to add an object in the registry""" |
364 """base method to add an object in the registry""" |
274 assert not '__abstract__' in obj.__dict__ |
365 assert not '__abstract__' in obj.__dict__ |
275 registryname = registryname or obj.__registry__ |
366 registryname = registryname or obj.__registry__ |
276 oid = oid or obj.id |
367 registry = self.setdefault(registryname) |
277 assert oid |
368 registry.register(obj, oid=oid, clear=clear) |
278 registry = self._registries.setdefault(registryname, {}) |
369 try: |
279 if clear: |
370 vname = obj.__name__ |
280 vobjects = registry[oid] = [] |
|
281 else: |
|
282 vobjects = registry.setdefault(oid, []) |
|
283 # registered() is technically a classmethod but is not declared |
|
284 # as such because we need to compose registered in some cases |
|
285 vobject = obj.registered.im_func(obj, self) |
|
286 assert not vobject in vobjects, \ |
|
287 'object %s is already registered' % vobject |
|
288 assert callable(vobject.__select__), vobject |
|
289 vobjects.append(vobject) |
|
290 try: |
|
291 vname = vobject.__name__ |
|
292 except AttributeError: |
371 except AttributeError: |
293 vname = vobject.__class__.__name__ |
372 vname = obj.__class__.__name__ |
294 self.debug('registered vobject %s in registry %s with id %s', |
373 self.debug('registered vobject %s in registry %s with id %s', |
295 vname, registryname, oid) |
374 vname, registryname, oid) |
296 # automatic reloading management |
375 # automatic reloading management |
297 self._loadedmods[obj.__module__]['%s.%s' % (obj.__module__, oid)] = obj |
376 self._loadedmods[obj.__module__]['%s.%s' % (obj.__module__, oid)] = obj |
298 |
377 |
299 def unregister(self, obj, registryname=None): |
378 def unregister(self, obj, registryname=None): |
300 registryname = registryname or obj.__registry__ |
379 self[registryname or obj.__registry__].unregister(obj) |
301 registry = self.registry(registryname) |
|
302 removed_id = obj.classid() |
|
303 for registered in registry.get(obj.id, ()): |
|
304 # use classid() to compare classes because vreg will probably |
|
305 # have its own version of the class, loaded through execfile |
|
306 if registered.classid() == removed_id: |
|
307 # XXX automatic reloading management |
|
308 registry[obj.id].remove(registered) |
|
309 break |
|
310 else: |
|
311 self.warning('can\'t remove %s, no id %s in the %s registry', |
|
312 removed_id, obj.id, registryname) |
|
313 |
380 |
314 def register_and_replace(self, obj, replaced, registryname=None): |
381 def register_and_replace(self, obj, replaced, registryname=None): |
315 # XXXFIXME this is a duplication of unregister() |
382 self[registryname or obj.__registry__].register_and_replace(obj, replaced) |
316 # remove register_and_replace in favor of unregister + register |
383 |
317 # or simplify by calling unregister then register here |
384 # initialization methods ################################################### |
318 if hasattr(replaced, 'classid'): |
|
319 replaced = replaced.classid() |
|
320 registryname = registryname or obj.__registry__ |
|
321 registry = self.registry(registryname) |
|
322 registered_objs = registry.get(obj.id, ()) |
|
323 for index, registered in enumerate(registered_objs): |
|
324 if registered.classid() == replaced: |
|
325 del registry[obj.id][index] |
|
326 break |
|
327 else: |
|
328 self.warning('trying to replace an unregistered view %s by %s', |
|
329 replaced, obj) |
|
330 self.register(obj, registryname=registryname) |
|
331 |
|
332 # intialization methods ################################################### |
|
333 |
385 |
334 def init_registration(self, path, extrapath=None): |
386 def init_registration(self, path, extrapath=None): |
335 # compute list of all modules that have to be loaded |
387 # compute list of all modules that have to be loaded |
336 self._toloadmods, filemods = _toload_info(path, extrapath) |
388 self._toloadmods, filemods = _toload_info(path, extrapath) |
337 self._loadedmods = {} |
389 self._loadedmods = {} |