[predicates] fix 'adaptable' implementation, used to return 0 on a rset with individualy adaptable entities of different types. Closes #2709663
--- 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:
--- 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()