--- a/.hgtags Mon Dec 16 15:31:56 2013 +0100
+++ b/.hgtags Fri Jun 06 11:26:23 2014 +0200
@@ -81,3 +81,5 @@
5cad47e1ffbf6c9a234d8a355c3c93655ba32737 rql-centos-version-0.31.4-1
5cad47e1ffbf6c9a234d8a355c3c93655ba32737 rql-version-0.31.4
5cad47e1ffbf6c9a234d8a355c3c93655ba32737 rql-debian-version-0.31.4-1
+816abac7f9ad7e0cf4153adc33cb0f53b8ec7f6e rql-version-0.31.5
+2fd17ed747d80fc795e14e651abea64d4c9735ff rql-debian-version-0.31.5-1
--- a/ChangeLog Mon Dec 16 15:31:56 2013 +0100
+++ b/ChangeLog Fri Jun 06 11:26:23 2014 +0200
@@ -1,6 +1,13 @@
ChangeLog for RQL
=================
+2014-03-11 -- 0.31.5
+ * #176472: fix implementation of add_type_restriction vs is_instance_of
+
+ * #176469: add_type_restriction is not properly undoable in some cases
+
+
+
2012-03-29 -- 0.31.2
* #88559: speed up query solutions analysis
--- a/__pkginfo__.py Mon Dec 16 15:31:56 2013 +0100
+++ b/__pkginfo__.py Fri Jun 06 11:26:23 2014 +0200
@@ -20,7 +20,7 @@
__docformat__ = "restructuredtext en"
modname = "rql"
-numversion = (0, 31, 4)
+numversion = (0, 31, 5)
version = '.'.join(str(num) for num in numversion)
license = 'LGPL'
--- a/debian/changelog Mon Dec 16 15:31:56 2013 +0100
+++ b/debian/changelog Fri Jun 06 11:26:23 2014 +0200
@@ -1,3 +1,9 @@
+rql (0.31.5-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr> Tue, 11 Mar 2014 14:18:18 +0100
+
rql (0.31.4-1) unstable; urgency=low
* new upstream release
--- a/nodes.py Mon Dec 16 15:31:56 2013 +0100
+++ b/nodes.py Fri Jun 06 11:26:23 2014 +0200
@@ -1,4 +1,4 @@
-# copyright 2004-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2004-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of rql.
@@ -220,8 +220,8 @@
"""builds a restriction node to express : variable is etype"""
typerel = var.stinfo.get('typerel', None)
if typerel:
- istarget = typerel.children[1].children[0]
if typerel.r_type == 'is':
+ istarget = typerel.children[1].children[0]
if isinstance(istarget, Constant):
etypes = (istarget.value,)
else: # Function (IN)
@@ -232,26 +232,11 @@
# iterate a copy of children because it's modified inplace
for child in istarget.children[:]:
if child.value != etype:
- istarget.remove(child)
+ typerel.stmt.remove_node(child)
+ return typerel
else:
- # let's botte en touche IN cases (who would do that anyway ?)
- if isinstance(istarget, Function):
- msg = 'adding type restriction over is_instance_of IN is not supported'
- raise NotImplementedError(msg)
- schema = self.root.schema
- if schema is None:
- msg = 'restriction with is_instance_of cannot be done without a schema'
- raise RQLException(msg)
- # let's check the restriction is compatible
- eschema = schema[etype]
- ancestors = set(eschema.ancestors())
- ancestors.add(etype) # let's be unstrict
- if istarget.value in ancestors:
- istarget.value = etype
- else:
- raise RQLException('type restriction %s-%s cannot be made on %s' %
- (var, etype, self))
- return typerel
+ assert typerel.r_type == 'is_instance_of'
+ typerel.stmt.remove_node(typerel)
return self.add_constant_restriction(var, 'is', etype, 'etype')
@@ -539,7 +524,7 @@
if root is not None and root.should_register_op and value != self.optional:
from rql.undo import SetOptionalOperation
root.undo_manager.add_operation(SetOptionalOperation(self, self.optional))
- self.optional= value
+ self.set_optional(value)
CMP_OPERATORS = frozenset(('=', '!=', '<', '<=', '>=', '>', 'ILIKE', 'LIKE', 'REGEXP'))
--- a/test/unittest_nodes.py Mon Dec 16 15:31:56 2013 +0100
+++ b/test/unittest_nodes.py Fri Jun 06 11:26:23 2014 +0200
@@ -1,5 +1,5 @@
# -*- coding: iso-8859-1 -*-
-# copyright 2004-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2004-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of rql.
@@ -62,35 +62,48 @@
self.simplify = helper.simplify
def test_add_is_type_restriction(self):
- tree = self.parse('Any X WHERE X is Person')
+ tree = self.parse("Any X WHERE X is Person, X name ILIKE 'A%'")
select = tree.children[0]
x = select.get_selected_variables().next()
self.assertRaises(RQLException, select.add_type_restriction, x.variable, 'Babar')
select.add_type_restriction(x.variable, 'Person')
- self.assertEqual(tree.as_string(), 'Any X WHERE X is Person')
+ self.assertEqual(tree.as_string(), "Any X WHERE X is Person, X name ILIKE 'A%'")
def test_add_new_is_type_restriction_in(self):
+ tree = self.parse("Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
+ select = tree.children[0]
+ x = select.get_selected_variables().next()
+ select.add_type_restriction(x.variable, 'Company')
+ # implementation is KISS (the IN remains)
+ self.assertEqual(tree.as_string(), "Any X WHERE X is IN(Company), X name ILIKE 'A%'")
+
+ def test_add_new_is_type_restriction_in_nonregr(self):
tree = self.parse('Any X WHERE X is IN(Person, Company, Student)')
select = tree.children[0]
x = select.get_selected_variables().next()
select.add_type_restriction(x.variable, 'Person')
- # implementation is KISS (the IN remains)
self.assertEqual(tree.as_string(), 'Any X WHERE X is IN(Person)')
def test_add_is_in_type_restriction(self):
- tree = self.parse('Any X WHERE X is IN(Person, Company)')
+ tree = self.parse("Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
select = tree.children[0]
x = select.get_selected_variables().next()
self.assertRaises(RQLException, select.add_type_restriction, x.variable, 'Babar')
- self.assertEqual(tree.as_string(), 'Any X WHERE X is IN(Person, Company)')
+ self.assertEqual(tree.as_string(), "Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
+
+ def test_add_is_type_restriction_on_is_instance_of(self):
+ select = self.parse("Any X WHERE X is_instance_of Person, X name ILIKE 'A%'").children[0]
+ x = select.get_selected_variables().next()
+ select.add_type_restriction(x.variable, 'Person')
+ self.assertEqual(select.as_string(), "Any X WHERE X name ILIKE 'A%', X is Person")
- # XXX a full schema is needed, see test in cw/server/test/unittest_security
- # def test_add_is_against_isintance_type_restriction(self):
- # tree = self.parse('Any X WHERE X is_instance_of Person')
- # select = tree.children[0]
- # x = select.get_selected_variables().next()
- # select.add_type_restriction(x.variable, 'Student')
- # self.parse(tree.as_string())
+ def test_add_new_is_type_restriction_in_on_is_instance_of(self):
+ tree = self.parse("Any X WHERE X is_instance_of IN(Person, Company), X name ILIKE 'A%'")
+ select = tree.children[0]
+ x = select.get_selected_variables().next()
+ select.add_type_restriction(x.variable, 'Company')
+ self.assertEqual(tree.as_string(), "Any X WHERE X name ILIKE 'A%', X is Company")
+
class NodesTest(TestCase):
def _parse(self, rql, normrql=None):
@@ -291,6 +304,30 @@
tree.check_references()
self.assertEqual(tree.as_string(), 'Any X,Y GROUPBY X,Y')
+ def test_recover_add_type_restriction_is_in(self):
+ tree = self._parse("Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
+ annotator.annotate(tree) # needed to get typerel index
+ tree.save_state()
+ select = tree.children[0]
+ x = select.get_selected_variables().next()
+ select.add_type_restriction(x.variable, 'Company')
+ self.assertEqual(tree.as_string(), "Any X WHERE X is IN(Company), X name ILIKE 'A%'")
+ tree.recover()
+ tree.check_references()
+ self.assertEqual(tree.as_string(), "Any X WHERE X is IN(Person, Company), X name ILIKE 'A%'")
+
+ def test_recover_add_type_restriction_is_instance_of(self):
+ tree = self._parse("Any X WHERE X is_instance_of IN(Person, Company), X name ILIKE 'A%'")
+ annotator.annotate(tree) # needed to get typerel index
+ tree.save_state()
+ select = tree.children[0]
+ x = select.get_selected_variables().next()
+ select.add_type_restriction(x.variable, 'Company')
+ self.assertEqual(tree.as_string(), "Any X WHERE X name ILIKE 'A%', X is Company")
+ tree.recover()
+ tree.check_references()
+ self.assertEqual(tree.as_string(), "Any X WHERE X is_instance_of IN(Person, Company), X name ILIKE 'A%'")
+
def test_select_base_1(self):
tree = self._parse("Any X WHERE X is Person")
self.assertIsInstance(tree, stmts.Union)