192 |
192 |
193 __docformat__ = "restructuredtext en" |
193 __docformat__ = "restructuredtext en" |
194 |
194 |
195 import logging |
195 import logging |
196 from warnings import warn |
196 from warnings import warn |
|
197 from operator import eq |
197 |
198 |
198 from logilab.common.deprecation import class_renamed |
199 from logilab.common.deprecation import class_renamed |
199 from logilab.common.compat import all, any |
200 from logilab.common.compat import all, any |
200 from logilab.common.interface import implements as implements_iface |
201 from logilab.common.interface import implements as implements_iface |
201 |
202 |
528 return 1 |
529 return 1 |
529 return 0 |
530 return 0 |
530 |
531 |
531 |
532 |
532 class multi_lines_rset(Selector): |
533 class multi_lines_rset(Selector): |
533 """If `nb` is specified, return 1 if the result set has exactly `nb` row of |
534 """Return 1 if the operator expression matches between `num` elements |
534 result. Else (`nb` is None), return 1 if the result set contains *at least* |
535 in the result set and the `expected` value if defined. |
|
536 |
|
537 By default, multi_lines_rset(expected) matches equality expression: |
|
538 `nb` row(s) in result set equals to expected value |
|
539 But, you can perform richer comparisons by overriding default operator: |
|
540 multi_lines_rset(expected, operator.gt) |
|
541 |
|
542 If `expected` is None, return 1 if the result set contains *at least* |
535 two rows. |
543 two rows. |
536 """ |
544 If rset is None, return 0. |
537 def __init__(self, nb=None): |
545 """ |
538 self.expected = nb |
546 def __init__(self, expected=None, operator=eq): |
|
547 self.expected = expected |
|
548 self.operator = operator |
539 |
549 |
540 def match_expected(self, num): |
550 def match_expected(self, num): |
541 if self.expected is None: |
551 if self.expected is None: |
542 return num > 1 |
552 return num > 1 |
543 return num == self.expected |
553 return self.operator(num, self.expected) |
544 |
554 |
545 @lltrace |
555 @lltrace |
546 def __call__(self, cls, req, rset=None, **kwargs): |
556 def __call__(self, cls, req, rset=None, **kwargs): |
547 return int(rset is not None and self.match_expected(rset.rowcount)) |
557 return int(rset is not None and self.match_expected(rset.rowcount)) |
548 |
558 |
1037 def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs): |
1047 def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs): |
1038 if kwargs.get('entity'): |
1048 if kwargs.get('entity'): |
1039 return self.score_entity(kwargs['entity']) |
1049 return self.score_entity(kwargs['entity']) |
1040 if rset is None: |
1050 if rset is None: |
1041 return 0 |
1051 return 0 |
1042 user = req.user |
|
1043 action = self.action |
|
1044 if row is None: |
1052 if row is None: |
1045 score = 0 |
1053 score = 0 |
1046 need_local_check = [] |
1054 need_local_check = [] |
1047 geteschema = req.vreg.schema.eschema |
1055 geteschema = req.vreg.schema.eschema |
|
1056 user = req.user |
|
1057 action = self.action |
1048 for etype in rset.column_types(0): |
1058 for etype in rset.column_types(0): |
1049 if etype in BASE_TYPES: |
1059 if etype in BASE_TYPES: |
1050 return 0 |
1060 return 0 |
1051 eschema = geteschema(etype) |
1061 eschema = geteschema(etype) |
1052 if not user.matching_groups(eschema.get_groups(action)): |
1062 if not user.matching_groups(eschema.get_groups(action)): |
1059 return 0 |
1069 return 0 |
1060 score += 1 |
1070 score += 1 |
1061 if need_local_check: |
1071 if need_local_check: |
1062 # check local role for entities of necessary types |
1072 # check local role for entities of necessary types |
1063 for i, row in enumerate(rset): |
1073 for i, row in enumerate(rset): |
1064 if not rset.description[i][0] in need_local_check: |
1074 if not rset.description[i][col] in need_local_check: |
1065 continue |
1075 continue |
1066 if not self.score(req, rset, i, col): |
1076 # micro-optimisation instead of calling self.score(req, |
|
1077 # rset, i, col): rset may be large |
|
1078 if not rset.get_entity(i, col).cw_has_perm(action): |
1067 return 0 |
1079 return 0 |
1068 score += 1 |
1080 score += 1 |
1069 return score |
1081 return score |
1070 return self.score(req, rset, row, col) |
1082 return self.score(req, rset, row, col) |
1071 |
1083 |