common/registerers.py
changeset 0 b97547f5f1fa
child 631 99f5852f8604
child 1252 e782f333408b
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     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         try:
       
   105             newaccepts = list(other.accepts)
       
   106             for etype in self.vobject.accepts:
       
   107                 try:
       
   108                     newaccepts.remove(etype)
       
   109                 except ValueError:
       
   110                     continue
       
   111             if newaccepts:
       
   112                 other.accepts = tuple(newaccepts)
       
   113                 return False
       
   114             return True
       
   115         except AttributeError:
       
   116             return False
       
   117 
       
   118 
       
   119 class id_registerer(priority_registerer):
       
   120     """register according to the "id" attribute of the wrapped class,
       
   121     refering to an entity type.
       
   122     
       
   123     * if the type is not Any and is not defined the application'schema,
       
   124       skip the wrapped class
       
   125     * if an object previously registered has the same .id attribute,
       
   126       kick it out
       
   127     * register
       
   128     """
       
   129     def do_it_yourself(self, registered):
       
   130         etype = self.vobject.id
       
   131         if etype != 'Any' and not self.schema.has_entity(etype):
       
   132             self.skip()
       
   133             return
       
   134         self.remove_equivalents(registered)
       
   135         return self.vobject
       
   136     
       
   137     def equivalent(self, other):
       
   138         return other.id == self.vobject.id
       
   139 
       
   140 
       
   141 class etype_rtype_registerer(registerer):
       
   142     """registerer handling optional .etype and .rtype attributes.:
       
   143     
       
   144     * if .etype is set and is not an entity type defined in the
       
   145       application schema, skip the wrapped class
       
   146     * if .rtype or .relname is set and is not a relation type defined in
       
   147       the application schema, skip the wrapped class
       
   148     * register
       
   149     """
       
   150     def do_it_yourself(self, registered):
       
   151         cls = self.vobject
       
   152         if hasattr(cls, 'etype'):
       
   153             if not self.schema.has_entity(cls.etype):
       
   154                 return
       
   155         rtype = getattr(cls, 'rtype', None)
       
   156         if rtype and not self.schema.has_relation(rtype):
       
   157             return
       
   158         return cls
       
   159 
       
   160 class etype_rtype_priority_registerer(etype_rtype_registerer):
       
   161     """add priority behaviour to the etype_rtype_registerer
       
   162     """
       
   163     def do_it_yourself(self, registered):
       
   164         cls = super(etype_rtype_priority_registerer, self).do_it_yourself(registered)
       
   165         if cls:
       
   166             registerer = priority_registerer(self.registry, cls)
       
   167             cls = registerer.do_it_yourself(registered)
       
   168         return cls
       
   169 
       
   170 class action_registerer(etype_rtype_registerer):
       
   171     """'all in one' actions registerer, handling optional .accepts,
       
   172     .etype and .rtype attributes:
       
   173     
       
   174     * if .etype is set and is not an entity type defined in the
       
   175       application schema, skip the wrapped class
       
   176     * if .rtype or .relname is set and is not a relation type defined in
       
   177       the application schema, skip the wrapped class
       
   178     * if .accepts is set, delegate to the accepts_registerer
       
   179     * register
       
   180     """
       
   181     def do_it_yourself(self, registered):
       
   182         cls = super(action_registerer, self).do_it_yourself(registered)
       
   183         if hasattr(cls, 'accepts'):
       
   184             registerer = accepts_registerer(self.registry, cls)
       
   185             cls = registerer.do_it_yourself(registered)
       
   186         return cls
       
   187 
       
   188 
       
   189 class extresources_registerer(priority_registerer):
       
   190     """'registerer according to a .need_resources attributes which
       
   191     should list necessary resource identifiers for the wrapped object.
       
   192     If one of its resources is missing, don't register
       
   193     """
       
   194     def do_it_yourself(self, registered):
       
   195         if not hasattr(self.config, 'has_resource'):
       
   196             return
       
   197         for resourceid in self.vobject.need_resources:
       
   198             if not self.config.has_resource(resourceid):
       
   199                 return
       
   200         return super(extresources_registerer, self).do_it_yourself(registered)
       
   201     
       
   202 
       
   203 __all__ = [cls.__name__ for cls in globals().values()
       
   204            if isinstance(cls, type) and issubclass(cls, registerer)
       
   205            and not cls is registerer]