merge
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
Wed, 25 Mar 2009 14:42:44 +0100
changeset 1158 98f83f1588d7
parent 1157 81a383cdda5c (current diff)
parent 1140 79bcbb1c39ce (diff)
child 1159 16a426d214ae
merge
--- a/common/mixins.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/common/mixins.py	Wed Mar 25 14:42:44 2009 +0100
@@ -2,7 +2,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
--- a/common/selectors.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/common/selectors.py	Wed Mar 25 14:42:44 2009 +0100
@@ -61,7 +61,7 @@
     def traced(cls, *args, **kwargs):
         ret = selector(cls, *args, **kwargs)
         if TRACED_OIDS == 'all' or cls.id in TRACED_OIDS:
-            SELECTOR_LOGGER.warning('selector %s returned %s for %s', selector.__name__, ret, cls)
+            SELECTOR_LOGGER.critical('selector %s returned %s for %s', selector.__name__, ret, cls)
         return ret
     traced.__name__ = selector.__name__
     return traced
--- a/cwvreg.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/cwvreg.py	Wed Mar 25 14:42:44 2009 +0100
@@ -1,7 +1,7 @@
 """extend the generic VRegistry with some cubicweb specific stuff
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -12,7 +12,7 @@
 
 from rql import RQLHelper
 
-from cubicweb import Binary, UnknownProperty
+from cubicweb import Binary, UnknownProperty, UnknownEid
 from cubicweb.vregistry import VRegistry, ObjectNotFound, NoSelectableObject
 
 _ = unicode
@@ -337,7 +337,11 @@
         rqlst = self.rqlhelper.parse(rql)
         def type_from_eid(eid, session=session):
             return session.describe(eid)[0]
-        self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
+        try:
+            self.rqlhelper.compute_solutions(rqlst, {'eid': type_from_eid}, args)
+        except UnknownEid:
+            for select in rqlst.children:
+                select.solutions = []
         return rqlst
 
     @property
--- a/devtools/apptest.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/devtools/apptest.py	Wed Mar 25 14:42:44 2009 +0100
@@ -500,6 +500,6 @@
         self.rollback()
         self.session.unsafe_execute('DELETE Any X WHERE X eid > %(x)s', {'x': self.maxeid})
         self.commit()
-        if close:
-            self.close()
+        #if close:
+        #    self.close()
     
--- a/i18n/fr.po	Wed Mar 25 14:41:24 2009 +0100
+++ b/i18n/fr.po	Wed Mar 25 14:42:44 2009 +0100
@@ -918,7 +918,7 @@
 "s #%(toeid)s"
 
 msgid "address"
-msgstr "adresse"
+msgstr "adresse électronique"
 
 msgid "alias"
 msgstr "alias"
--- a/server/msplanner.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/server/msplanner.py	Wed Mar 25 14:42:44 2009 +0100
@@ -49,7 +49,7 @@
 
 
 :organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -149,7 +149,15 @@
                 select.append_selected(vref.copy(select))
                 if select.groupby and not vref in select.groupby:
                     select.add_group_var(vref.copy(select))
-            
+
+# XXX move to rql
+def is_ancestor(n1, n2):
+    p = n1.parent
+    while p is not None:
+        if p is n2:
+            return True
+        p = p.parent
+    return False
 
 class PartPlanInformation(object):
     """regroups necessary information to execute some part of a "global" rql
@@ -194,7 +202,7 @@
         self._inputmaps = {}
         if rqlhelper is not None: # else test
             self._insert_identity_variable = rqlhelper._annotator.rewrite_shared_optional
-
+            
     def copy_solutions(self, solindices):
         return [self._solutions[solidx].copy() for solidx in solindices]
     
@@ -431,8 +439,14 @@
                 # can't get information from relation inside a NOT exists
                 # where variables don't belong to the same scope
                 continue
