# HG changeset patch # User Adrien Di Mascio # Date 1237988564 -3600 # Node ID 98f83f1588d723cb3f1e7ec6f3a4d2da2c0a7e7a # Parent 81a383cdda5c38a7135cf680a96b554376bf4653# Parent 79bcbb1c39ce428f8302596409e163b1d7ffe552 merge diff -r 81a383cdda5c -r 98f83f1588d7 common/mixins.py --- 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" diff -r 81a383cdda5c -r 98f83f1588d7 common/selectors.py --- 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 diff -r 81a383cdda5c -r 98f83f1588d7 cwvreg.py --- 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 diff -r 81a383cdda5c -r 98f83f1588d7 devtools/apptest.py --- 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() diff -r 81a383cdda5c -r 98f83f1588d7 i18n/fr.po --- 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" diff -r 81a383cdda5c -r 98f83f1588d7 server/msplanner.py --- 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 diff -r 81a383cdda5c -r 98f83f1588d7 server/sources/extlite.py --- 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) diff -r 81a383cdda5c -r 98f83f1588d7 server/sources/rql2sql.py --- 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 diff -r 81a383cdda5c -r 98f83f1588d7 server/test/unittest_ldapuser.py --- 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): diff -r 81a383cdda5c -r 98f83f1588d7 server/test/unittest_msplanner.py --- 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: diff -r 81a383cdda5c -r 98f83f1588d7 sobjects/notification.py --- 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(), diff -r 81a383cdda5c -r 98f83f1588d7 web/htmlwidgets.py --- 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 """ diff -r 81a383cdda5c -r 98f83f1588d7 web/views/baseviews.py --- 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 view""" req = self.req self.w(u'\n' % req.encoding) - self.w(u'''''') self.w(u' \n' % html_escape(req.url())) self.w(u' %s RSS Feed\n' % html_escape(self.page_title())) @@ -692,17 +691,10 @@ params = req.form.copy() params.pop('vid', None) self.w(u' %s\n' % html_escape(self.build_url(**params))) - self.w(u' \n') - self.w(u' \n') - for entity in self.rset.entities(): - self.w(u' \n' % html_escape(entity.absolute_url())) - self.w(u' \n') - self.w(u' \n') - self.w(u' \n') for i in xrange(self.rset.rowcount): self.cell_call(i, 0) - self.w(u'') - + self.w(u' \n') + self.w(u'') class RssItemView(EntityView): id = 'rssitem' @@ -711,24 +703,29 @@ def cell_call(self, row, col): entity = self.complete_entity(row, col) self.w(u'\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'\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'') - 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'') - self.w(u'\n') + self.w(u'') + self.w(email) + self.w(u'') def _marker(self, marker, value): if value: self.w(u' <%s>%s\n' % (marker, html_escape(value), marker)) - class CSVMixIn(object): """mixin class for CSV views""" templatable = False diff -r 81a383cdda5c -r 98f83f1588d7 web/views/iprogress.py --- 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 """