fix add_type_restriction() implementation with IN() function (closes #138635)

When the variable type is defined by an IN() function, add_type_restriction removes all types in it that don't match the specified type. Since the list of types is modified inplace, the iteration must be done on a copy, not on the list itself.

There was a test for "add_type_restriction + IN()" case but since there was only 2 types defined in the IN function, the problem was not exposed.

authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
changeset3e6b5f8cc4d2
branchstable
phasepublic
hiddenno
parent revision#cb978d851ad1 Added tag rql-centos-version-0.31.3-1 for changeset 496945a4ed23
child revision#0842fc538834 [pkg] Make sure the gecode extension build never ever fails, #0dff683ca149 remove has_key usage, #679566d1203d [pkg] Make sure the gecode extension build never ever fails (closes #158948)
files modified by this revision
nodes.py
test/unittest_nodes.py
# HG changeset patch
# User Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
# Date 1368599546 -7200
# Wed May 15 08:32:26 2013 +0200
# Branch stable
# Node ID 3e6b5f8cc4d22d3f6154101b66e89ccefcd09c30
# Parent cb978d851ad130fa006afecd63e2a88a2dafbdc9
fix add_type_restriction() implementation with IN() function (closes #138635)

When the variable type is defined by an IN() function, ``add_type_restriction``
removes all types in it that don't match the specified type. Since the list
of types is modified inplace, the iteration must be done on a copy, not on
the list itself.

There was a test for "add_type_restriction + IN()" case but since there
was only 2 types defined in the IN function, the problem was not exposed.

diff --git a/nodes.py b/nodes.py
@@ -227,11 +227,12 @@
1                  else: # Function (IN)
2                      etypes = [et.value for et in istarget.children]
3                  if etype not in etypes:
4                      raise RQLException('%r not in %r' % (etype, etypes))
5                  if len(etypes) > 1:
6 -                    for child in istarget.children:
7 +                    # iterate a copy of children because it's modified inplace
8 +                    for child in istarget.children[:]:
9                          if child.value != etype:
10                              istarget.remove(child)
11              else:
12                  # let's botte en touche IN cases (who would do that anyway ?)
13                  if isinstance(istarget, Function):
diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py
@@ -68,16 +68,16 @@
14          self.assertRaises(RQLException, select.add_type_restriction, x.variable, 'Babar')
15          select.add_type_restriction(x.variable, 'Person')
16          self.assertEqual(tree.as_string(), 'Any X WHERE X is Person')
17 
18      def test_add_new_is_type_restriction_in(self):
19 -        tree = self.parse('Any X WHERE X is IN(Person, Company)')
20 +        tree = self.parse('Any X WHERE X is IN(Person, Company, Student)')
21          select = tree.children[0]
22          x = select.get_selected_variables().next()
23 -        select.add_type_restriction(x.variable, 'Company')
24 +        select.add_type_restriction(x.variable, 'Person')
25          # implementation is KISS (the IN remains)
26 -        self.assertEqual(tree.as_string(), 'Any X WHERE X is IN(Company)')
27 +        self.assertEqual(tree.as_string(), 'Any X WHERE X is IN(Person)')
28 
29      def test_add_is_in_type_restriction(self):
30          tree = self.parse('Any X WHERE X is IN(Person, Company)')
31          select = tree.children[0]
32          x = select.get_selected_variables().next()