-            if not (var.scope is rel.scope and ovar.scope is rel.scope) and rel.ored():
-                continue
+            need_ancestor_scope = False
+            if not (var.scope is rel.scope and ovar.scope is rel.scope):
+                if rel.ored():
+                    continue
+                if rel.ored(traverse_scope=True):
+                    # if relation has some OR as parent, constraints should only
+                    # propagate from parent scope to child scope, nothing else
+                    need_ancestor_scope = True
             relsources = self._session.repo.rel_type_sources(rel.r_type)
             if rel.neged(strict=True) and (
                 len(relsources) < 2
@@ -448,8 +462,10 @@
                 continue
             norelsup = self._norel_support_set(rel)
             # compute invalid sources for variables and remove them
-            self._remove_var_sources(var, norelsup, ovar, vsources)
-            self._remove_var_sources(ovar, norelsup, var, vsources)
+            if not need_ancestor_scope or is_ancestor(var.scope, ovar.scope):
+                self._remove_var_sources(var, norelsup, ovar, vsources)
+            if not need_ancestor_scope or is_ancestor(ovar.scope, var.scope):
+                self._remove_var_sources(ovar, norelsup, var, vsources)
     
     def _remove_var_sources(self, var, norelsup, ovar, vsources):
         """remove invalid sources for var according to ovar's sources and the
--- a/server/sources/extlite.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/server/sources/extlite.py	Wed Mar 25 14:42:44 2009 +0100
@@ -141,7 +141,7 @@
         
     def set_schema(self, schema):
         super(SQLiteAbstractSource, self).set_schema(schema)
-        if self._need_sql_create and self._is_schema_complete():
+        if self._need_sql_create and self._is_schema_complete() and self.dbpath:
             self._create_database()
         self.rqlsqlgen = self.sqlgen_class(schema, self.sqladapter.dbhelper)
                 
--- a/server/sources/rql2sql.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/server/sources/rql2sql.py	Wed Mar 25 14:42:44 2009 +0100
@@ -25,7 +25,7 @@
 
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -802,7 +802,7 @@
             else:
                 join += ')'
         if not rhsconst:
-            rhstable = self._var_table(rhsvar)
+            rhstable = rhsvar._q_sqltable
             if rhstable:
                 assert rhstable is not None, rhsvar
                 join += ' %s OUTER JOIN %s ON (%s.%s=%s)' % (
@@ -967,7 +967,10 @@
         """get the sql name for a subquery column alias"""
         if colalias.name in self._varmap:
             sql = self._varmap[colalias.name]
-            self.add_table(sql.split('.', 1)[0])
+            table = sql.split('.', 1)[0]
+            colalias._q_sqltable = table
+            colalias._q_sql = sql
+            self.add_table(table)
             return sql
         return colalias._q_sql
     
--- a/server/test/unittest_ldapuser.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/server/test/unittest_ldapuser.py	Wed Mar 25 14:42:44 2009 +0100
@@ -279,32 +279,39 @@
         rset = cu.execute('Any F WHERE X has_text "iaminguestsgrouponly", X firstname F')
         self.assertEquals(rset.rows, [[None]])
 
-    def test_nonregr_1(self):
+    def test_nonregr1(self):
         self.execute('Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E owned_by X, '
                      'X modification_date AA',
                      {'x': cnx.user(self.session).eid})
 
-    def test_nonregr_2(self):
+    def test_nonregr2(self):
         self.execute('Any X,L,AA WHERE E eid %(x)s, E owned_by X, '
                      'X login L, X modification_date AA',
                      {'x': cnx.user(self.session).eid})
 
-    def test_nonregr_3(self):
+    def test_nonregr3(self):
         self.execute('Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, '
                      'X modification_date AA',
                      {'x': cnx.user(self.session).eid})
 
-    def test_nonregr_4(self):
+    def test_nonregr4(self):
         emaileid = self.execute('INSERT EmailAddress X: X address "toto@logilab.org"')[0][0]
         self.execute('Any X,AA WHERE X use_email Y, Y eid %(x)s, X modification_date AA',
                      {'x': emaileid})
         
-    def test_nonregr_5(self):
+    def test_nonregr5(self):
         # original jpl query:
         # Any X, NOW - CD, P WHERE P is Project, U interested_in P, U is EUser, U login "sthenault", X concerns P, X creation_date CD ORDERBY CD DESC LIMIT 5
         rql = 'Any X, NOW - CD, P ORDERBY CD DESC LIMIT 5 WHERE P bookmarked_by U, U login "%s", P is X, X creation_date CD' % self.session.user.login
         self.execute(rql, )#{'x': })
         
+    def test_nonregr6(self):
+        self.execute('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File '
+                     'WITH U,UL BEING (Any U,UL WHERE ME eid %(x)s, (EXISTS(U identity ME) '
+                     'OR (EXISTS(U in_group G, G name IN("managers", "staff")))) '
+                     'OR (EXISTS(U in_group H, ME in_group H, NOT H name "users")), U login UL, U is EUser)',
+                     {'x': self.session.user.eid})
+
 
 class GlobTrFuncTC(TestCase):
 
--- a/server/test/unittest_msplanner.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/server/test/unittest_msplanner.py	Wed Mar 25 14:42:44 2009 +0100
@@ -1818,6 +1818,65 @@
                       )],
                    {'x': 999999})
 
+    def test_nonregr13_1(self):
+        # identity wrapped into exists:
+        # should'nt propagate constraint that U is in the same source as ME
+        self._test('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File '
+                   'WITH U,UL BEING (Any U,UL WHERE ME eid %(x)s, (EXISTS(U identity ME) '
+                   'OR (EXISTS(U in_group G, G name IN("managers", "staff")))) '
+                   'OR (EXISTS(U in_group H, ME in_group H, NOT H name "users")), U login UL, U is EUser)',
+                   [('FetchStep', [('Any U,UL WHERE U login UL, U is EUser',
+                                    [{'U': 'EUser', 'UL': 'String'}])],
+                     [self.ldap, self.system], None,
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     []),
+                    ('FetchStep', [('Any U,UL WHERE ((EXISTS(U identity 5)) OR (EXISTS(U in_group G, G name IN("managers", "staff"), G is EGroup))) OR (EXISTS(U in_group H, 5 in_group H, NOT H name "users", H is EGroup)), U login UL, U is EUser',
+                                    [{'G': 'EGroup', 'H': 'EGroup', 'U': 'EUser', 'UL': 'String'}])],
+                     [self.system],
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     {'U': 'table1.C0', 'U.login': 'table1.C1', 'UL': 'table1.C1'},
+                     []),
+                    ('OneFetchStep', [('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File',
+                                       [{'B': 'File', 'U': 'EUser', 'UL': 'String'}])],
+                     None, None, [self.system],
+                     {'U': 'table1.C0', 'UL': 'table1.C1'},
+                     [])],
+                   {'x': self.session.user.eid})
+        
+    def test_nonregr13_2(self):
+        # identity *not* wrapped into exists.
+        #
+        # XXX this test fail since in this case, in "U identity 5" U and 5 are
+        # from the same scope so constraints are applied (telling the U should
+        # come from the same source as user with eid 5).
+        #
+        # IMO this is normal, unless we introduce a special case for the
+        # identity relation. BUT I think it's better to leave it as is and to
+        # explain constraint propagation rules, and so why this should be
+        # wrapped in exists() is used in multi-source
+        self.skip('take a look at me if you wish')
+        self._test('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File '
+                   'WITH U,UL BEING (Any U,UL WHERE ME eid %(x)s, (U identity ME '
+                   'OR (EXISTS(U in_group G, G name IN("managers", "staff")))) '
+                   'OR (EXISTS(U in_group H, ME in_group H, NOT H name "users")), U login UL, U is EUser)',
+                   [('FetchStep', [('Any U,UL WHERE U login UL, U is EUser',
+                                    [{'U': 'EUser', 'UL': 'String'}])],
+                     [self.ldap, self.system], None,
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     []),
+                    ('FetchStep', [('Any U,UL WHERE ((U identity 5) OR (EXISTS(U in_group G, G name IN("managers", "staff"), G is EGroup))) OR (EXISTS(U in_group H, 5 in_group H, NOT H name "users", H is EGroup)), U login UL, U is EUser',
+                                    [{'G': 'EGroup', 'H': 'EGroup', 'U': 'EUser', 'UL': 'String'}])],
+                     [self.system],
+                     {'U': 'table0.C0', 'U.login': 'table0.C1', 'UL': 'table0.C1'},
+                     {'U': 'table1.C0', 'U.login': 'table1.C1', 'UL': 'table1.C1'},
+                     []),
+                    ('OneFetchStep', [('Any B,U,UL GROUPBY B,U,UL WHERE B created_by U?, B is File',
+                                       [{'B': 'File', 'U': 'EUser', 'UL': 'String'}])],
+                     None, None, [self.system],
+                     {'U': 'table1.C0', 'UL': 'table1.C1'},
+                     [])],
+                   {'x': self.session.user.eid})
+
 
 class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
     """test planner related feature on a 3-sources repository:
--- a/sobjects/notification.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/sobjects/notification.py	Wed Mar 25 14:42:44 2009 +0100
@@ -160,8 +160,8 @@
     def context(self, **kwargs):
         entity = self.entity(0, 0)
         for key, val in kwargs.iteritems():
-            if val and val.strip():
-                kwargs[key] = self.req._(val)
+            if val and isinstance(val, unicode) and val.strip():
+               kwargs[key] = self.req._(val)
         kwargs.update({'user': self.user_login(),
                        'eid': entity.eid,
                        'etype': entity.dc_type(),
--- a/web/htmlwidgets.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/web/htmlwidgets.py	Wed Mar 25 14:42:44 2009 +0100
@@ -4,7 +4,7 @@
 serialization time
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 
--- a/web/views/baseviews.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/web/views/baseviews.py	Wed Mar 25 14:42:44 2009 +0100
@@ -681,10 +681,9 @@
         """display a list of entities by calling their <item_vid> view"""
         req = self.req
         self.w(u'<?xml version="1.0" encoding="%s"?>\n' % req.encoding)
-        self.w(u'''<rdf:RDF
+        self.w(u'''<rss version="2.0"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns="http://purl.org/rss/1.0/"
 >''')
         self.w(u'  <channel rdf:about="%s">\n' % html_escape(req.url()))
         self.w(u'    <title>%s RSS Feed</title>\n' % html_escape(self.page_title()))
@@ -692,17 +691,10 @@
         params = req.form.copy()
         params.pop('vid', None)
         self.w(u'    <link>%s</link>\n' % html_escape(self.build_url(**params)))
-        self.w(u'    <items>\n')
-        self.w(u'      <rdf:Seq>\n')
-        for entity in self.rset.entities():
-            self.w(u'      <rdf:li resource="%s" />\n' % html_escape(entity.absolute_url()))
-        self.w(u'      </rdf:Seq>\n')
-        self.w(u'    </items>\n')
-        self.w(u'  </channel>\n')
         for i in xrange(self.rset.rowcount):
             self.cell_call(i, 0)
-        self.w(u'</rdf:RDF>')
-
+        self.w(u'  </channel>\n')
+        self.w(u'</rss>')       
 
 class RssItemView(EntityView):
     id = 'rssitem'
@@ -711,24 +703,29 @@
     def cell_call(self, row, col):
         entity = self.complete_entity(row, col)
         self.w(u'<item rdf:about="%s">\n' % html_escape(entity.absolute_url()))
+        self.render_title_link(entity)
+        self._marker('description', html_escape(entity.dc_description()))
+        self._marker('dc:date', entity.dc_date(self.date_format))
+        self.render_entity_creator(entity)
+        self.w(u'</item>\n')
+
+    def render_title_link(self, entity):
         self._marker('title', entity.dc_long_title())
         self._marker('link', entity.absolute_url())
-        self._marker('description', entity.dc_description())
-        self._marker('dc:date', entity.dc_date(self.date_format))
+           
+    def render_entity_creator(self, entity):
         if entity.creator:
-            self.w(u'<author>')
-            self._marker('name', entity.creator.name())
+            self._marker('dc:creator', entity.creator.name())
             email = entity.creator.get_email()
             if email:
-                self._marker('email', email)
-            self.w(u'</author>')
-        self.w(u'</item>\n')
+                self.w(u'<author>')
+                self.w(email)
+                self.w(u'</author>')       
         
     def _marker(self, marker, value):
         if value:
             self.w(u'  <%s>%s</%s>\n' % (marker, html_escape(value), marker))
 
-
 class CSVMixIn(object):
     """mixin class for CSV views"""
     templatable = False
--- a/web/views/iprogress.py	Wed Mar 25 14:41:24 2009 +0100
+++ b/web/views/iprogress.py	Wed Mar 25 14:42:44 2009 +0100
@@ -1,7 +1,7 @@
 """Specific views for entities implementing IProgress
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """