selectors.py
branchtls-sprint
changeset 779 8510e14335e1
parent 774 48cb1f42e79c
child 784 33db07c66789
equal deleted inserted replaced
778:847db4c91061 779:8510e14335e1
    52 from yams import BASE_TYPES
    52 from yams import BASE_TYPES
    53 
    53 
    54 from cubicweb import Unauthorized, NoSelectableObject, role
    54 from cubicweb import Unauthorized, NoSelectableObject, role
    55 from cubicweb.vregistry import (NoSelectableObject, Selector,
    55 from cubicweb.vregistry import (NoSelectableObject, Selector,
    56                                 chainall, chainfirst, objectify_selector)
    56                                 chainall, chainfirst, objectify_selector)
    57 from cubicweb.cwvreg import DummyCursorError
       
    58 from cubicweb.cwconfig import CubicWebConfiguration
    57 from cubicweb.cwconfig import CubicWebConfiguration
    59 from cubicweb.schema import split_expression
    58 from cubicweb.schema import split_expression
    60 
    59 
    61 # helpers for debugging selectors
    60 # helpers for debugging selectors
    62 SELECTOR_LOGGER = logging.getLogger('cubicweb.selectors')
    61 SELECTOR_LOGGER = logging.getLogger('cubicweb.selectors')
    68         return selector
    67         return selector
    69     def traced(cls, *args, **kwargs):
    68     def traced(cls, *args, **kwargs):
    70         # /!\ lltrace decorates pure function or __call__ method, this
    69         # /!\ lltrace decorates pure function or __call__ method, this
    71         #     means argument order may be different
    70         #     means argument order may be different
    72         if isinstance(cls, Selector):
    71         if isinstance(cls, Selector):
    73             selname = cls.__class__.__name__
    72             selname = str(cls)
    74             vobj = args[0]
    73             vobj = args[0]
    75         else:
    74         else:
    76             selname = selector.__name__
    75             selname = selector.__name__
    77             vobj = cls
    76             vobj = cls
    78         oid = vobj.id
    77         oid = vobj.id
   126       - `once_is_enough` is True, in which case the first non-zero score is
   125       - `once_is_enough` is True, in which case the first non-zero score is
   127         returned
   126         returned
   128       - `once_is_enough` is False, in which case if score_class return 0, 0 is
   127       - `once_is_enough` is False, in which case if score_class return 0, 0 is
   129         returned
   128         returned
   130     """
   129     """
   131     def __init__(self, once_is_enough=False):
   130     def __init__(self, once_is_enough=False, sumscores=True):
   132         self.once_is_enough = once_is_enough
   131         self.once_is_enough = once_is_enough
       
   132         self.sumscores = sumscores
   133     
   133     
   134     @lltrace
   134     @lltrace
   135     def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
   135     def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
   136         if not rset:
   136         if not rset:
   137             return 0
   137             return 0
   148                 score += escore
   148                 score += escore
   149         else:
   149         else:
   150             etype = rset.description[row][col]
   150             etype = rset.description[row][col]
   151             if etype is not None:
   151             if etype is not None:
   152                 score = self.score(cls, req, etype)
   152                 score = self.score(cls, req, etype)
   153         return score and (score + 1)
   153         return score
   154 
   154 
   155     def score(self, cls, req, etype):
   155     def score(self, cls, req, etype):
   156         if etype in BASE_TYPES:
   156         if etype in BASE_TYPES:
   157             return 0
   157             return 0
   158         return self.score_class(cls.vreg.etype_class(etype), req)
   158         return self.score_class(cls.vreg.etype_class(etype), req)
   195                 score += escore
   195                 score += escore
   196         else:
   196         else:
   197             etype = rset.description[row][col]
   197             etype = rset.description[row][col]
   198             if etype is not None: # outer join
   198             if etype is not None: # outer join
   199                 score = self.score(req, rset, row, col)
   199                 score = self.score(req, rset, row, col)
   200         return score and (score + 1)
   200         return score
   201 
   201 
   202     def score(self, req, rset, row, col):
   202     def score(self, req, rset, row, col):
   203         try:
   203         try:
   204             return self.score_entity(rset.get_entity(row, col))
   204             return self.score_entity(rset.get_entity(row, col))
   205         except NotAnEntity:
   205         except NotAnEntity:
   384                      object to create a relation with another)
   384                      object to create a relation with another)
   385     """
   385     """
   386     def __init__(self, *expected):
   386     def __init__(self, *expected):
   387         assert expected, self
   387         assert expected, self
   388         self.expected = frozenset(expected)
   388         self.expected = frozenset(expected)
       
   389 
       
   390     def __str__(self):
       
   391         return '%s(%s)' % (self.__class__.__name__,
       
   392                            ','.join(sorted(str(s) for s in self.expected)))
   389         
   393         
   390     @lltrace
   394     @lltrace
   391     def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
   395     def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
   392         try:
   396         try:
   393             if not req.search_state[0] in self.expected:
   397             if not req.search_state[0] in self.expected:
   500     """
   504     """
   501     def __init__(self, *expected_ifaces):
   505     def __init__(self, *expected_ifaces):
   502         super(implements, self).__init__()
   506         super(implements, self).__init__()
   503         self.expected_ifaces = expected_ifaces
   507         self.expected_ifaces = expected_ifaces
   504 
   508 
       
   509     def __str__(self):
       
   510         return '%s(%s)' % (self.__class__.__name__,
       
   511                            ','.join(str(s) for s in self.expected_ifaces))
       
   512     
   505     def score_class(self, eclass, req):
   513     def score_class(self, eclass, req):
   506         score = 0
   514         score = 0
   507         for iface in self.expected_ifaces:
   515         for iface in self.expected_ifaces:
   508             if isinstance(iface, basestring):
   516             if isinstance(iface, basestring):
   509                 # entity type
   517                 # entity type
   510                 iface = eclass.vreg.etype_class(iface)
   518                 iface = eclass.vreg.etype_class(iface)
   511             if implements_iface(eclass, iface):
   519             if implements_iface(eclass, iface):
   512                 score += 1
       
   513                 if getattr(iface, '__registry__', None) == 'etypes':
   520                 if getattr(iface, '__registry__', None) == 'etypes':
   514                     score += 1
       
   515                     # adjust score if the interface is an entity class
   521                     # adjust score if the interface is an entity class
   516                     if iface is eclass:
   522                     if iface is eclass:
   517                         score += (len(eclass.e_schema.ancestors()) + 1)
   523                         score += len(eclass.e_schema.ancestors()) + 4
   518 #                        print 'is majoration', len(eclass.e_schema.ancestors()) 
   524                     else: 
   519                     else:
       
   520                         parents = [e.type for e in eclass.e_schema.ancestors()]
   525                         parents = [e.type for e in eclass.e_schema.ancestors()]
   521                         for index, etype in enumerate(reversed(parents)):
   526                         for index, etype in enumerate(reversed(parents)):
   522                             basecls = eclass.vreg.etype_class(etype)
   527                             basecls = eclass.vreg.etype_class(etype)
   523                             if iface is basecls:
   528                             if iface is basecls:
   524                                 score += index
   529                                 score += index + 3
   525 #                                print 'etype majoration', index
       
   526                                 break
   530                                 break
       
   531                         else: # Any
       
   532                             score += 1
       
   533                 else:
       
   534                     # implenting an interface takes precedence other special Any
       
   535                     # interface
       
   536                     score += 2
   527         return score
   537         return score
   528 
   538 
   529 
   539 
   530 class specified_etype_implements(implements):
   540 class specified_etype_implements(implements):
   531     """accept if entity class specified using an 'etype' parameters in name
   541     """accept if entity class specified using an 'etype' parameters in name