# HG changeset patch # User Sylvain Thénault # Date 1359985195 -3600 # Node ID 51fdbbbd07b29d1aebafeda507cb499d5f047dce # Parent 5d08086c3e6dccfc2a7ec7a64f5349156605ab55 [predicates] fix 'adaptable' implementation, used to return 0 on a rset with individualy adaptable entities of different types. Closes #2709663 diff -r 5d08086c3e6d -r 51fdbbbd07b2 predicates.py --- a/predicates.py Wed Apr 03 14:33:20 2013 +0200 +++ b/predicates.py Mon Feb 04 14:39:55 2013 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -501,11 +501,30 @@ def __call__(self, cls, req, **kwargs): kwargs.setdefault('accept_none', False) - # being adaptable to an interface should takes precedence other is_instance('Any'), - # but not other explicit is_instance('SomeEntityType'), and: + score = super(adaptable, self).__call__(cls, req, **kwargs) + if score == 0 and kwargs.get('rset') and len(kwargs['rset']) > 1 and not 'row' in kwargs: + # on rset containing several entity types, each row may be + # individually adaptable, while the whole rset won't be if the + # same adapter can't be used for each type + for row in xrange(len(kwargs['rset'])): + kwargs.setdefault('col', 0) + _score = super(adaptable, self).__call__(cls, req, row=row, **kwargs) + if not _score: + return 0 + # adjust score per row as expected by default adjust_score + # implementation + score += self.adjust_score(_score) + else: + score = self.adjust_score(score) + return score + + @staticmethod + def adjust_score(score): + # being adaptable to an interface should takes precedence other + # is_instance('Any'), but not other explicit + # is_instance('SomeEntityType'), and, for **a single entity**: # * is_instance('Any') score is 1 # * is_instance('SomeEntityType') score is at least 2 - score = super(adaptable, self).__call__(cls, req, **kwargs) if score >= 2: return score - 0.5 if score == 1: diff -r 5d08086c3e6d -r 51fdbbbd07b2 test/unittest_predicates.py --- a/test/unittest_predicates.py Wed Apr 03 14:33:20 2013 +0200 +++ b/test/unittest_predicates.py Mon Feb 04 14:39:55 2013 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -27,6 +27,7 @@ multi_lines_rset, score_entity, is_in_state, rql_condition, relation_possible) from cubicweb.selectors import on_transition # XXX on_transition is deprecated +from cubicweb.view import EntityAdapter from cubicweb.web import action @@ -337,6 +338,22 @@ selector = rql_condition('U login "toto"', user_condition=True) self.assertEqual(selector(None, req), 0) + +class AdaptablePredicateTC(CubicWebTC): + + def test_multiple_entity_types_rset(self): + class CWUserIWhatever(EntityAdapter): + __regid__ = 'IWhatever' + __select__ = is_instance('CWUser') + class CWGroupIWhatever(EntityAdapter): + __regid__ = 'IWhatever' + __select__ = is_instance('CWGroup') + with self.temporary_appobjects(CWUserIWhatever, CWGroupIWhatever): + req = self.request() + selector = adaptable('IWhatever') + rset = req.execute('Any X WHERE X is IN(CWGroup, CWUser)') + self.assertTrue(selector(None, req, rset=rset)) + if __name__ == '__main__': unittest_main()