selectors.py
branchstable
changeset 6046 3fd4a34c4a09
parent 6008 e1c43115af3b
child 6106 1e6d93f70d14
equal deleted inserted replaced
6045:f414a587075d 6046:3fd4a34c4a09
   210 from cubicweb.appobject import Selector, objectify_selector, lltrace, yes
   210 from cubicweb.appobject import Selector, objectify_selector, lltrace, yes
   211 from cubicweb.schema import split_expression
   211 from cubicweb.schema import split_expression
   212 
   212 
   213 from cubicweb.appobject import traced_selection # XXX for bw compat
   213 from cubicweb.appobject import traced_selection # XXX for bw compat
   214 
   214 
   215 def score_interface(etypesreg, cls_or_inst, cls, iface):
   215 def score_interface(etypesreg, eclass, iface):
   216     """Return XXX if the give object (maybe an instance or class) implements
   216     """Return XXX if the give object (maybe an instance or class) implements
   217     the interface.
   217     the interface.
   218     """
   218     """
   219     if getattr(iface, '__registry__', None) == 'etypes':
   219     if getattr(iface, '__registry__', None) == 'etypes':
   220         # adjust score if the interface is an entity class
   220         # adjust score if the interface is an entity class
   221         parents = etypesreg.parent_classes(cls_or_inst.__regid__)
   221         parents, any = etypesreg.parent_classes(eclass.__regid__)
   222         if iface is cls:
   222         if iface is eclass:
   223             return len(parents) + 4
   223             return len(parents) + 4
   224         if iface is parents[-1]: # Any
   224         if iface is any: # Any
   225             return 1
   225             return 1
   226         for index, basecls in enumerate(reversed(parents[:-1])):
   226         for index, basecls in enumerate(reversed(parents)):
   227             if iface is basecls:
   227             if iface is basecls:
   228                 return index + 3
   228                 return index + 3
   229         return 0
   229         return 0
   230     # XXX iface in implements deprecated in 3.9
   230     # XXX iface in implements deprecated in 3.9
   231     if implements_iface(cls_or_inst, iface):
   231     if implements_iface(eclass, iface):
   232         # implenting an interface takes precedence other special Any interface
   232         # implementing an interface takes precedence other special Any interface
   233         return 2
   233         return 2
   234     return 0
   234     return 0
   235 
   235 
   236 
   236 
   237 # abstract selectors / mixin helpers ###########################################
   237 # abstract selectors / mixin helpers ###########################################
   697     def __str__(self):
   697     def __str__(self):
   698         return '%s(%s)' % (self.__class__.__name__,
   698         return '%s(%s)' % (self.__class__.__name__,
   699                            ','.join(str(s) for s in self.expected_ifaces))
   699                            ','.join(str(s) for s in self.expected_ifaces))
   700 
   700 
   701     def score_class(self, eclass, req):
   701     def score_class(self, eclass, req):
   702         return self.score_interfaces(req, eclass, eclass)
       
   703 
       
   704     def score_interfaces(self, req, cls_or_inst, cls):
       
   705         score = 0
   702         score = 0
   706         etypesreg = req.vreg['etypes']
   703         etypesreg = req.vreg['etypes']
   707         for iface in self.expected_ifaces:
   704         for iface in self.expected_ifaces:
   708             if isinstance(iface, basestring):
   705             if isinstance(iface, basestring):
   709                 # entity type
   706                 # entity type
   710                 try:
   707                 try:
   711                     iface = etypesreg.etype_class(iface)
   708                     iface = etypesreg.etype_class(iface)
   712                 except KeyError:
   709                 except KeyError:
   713                     continue # entity type not in the schema
   710                     continue # entity type not in the schema
   714             score += score_interface(etypesreg, cls_or_inst, cls, iface)
   711             score += score_interface(etypesreg, eclass, iface)
   715         return score
   712         return score
   716 
   713 
   717 def _reset_is_instance_cache(vreg):
   714 def _reset_is_instance_cache(vreg):
   718     vreg._is_instance_selector_cache = {}
   715     vreg._is_instance_selector_cache = {}
   719 
   716 
   742     def __str__(self):
   739     def __str__(self):
   743         return '%s(%s)' % (self.__class__.__name__,
   740         return '%s(%s)' % (self.__class__.__name__,
   744                            ','.join(str(s) for s in self.expected_etypes))
   741                            ','.join(str(s) for s in self.expected_etypes))
   745 
   742 
   746     def score_class(self, eclass, req):
   743     def score_class(self, eclass, req):
   747         return self.score_etypes(req, eclass, eclass)
       
   748 
       
   749     def score_etypes(self, req, cls_or_inst, cls):
       
   750         # cache on vreg to avoid reloading issues
   744         # cache on vreg to avoid reloading issues
   751         cache = req.vreg._is_instance_selector_cache
   745         cache = req.vreg._is_instance_selector_cache
   752         try:
   746         try:
   753             expected_eclasses = cache[self]
   747             expected_eclasses = cache[self]
   754         except KeyError:
   748         except KeyError:
   756             #  (entity class, parent classes)
   750             #  (entity class, parent classes)
   757             etypesreg = req.vreg['etypes']
   751             etypesreg = req.vreg['etypes']
   758             expected_eclasses = cache[self] = []
   752             expected_eclasses = cache[self] = []
   759             for etype in self.expected_etypes:
   753             for etype in self.expected_etypes:
   760                 try:
   754                 try:
   761                     expected_eclasses.append(
   755                     expected_eclasses.append(etypesreg.etype_class(etype))
   762                         (etypesreg.etype_class(etype),
       
   763                          etypesreg.parent_classes(etype))
       
   764                         )
       
   765                 except KeyError:
   756                 except KeyError:
   766                     continue # entity type not in the schema
   757                     continue # entity type not in the schema
       
   758         parents, any = req.vreg['etypes'].parent_classes(eclass.__regid__)
   767         score = 0
   759         score = 0
   768         for iface, parents in expected_eclasses:
   760         for expectedcls in expected_eclasses:
   769             # adjust score according to class proximity
   761             # adjust score according to class proximity
   770             if iface is cls:
   762             if expectedcls is eclass:
   771                 score += len(parents) + 4
   763                 score += len(parents) + 4
   772             elif iface is parents[-1]: # Any
   764             elif expectedcls is any: # Any
   773                 score += 1
   765                 score += 1
   774             else:
   766             else:
   775                 for index, basecls in enumerate(reversed(parents[:-1])):
   767                 for index, basecls in enumerate(reversed(parents)):
   776                     if iface is basecls:
   768                     if expectedcls is basecls:
   777                         score += index + 3
   769                         score += index + 3
   778                         break
   770                         break
   779         return score
   771         return score
   780 
   772 
   781 
   773