merge 3.16.x fix in 3.17.x branch
authorPierre-Yves David <pierre-yves.david@logilab.fr>
Mon, 08 Apr 2013 14:45:10 +0200
changeset 8867 6ad000b91347
parent 8852 59a29405688c (current diff)
parent 8866 64f24ecad177 (diff)
child 8885 b3409c1dc012
merge 3.16.x fix in 3.17.x branch
__pkginfo__.py
predicates.py
server/querier.py
server/ssplanner.py
web/facet.py
--- a/.hgtags	Thu Apr 04 17:45:09 2013 +0200
+++ b/.hgtags	Mon Apr 08 14:45:10 2013 +0200
@@ -258,6 +258,8 @@
 81394043ad226942ac0019b8e1d4f7058d67a49f cubicweb-debian-version-3.14.8-1
 9337812cef6b949eee89161190e0c3d68d7f32ea cubicweb-version-3.14.9
 68c762adf2d5a2c338910ef1091df554370586f0 cubicweb-debian-version-3.14.9-1
+0ff798f80138ca8f50a59f42284380ce8f6232e8 cubicweb-version-3.14.10
+197bcd087c87cd3de9f21f5bf40bd6203c074f1f cubicweb-debian-version-3.14.10-1
 783a5df54dc742e63c8a720b1582ff08366733bd cubicweb-version-3.15.1
 fe5e60862b64f1beed2ccdf3a9c96502dfcd811b cubicweb-debian-version-3.15.1-1
 2afc157ea9b2b92eccb0f2d704094e22ce8b5a05 cubicweb-version-3.15.2
@@ -278,6 +280,8 @@
 29fbc632a69667840294d7b38b0ca00e5f66ec19 cubicweb-debian-version-3.15.9-1
 89bdb5444cd20213d5af03c2612ceb28340cb760 cubicweb-version-3.15.10
 feca12e4a6188fbaae0cc48c6f8cc5f4202e1662 cubicweb-debian-version-3.15.10-1
+38c6a3ea8252e1a40452aad05e4aa25b43f66cd8 cubicweb-version-3.15.11
+09d65bc1f0253eacef4b480716b7c139ab9efc35 cubicweb-debian-version-3.15.11-1
 6c7c2a02c9a0ca870accfc8ed1bb120e9c858d5d cubicweb-version-3.16.0
 853237d1daf6710af94cc2ec8ee12aa7dba16934 cubicweb-debian-version-3.16.0-1
 d95cbb7349f01b9e02e5da65d55a92582bbee6db cubicweb-version-3.16.1
--- a/debian/changelog	Thu Apr 04 17:45:09 2013 +0200
+++ b/debian/changelog	Mon Apr 08 14:45:10 2013 +0200
@@ -10,6 +10,12 @@
 
  -- Aurélien Campéas <aurelien.campeas@logilab.fr>  Wed, 23 Jan 2013 17:40:00 +0100
 
+cubicweb (3.15.11-1) squeeze; urgency=low
+
+  * New upstream release
+
+ -- Pierre-Yves David <pierre-yves.david@logilab.fr>  Mon, 08 Apr 2013 12:43:02 +0200
+
 cubicweb (3.15.10-1) squeeze; urgency=low
 
   * New upstream release
@@ -85,6 +91,12 @@
 
  -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Thu, 12 Apr 2012 13:52:05 +0200
 
