diff -r 000000000000 -r b97547f5f1fa common/registerers.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/registerers.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,205 @@ +"""This file contains some basic registerers required by application objects +registry to handle registration at startup time. + +A registerer is responsible to tell if an object should be registered according +to the application's schema or to already registered object + +:organization: Logilab +:copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +from cubicweb.vregistry import registerer + + +def _accepts_interfaces(obj): + return sorted(getattr(obj, 'accepts_interfaces', ())) + + +class yes_registerer(registerer): + """register without any other action""" + def do_it_yourself(self, registered): + return self.vobject + +class priority_registerer(registerer): + """systematically kick previous registered class and register the + wrapped class (based on the fact that directory containing vobjects + are loaded from the most generic to the most specific). + + This is usually for templates or startup views where we want to + keep only the latest in the load path + """ + def do_it_yourself(self, registered): + if registered: + if len(registered) > 1: + self.warning('priority_registerer found more than one registered objects ' + '(registerer monkey patch ?)') + for regobj in registered[:]: + self.kick(registered, regobj) + return self.vobject + + def remove_equivalents(self, registered): + for _obj in registered[:]: + if self.equivalent(_obj): + self.kick(registered, _obj) + break + + def remove_all_equivalents(self, registered): + for _obj in registered[:]: + if _obj is self.vobject: + continue + if self.equivalent(_obj): + self.kick(registered, _obj) + + def equivalent(self, other): + raise NotImplementedError(self, self.vobject) + + +class kick_registerer(registerer): + """systematically kick previous registered class and don't register the + wrapped class. This is temporarily used to discard library object registrable + but that we don't want to use + """ + def do_it_yourself(self, registered): + if registered: + self.kick(registered, registered[-1]) + return + + +class accepts_registerer(priority_registerer): + """register according to the .accepts attribute of the wrapped + class, which should be a tuple refering some entity's types + + * if no type is defined the application'schema, skip the wrapped + class + * if the class defines a requires attribute, each entity type defined + in the requires list must be in the schema + * if an object previously registered has equivalent .accepts + attribute, kick it out + * register + """ + def do_it_yourself(self, registered): + # if object is accepting interface, we have register it now and + # remove it latter if no object is implementing accepted interfaces + if _accepts_interfaces(self.vobject): + return self.vobject + if not 'Any' in self.vobject.accepts: + for ertype in self.vobject.accepts: + if ertype in self.schema: + break + else: + self.skip() + return None + for required in getattr(self.vobject, 'requires', ()): + if required not in self.schema: + self.skip() + return + self.remove_equivalents(registered) + return self.vobject + + def equivalent(self, other): + if _accepts_interfaces(self.vobject) != _accepts_interfaces(other): + return False + try: + newaccepts = list(other.accepts) + for etype in self.vobject.accepts: + try: + newaccepts.remove(etype) + except ValueError: + continue + if newaccepts: + other.accepts = tuple(newaccepts) + return False + return True + except AttributeError: + return False + + +class id_registerer(priority_registerer): + """register according to the "id" attribute of the wrapped class, + refering to an entity type. + + * if the type is not Any and is not defined the application'schema, + skip the wrapped class + * if an object previously registered has the same .id attribute, + kick it out + * register + """ + def do_it_yourself(self, registered): + etype = self.vobject.id + if etype != 'Any' and not self.schema.has_entity(etype): + self.skip() + return + self.remove_equivalents(registered) + return self.vobject + + def equivalent(self, other): + return other.id == self.vobject.id + + +class etype_rtype_registerer(registerer): + """registerer handling optional .etype and .rtype attributes.: + + * if .etype is set and is not an entity type defined in the + application schema, skip the wrapped class + * if .rtype or .relname is set and is not a relation type defined in + the application schema, skip the wrapped class + * register + """ + def do_it_yourself(self, registered): + cls = self.vobject + if hasattr(cls, 'etype'): + if not self.schema.has_entity(cls.etype): + return + rtype = getattr(cls, 'rtype', None) + if rtype and not self.schema.has_relation(rtype): + return + return cls + +class etype_rtype_priority_registerer(etype_rtype_registerer): + """add priority behaviour to the etype_rtype_registerer + """ + def do_it_yourself(self, registered): + cls = super(etype_rtype_priority_registerer, self).do_it_yourself(registered) + if cls: + registerer = priority_registerer(self.registry, cls) + cls = registerer.do_it_yourself(registered) + return cls + +class action_registerer(etype_rtype_registerer): + """'all in one' actions registerer, handling optional .accepts, + .etype and .rtype attributes: + + * if .etype is set and is not an entity type defined in the + application schema, skip the wrapped class + * if .rtype or .relname is set and is not a relation type defined in + the application schema, skip the wrapped class + * if .accepts is set, delegate to the accepts_registerer + * register + """ + def do_it_yourself(self, registered): + cls = super(action_registerer, self).do_it_yourself(registered) + if hasattr(cls, 'accepts'): + registerer = accepts_registerer(self.registry, cls) + cls = registerer.do_it_yourself(registered) + return cls + + +class extresources_registerer(priority_registerer): + """'registerer according to a .need_resources attributes which + should list necessary resource identifiers for the wrapped object. + If one of its resources is missing, don't register + """ + def do_it_yourself(self, registered): + if not hasattr(self.config, 'has_resource'): + return + for resourceid in self.vobject.need_resources: + if not self.config.has_resource(resourceid): + return + return super(extresources_registerer, self).do_it_yourself(registered) + + +__all__ = [cls.__name__ for cls in globals().values() + if isinstance(cls, type) and issubclass(cls, registerer) + and not cls is registerer]