--- 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
"""