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 |