+cubicweb (3.14.10-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Pierre-Yves David <pierre-yves.david@logilab.fr>  Mon, 08 Apr 2013 12:18:20 +0200
+
 cubicweb (3.14.9-1) unstable; urgency=low
 
   * new upstream release
--- a/devtools/devctl.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/devtools/devctl.py	Mon Apr 08 14:45:10 2013 +0200
@@ -675,13 +675,13 @@
 class ExamineLogCommand(Command):
     """Examine a rql log file.
 
-    will print out the following table
+    Will print out the following table
 
-      total execution time || number of occurences || rql query
+      Percentage; Cumulative Time (clock); Cumulative Time (CPU); Occurences; Query
 
-    sorted by descending total execution time
+    sorted by descending cumulative time (clock). Time are expressed in seconds.
 
-    chances are the lines at the top are the ones that will bring the higher
+    Chances are the lines at the top are the ones that will bring the higher
     benefit after optimisation. Start there.
     """
     arguments = 'rql.log'
--- a/predicates.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/predicates.py	Mon Apr 08 14:45:10 2013 +0200
@@ -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.
@@ -479,11 +479,8 @@
 
     def __call__(self, cls, req, **kwargs):
         for regid in self.regids:
-            try:
-                req.vreg[self.registry].select(regid, req, **kwargs)
+            if req.vreg[self.registry].select_or_none(regid, req, **kwargs) is not None:
                 return self.selectable_score
-            except NoSelectableObject:
-                continue
         return 0
 
 
@@ -501,11 +498,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/server/querier.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/server/querier.py	Mon Apr 08 14:45:10 2013 +0200
@@ -63,8 +63,9 @@
 def check_no_password_selected(rqlst):
     """check that Password entities are not selected"""
     for solution in rqlst.solutions:
-        if 'Password' in solution.itervalues():
-            raise Unauthorized('Password selection is not allowed')
+        for var, etype in solution.iteritems():
+            if etype == 'Password':
+                raise Unauthorized('Password selection is not allowed (%s)' % var)
 
 def term_etype(session, term, solution, args):
     """return the entity type for the given term (a VariableRef or a Constant
--- a/server/ssplanner.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/server/ssplanner.py	Mon Apr 08 14:45:10 2013 +0200
@@ -76,7 +76,12 @@
     checkread = session.read_security
     eschema = session.vreg.schema.eschema
     for rel in rqlst.where.get_nodes(Relation):
-        if rel.r_type == 'eid' and not rel.neged(strict=True):
+        # only care for 'eid' relations ...
+        if (rel.r_type == 'eid'
+            # ... that are not part of a NOT clause ...
+            and not rel.neged(strict=True)
+            # ... and where eid is specified by '=' operator.
+            and rel.children[1].operator == '='):
             lhs, rhs = rel.get_variable_parts()
             if isinstance(rhs, Constant):
                 eid = int(rhs.eval(plan.args))
--- a/server/test/unittest_querier.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/server/test/unittest_querier.py	Mon Apr 08 14:45:10 2013 +0200
@@ -1562,5 +1562,28 @@
             res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'})
             self.assertEqual(res.rows, [[aff2.eid]])
 
+    def test_set_relations_eid(self):
+        req = self.request()
+        # create 3 email addresses
+        a1 = req.create_entity('EmailAddress', address=u'a1')
+        a2 = req.create_entity('EmailAddress', address=u'a2')
+        a3 = req.create_entity('EmailAddress', address=u'a3')
+        # SET relations using '>=' operator on eids
+        req.execute('SET U use_email A WHERE U login "admin", A eid >= %s' % a2.eid)
+        self.assertEqual(
+            [[a2.eid], [a3.eid]],
+            req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
+        # DELETE
+        req.execute('DELETE U use_email A WHERE U login "admin", A eid > %s' % a2.eid)
+        self.assertEqual(
+            [[a2.eid]],
+            req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
+        req.execute('DELETE U use_email A WHERE U login "admin"')
+        # SET relations using '<' operator on eids
+        req.execute('SET U use_email A WHERE U login "admin", A eid < %s' % a2.eid)
+        self.assertEqual(
+            [[a1.eid]],
+            req.execute('Any A ORDERBY A WHERE U use_email A, U login "admin"').rows)
+
 if __name__ == '__main__':
     unittest_main()
--- a/test/unittest_predicates.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/test/unittest_predicates.py	Mon Apr 08 14:45:10 2013 +0200
@@ -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.
@@ -26,6 +26,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
 
 
@@ -336,6 +337,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()
 
--- a/web/facet.py	Thu Apr 04 17:45:09 2013 +0200
+++ b/web/facet.py	Mon Apr 08 14:45:10 2013 +0200
@@ -66,7 +66,7 @@
 
 from cubicweb import Unauthorized
 from cubicweb.schema import display_name
-from cubicweb.uilib import css_em_num_value
+from cubicweb.uilib import css_em_num_value, domid
 from cubicweb.utils import make_uid
 from cubicweb.predicates import match_context_prop, partial_relation_possible
 from cubicweb.appobject import AppObject
@@ -1449,7 +1449,7 @@
     def _render(self):
         w = self.w
         title = xml_escape(self.facet.title)
-        facetid = make_uid(self.facet.__regid__)
+        facetid = domid(make_uid(self.facet.__regid__))
         w(u'<div id="%s" class="facet">\n' % facetid)
         cssclass = 'facetTitle'
         if self.facet.allow_hide: