selectors.py
changeset 2822 f26578339214
parent 2819 b864288fd316
child 2834 7df3494ae657
equal deleted inserted replaced
2821:526f44213b70 2822:f26578339214
   110         global TRACED_OIDS
   110         global TRACED_OIDS
   111         TRACED_OIDS = ()
   111         TRACED_OIDS = ()
   112         return traceback is None
   112         return traceback is None
   113 
   113 
   114 
   114 
   115 def score_interface(cls_or_inst, cls, iface):
   115 def score_interface(etypesreg, cls_or_inst, cls, iface):
   116     """Return XXX if the give object (maybe an instance or class) implements
   116     """Return XXX if the give object (maybe an instance or class) implements
   117     the interface.
   117     the interface.
   118     """
   118     """
   119     if getattr(iface, '__registry__', None) == 'etypes':
   119     if getattr(iface, '__registry__', None) == 'etypes':
   120         # adjust score if the interface is an entity class
   120         # adjust score if the interface is an entity class
   121         parents = cls_or_inst.parent_classes()
   121         parents = etypesreg.parent_classes(cls_or_inst.id)
   122         if iface is cls:
   122         if iface is cls:
   123             return len(parents) + 4
   123             return len(parents) + 4
   124         if iface is parents[-1]: # Any
   124         if iface is parents[-1]: # Any
   125             return 1
   125             return 1
   126         for index, basecls in enumerate(reversed(parents[:-1])):
   126         for index, basecls in enumerate(reversed(parents[:-1])):
   155 
   155 
   156     def __str__(self):
   156     def __str__(self):
   157         return '%s(%s)' % (self.__class__.__name__,
   157         return '%s(%s)' % (self.__class__.__name__,
   158                            ','.join(str(s) for s in self.expected_ifaces))
   158                            ','.join(str(s) for s in self.expected_ifaces))
   159 
   159 
   160     def score_interfaces(self, cls_or_inst, cls):
   160     def score_interfaces(self, req, cls_or_inst, cls):
   161         score = 0
   161         score = 0
   162         vreg, eschema = cls_or_inst.vreg, cls_or_inst.e_schema
   162         etypesreg = req.vreg['etypes']
       
   163         eschema = cls_or_inst.e_schema
   163         for iface in self.expected_ifaces:
   164         for iface in self.expected_ifaces:
   164             if isinstance(iface, basestring):
   165             if isinstance(iface, basestring):
   165                 # entity type
   166                 # entity type
   166                 try:
   167                 try:
   167                     iface = vreg['etypes'].etype_class(iface)
   168                     iface = etypesreg.etype_class(iface)
   168                 except KeyError:
   169                 except KeyError:
   169                     continue # entity type not in the schema
   170                     continue # entity type not in the schema
   170             score += score_interface(cls_or_inst, cls, iface)
   171             score += score_interface(etypesreg, cls_or_inst, cls, iface)
   171         return score
   172         return score
   172 
   173 
   173 
   174 
   174 class EClassSelector(Selector):
   175 class EClassSelector(Selector):
   175     """abstract class for selectors working on the entity classes of the result
   176     """abstract class for selectors working on the entity classes of the result
   209         return score
   210         return score
   210 
   211 
   211     def score(self, cls, req, etype):
   212     def score(self, cls, req, etype):
   212         if etype in BASE_TYPES:
   213         if etype in BASE_TYPES:
   213             return 0
   214             return 0
   214         return self.score_class(cls.vreg['etypes'].etype_class(etype), req)
   215         return self.score_class(req.vreg['etypes'].etype_class(etype), req)
   215 
   216 
   216     def score_class(self, eclass, req):
   217     def score_class(self, eclass, req):
   217         raise NotImplementedError()
   218         raise NotImplementedError()
   218 
   219 
   219 
   220 
   558         self.registry = registry
   559         self.registry = registry
   559         self.oid = oid
   560         self.oid = oid
   560 
   561 
   561     def __call__(self, cls, req, **kwargs):
   562     def __call__(self, cls, req, **kwargs):
   562         try:
   563         try:
   563             cls.vreg[self.registry].select(self.oid, req, **kwargs)
   564             req.vreg[self.registry].select(self.oid, req, **kwargs)
   564             return 1
   565             return 1
   565         except NoSelectableObject:
   566         except NoSelectableObject:
   566             return 0
   567             return 0
   567 
   568 
   568 
   569 
   582 
   583 
   583     note: when interface is an entity class, the score will reflect class
   584     note: when interface is an entity class, the score will reflect class
   584           proximity so the most specific object'll be selected
   585           proximity so the most specific object'll be selected
   585     """
   586     """
   586     def score_class(self, eclass, req):
   587     def score_class(self, eclass, req):
   587         return self.score_interfaces(eclass, eclass)
   588         return self.score_interfaces(req, eclass, eclass)
   588 
   589 
   589 
   590 
   590 class specified_etype_implements(implements):
   591 class specified_etype_implements(implements):
   591     """accept if entity class specified using an 'etype' parameters in name
   592     """accept if entity class specified using an 'etype' parameters in name
   592     argument or request form implements at least one of the interfaces given as
   593     argument or request form implements at least one of the interfaces given as
   612                 return 0
   613                 return 0
   613         else:
   614         else:
   614             # only check this is a known type if etype comes from req.form,
   615             # only check this is a known type if etype comes from req.form,
   615             # else we want the error to propagate
   616             # else we want the error to propagate
   616             try:
   617             try:
   617                 etype = cls.vreg.case_insensitive_etypes[etype.lower()]
   618                 etype = req.vreg.case_insensitive_etypes[etype.lower()]
   618                 req.form['etype'] = etype
   619                 req.form['etype'] = etype
   619             except KeyError:
   620             except KeyError:
   620                 return 0
   621                 return 0
   621         return self.score_class(cls.vreg['etypes'].etype_class(etype), req)
   622         return self.score_class(req.vreg['etypes'].etype_class(etype), req)
   622 
   623 
   623 
   624 
   624 class entity_implements(ImplementsMixIn, EntitySelector):
   625 class entity_implements(ImplementsMixIn, EntitySelector):
   625     """accept if entity instances found in the result set implements at least one
   626     """accept if entity instances found in the result set implements at least one
   626     of the interfaces given as argument. Returned score is the number of
   627     of the interfaces given as argument. Returned score is the number of
   635 
   636 
   636     note: when interface is an entity class, the score will reflect class
   637     note: when interface is an entity class, the score will reflect class
   637           proximity so the most specific object'll be selected
   638           proximity so the most specific object'll be selected
   638     """
   639     """
   639     def score_entity(self, entity):
   640     def score_entity(self, entity):
   640         return self.score_interfaces(entity, entity.__class__)
   641         return self.score_interfaces(entity.req, entity, entity.__class__)
   641 
   642 
   642 
   643 
   643 class relation_possible(EClassSelector):
   644 class relation_possible(EClassSelector):
   644     """accept if entity class found in the result set support the relation.
   645     """accept if entity class found in the result set support the relation.
   645 
   646