[rqlrewrite] Test and fix potential NameError
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 21 Nov 2016 15:17:32 +0100
changeset 11855 e6cdc4d3add5
parent 11854 056de1196ef8
child 11856 92e9cbc6fc57
[rqlrewrite] Test and fix potential NameError We were referencing a loop variable, which may lead to a name error and show a potential error if there are several matching variables. To avoid this, introduce a list to hold every encountered variable and process all of them later.
cubicweb/rqlrewrite.py
cubicweb/test/unittest_rqlrewrite.py
--- a/cubicweb/rqlrewrite.py	Wed Nov 16 15:55:35 2016 +0100
+++ b/cubicweb/rqlrewrite.py	Mon Nov 21 15:17:32 2016 +0100
@@ -580,6 +580,7 @@
                     done.add(rel)
                     rschema = get_rschema(rel.r_type)
                     if rschema.final or rschema.inlined:
+                        subselect_vrefs = []
                         rel.children[0].name = varname # XXX explain why
                         subselect.add_restriction(rel.copy(subselect))
                         for vref in rel.children[1].iget_nodes(n.VariableRef):
@@ -592,6 +593,7 @@
                                     "least uninline %s" % rel.r_type)
                             subselect.append_selected(vref.copy(subselect))
                             aliases.append(vref.name)
+                            subselect_vrefs.append(vref)
                         self.select.remove_node(rel)
                         # when some inlined relation has to be copied in the
                         # subquery and that relation is optional, we need to
@@ -602,14 +604,15 @@
                         # also, if some attributes or inlined relation of the
                         # object variable are accessed, we need to get all those
                         # from the subquery as well
-                        if vref.name not in done and rschema.inlined:
-                            # we can use vref here define in above for loop
-                            ostinfo = vref.variable.stinfo
-                            for orel in iter_relations(ostinfo):
-                                orschema = get_rschema(orel.r_type)
-                                if orschema.final or orschema.inlined:
-                                    todo.append( (vref.name, ostinfo) )
-                                    break
+                        for vref in subselect_vrefs:
+                            if vref.name not in done and rschema.inlined:
+                                # we can use vref here define in above for loop
+                                ostinfo = vref.variable.stinfo
+                                for orel in iter_relations(ostinfo):
+                                    orschema = get_rschema(orel.r_type)
+                                    if orschema.final or orschema.inlined:
+                                        todo.append( (vref.name, ostinfo) )
+                                        break
             if need_null_test:
                 snippetrqlst = n.Or(
                     n.make_relation(subselect.get_variable(selectvar), 'is',
--- a/cubicweb/test/unittest_rqlrewrite.py	Wed Nov 16 15:55:35 2016 +0100
+++ b/cubicweb/test/unittest_rqlrewrite.py	Mon Nov 21 15:17:32 2016 +0100
@@ -215,6 +215,12 @@
         self.assertEqual(rqlst.as_string(),
                          u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))')
 
+    def test_ambiguous_optional_same_exprs_constant(self):
+        rqlst = parse(u'Any A,AR,X WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date TODAY')
+        rewrite(rqlst, {('X', 'X'): ('X created_by U',),}, {'a': 3})
+        self.assertEqual(rqlst.as_string(),
+                         u'Any A,AR,X WHERE A concerne X?, A ref AR, A eid %(a)s WITH X BEING (Any X WHERE X creation_date TODAY, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))')
+
     def test_optional_var_inlined(self):
         c1 = ('X require_permission P')
         c2 = ('X inlined_card O, O require_permission P')