common/registerers.py
changeset 1808 aa09e20dd8c0
parent 1693 49075f57cf2c
parent 1807 6d541c610165
child 1810 e95e876be17c
equal deleted inserted replaced
1693:49075f57cf2c 1808:aa09e20dd8c0
     1 """This file contains some basic registerers required by application objects
       
     2 registry to handle registration at startup time.
       
     3 
       
     4 A registerer is responsible to tell if an object should be registered according
       
     5 to the application's schema or to already registered object
       
     6 
       
     7 :organization: Logilab
       
     8 :copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     9 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
    10 """
       
    11 __docformat__ = "restructuredtext en"
       
    12 
       
    13 from cubicweb.vregistry import registerer
       
    14 
       
    15 
       
    16 def _accepts_interfaces(obj):
       
    17     return sorted(getattr(obj, 'accepts_interfaces', ()))
       
    18 
       
    19 
       
    20 class yes_registerer(registerer):
       
    21     """register without any other action"""
       
    22     def do_it_yourself(self, registered):
       
    23         return self.vobject
       
    24 
       
    25 class priority_registerer(registerer):
       
    26     """systematically kick previous registered class and register the
       
    27     wrapped class (based on the fact that directory containing vobjects
       
    28     are loaded from the most generic to the most specific).
       
    29 
       
    30     This is usually for templates or startup views where we want to
       
    31     keep only the latest in the load path
       
    32     """
       
    33     def do_it_yourself(self, registered):
       
    34         if registered:
       
    35             if len(registered) > 1:
       
    36                 self.warning('priority_registerer found more than one registered objects '
       
    37                              '(registerer monkey patch ?)')
       
    38             for regobj in registered[:]:
       
    39                 self.kick(registered, regobj)
       
    40         return self.vobject
       
    41     
       
    42     def remove_equivalents(self, registered):
       
    43         for _obj in registered[:]:
       
    44             if self.equivalent(_obj):
       
    45                 self.kick(registered, _obj)
       
    46                 break
       
    47             
       
    48     def remove_all_equivalents(self, registered):
       
    49         for _obj in registered[:]:
       
    50             if _obj is self.vobject:
       
    51                 continue
       
    52             if self.equivalent(_obj):
       
    53                 self.kick(registered, _obj)
       
    54 
       
    55     def equivalent(self, other):
       
    56         raise NotImplementedError(self, self.vobject)
       
    57 
       
    58 
       
    59 class kick_registerer(registerer):
       
    60     """systematically kick previous registered class and don't register the
       
    61     wrapped class. This is temporarily used to discard library object registrable
       
    62     but that we don't want to use
       
    63     """
       
    64     def do_it_yourself(self, registered):
       
    65         if registered:
       
    66             self.kick(registered, registered[-1])
       
    67         return 
       
    68     
       
    69 
       
    70 class accepts_registerer(priority_registerer):
       
    71     """register according to the .accepts attribute of the wrapped
       
    72     class, which should be a tuple refering some entity's types
       
    73 
       
    74     * if no type is defined the application'schema, skip the wrapped
       
    75       class
       
    76     * if the class defines a requires attribute, each entity type defined
       
    77       in the requires list must be in the schema
       
    78     * if an object previously registered has equivalent .accepts
       
    79       attribute, kick it out
       
    80     * register
       
    81     """
       
    82     def do_it_yourself(self, registered):
       
    83         # if object is accepting interface, we have register it now and
       
    84         # remove it latter if no object is implementing accepted interfaces
       
    85         if _accepts_interfaces(self.vobject):
       
    86             return self.vobject
       
    87         if not 'Any' in self.vobject.accepts:
       
    88             for ertype in self.vobject.accepts:
       
    89                 if ertype in self.schema:
       
    90                     break
       
    91             else:
       
    92                 self.skip()
       
    93                 return None
       
    94         for required in getattr(self.vobject, 'requires', ()):
       
    95             if required not in self.schema:
       
    96                 self.skip()
       
    97                 return
       
    98         self.remove_equivalents(registered)
       
    99         return self.vobject
       
   100     
       
   101     def equivalent(self, other):
       
   102         if _accepts_interfaces(self.vobject) != _accepts_interfaces(other):
       
   103             return False
       
   104         if getattr(self.vobject, 'require_groups', ()) != getattr(other, 'require_groups', ()):
       
   105             return False
       
   106         try:
       
   107             newaccepts = list(other.accepts)
       
   108             for etype in self.vobject.accepts:
       
   109                 try:
       
   110                     newaccepts.remove(etype)
       
   111                 except ValueError:
       
   112                     continue
       
   113             if newaccepts:
       
   114                 other.accepts = tuple(newaccepts)
       
   115                 return False
       
   116             return True
       
   117         except AttributeError:
       
   118             return False
       
   119 
       
   120 
       
   121 class id_registerer(priority_registerer):
       
   122     """register according to the "id" attribute of the wrapped class,
       
   123     refering to an entity type.
       
   124     
       
   125     * if the type is not Any and is not defined the application'schema,
       
   126       skip the wrapped class
       
   127     * if an object previously registered has the same .id attribute,
       
   128       kick it out
       
   129     * register
       
   130     """
       
   131     def do_it_yourself(self, registered):
       
   132         etype = self.vobject.id
       
   133         if etype != 'Any' and not self.schema.has_entity(etype):
       
   134             self.skip()
       
   135             return
       
   136         self.remove_equivalents(registered)
       
   137         return self.vobject
       
   138     
       
   139     def equivalent(self, other):
       
   140         return other.id == self.vobject.id
       
   141 
       
   142 
       
   143 class etype_rtype_registerer(registerer):
       
   144     """registerer handling optional .etype and .rtype attributes.:
       
   145     
       
   146     * if .etype is set and is not an entity type defined in the
       
   147       application schema, skip the wrapped class
       
   148     * if .rtype or .relname is set and is not a relation type defined in
       
   149       the application schema, skip the wrapped class
       
   150     * register
       
   151     """
       
   152     def do_it_yourself(self, registered):
       
   153         cls = self.vobject
       
   154         if hasattr(cls, 'etype'):
       
   155             if not self.schema.has_entity(cls.etype):
       
   156                 return
       
   157         rtype = getattr(cls, 'rtype', None)
       
   158         if rtype and not self.schema.has_relation(rtype):
       
   159             return
       
   160         return cls
       
   161 
       
   162 class etype_rtype_priority_registerer(etype_rtype_registerer):
       
   163     """add priority behaviour to the etype_rtype_registerer
       
   164     """
       
   165     def do_it_yourself(self, registered):
       
   166         cls = super(etype_rtype_priority_registerer, self).do_it_yourself(registered)
       
   167         if cls:
       
   168             registerer = priority_registerer(self.registry, cls)
       
   169             cls = registerer.do_it_yourself(registered)
       
   170         return cls
       
   171 
       
   172 class action_registerer(etype_rtype_registerer):
       
   173     """'all in one' actions registerer, handling optional .accepts,
       
   174     .etype and .rtype attributes:
       
   175     
       
   176     * if .etype is set and is not an entity type defined in the
       
   177       application schema, skip the wrapped class
       
   178     * if .rtype or .relname is set and is not a relation type defined in
       
   179       the application schema, skip the wrapped class
       
   180     * if .accepts is set, delegate to the accepts_registerer
       
   181     * register
       
   182     """
       
   183     def do_it_yourself(self, registered):
       
   184         cls = super(action_registerer, self).do_it_yourself(registered)
       
   185         if hasattr(cls, 'accepts'):
       
   186             registerer = accepts_registerer(self.registry, cls)
       
   187             cls = registerer.do_it_yourself(registered)
       
   188         return cls
       
   189 
       
   190 
       
   191 class extresources_registerer(priority_registerer):
       
   192     """'registerer according to a .need_resources attributes which
       
   193     should list necessary resource identifiers for the wrapped object.
       
   194     If one of its resources is missing, don't register
       
   195     """
       
   196     def do_it_yourself(self, registered):
       
   197         if not hasattr(self.config, 'has_resource'):
       
   198             return
       
   199         for resourceid in self.vobject.need_resources:
       
   200             if not self.config.has_resource(resourceid):
       
   201                 return
       
   202         return super(extresources_registerer, self).do_it_yourself(registered)
       
   203     
       
   204 
       
   205 __all__ = [cls.__name__ for cls in globals().values()
       
   206            if isinstance(cls, type) and issubclass(cls, registerer)
       
   207            and not cls is registerer]