Currently if pylint is run under Python 2.7 to check a file containing dictionary comprehensions or set comprehensions, it results in an exception in the astng code.

The attached patches (against the current hg tip) add support for these constructs to astng.

Cheers,

Daniel Harding
# HG changeset patch
# User Daniel Harding <[email protected]>
# Date 1285956113 0
# Branch stable
# Node ID c50ddf5bf2e4c4643a453b968138340551bdea17
# Parent  24cc9d8273ce8c15e7e73020aa3ed2d8c4d6b76d
[mq]: add_dictcomp

diff -r 24cc9d8273ce -r c50ddf5bf2e4 _nodes_ast.py
--- a/_nodes_ast.py     Tue Sep 28 14:33:56 2010 +0200
+++ b/_nodes_ast.py     Fri Oct 01 18:01:53 2010 +0000
@@ -328,6 +328,17 @@
         newnode.set_line_info(newnode.last_child())
         return newnode
 
+    def visit_dictcomp(self, node, parent):
+        """visit a DictComp node by returning a fresh instance of it"""
+        newnode = new.DictComp()
+        _lineno_parent(node, newnode, parent)
+        newnode.key = self.visit(node.key, newnode)
+        newnode.value = self.visit(node.value, newnode)
+        newnode.generators = [self.visit(child, newnode)
+                              for child in node.generators]
+        newnode.set_line_info(newnode.last_child())
+        return newnode
+
     def visit_discard(self, node, parent):
         """visit a Discard node by returning a fresh instance of it"""
         newnode = new.Discard()
diff -r 24cc9d8273ce -r c50ddf5bf2e4 node_classes.py
--- a/node_classes.py   Tue Sep 28 14:33:56 2010 +0200
+++ b/node_classes.py   Fri Oct 01 18:01:53 2010 +0000
@@ -505,6 +505,14 @@
         raise IndexError(key)
 
 
+class DictComp(NodeNG):
+    """class representing a DictComp node"""
+    _astng_fields = ('key', 'value', 'generators')
+    key = None
+    value = None
+    generators = None
+
+
 class Discard(StmtMixIn, NodeNG):
     """class representing a Discard node"""
     _astng_fields = ('value',)
diff -r 24cc9d8273ce -r c50ddf5bf2e4 nodes.py
--- a/nodes.py  Tue Sep 28 14:33:56 2010 +0200
+++ b/nodes.py  Fri Oct 01 18:01:53 2010 +0000
@@ -54,8 +54,8 @@
 from logilab.astng.node_classes import Arguments, AssAttr, Assert, Assign, \
     AssName, AugAssign, Backquote, BinOp, BoolOp, Break, CallFunc, Compare, \
     Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete, \
-    Dict, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice, For, \
-    From, Getattr, Global, If, IfExp, Import, Index, Keyword, \
+    Dict, DictComp, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, \
+    ExtSlice, For, From, Getattr, Global, If, IfExp, Import, Index, Keyword, \
     List, ListComp, Name, Pass, Print, Raise, Return, Slice, Subscript, \
     TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, const_factory
 from logilab.astng.scoped_nodes import Module, GenExpr, Lambda, Function, Class
@@ -65,7 +65,7 @@
     Backquote, BinOp, BoolOp, Break,
     CallFunc, Class, Compare, Comprehension, Const, Continue,
     Decorators, DelAttr, DelName, Delete,
-    Dict, Discard,
+    Dict, DictComp, Discard,
     Ellipsis, EmptyNode, ExceptHandler, Exec, ExtSlice,
     For, From, Function,
     Getattr, GenExpr, Global,
diff -r 24cc9d8273ce -r c50ddf5bf2e4 nodes_as_string.py
--- a/nodes_as_string.py        Tue Sep 28 14:33:56 2010 +0200
+++ b/nodes_as_string.py        Fri Oct 01 18:01:53 2010 +0000
@@ -173,7 +173,12 @@
         """return an astng.Dict node as string"""
         return '{%s}' % ', '.join(['%s: %s' % (key.accept(self), 
                             value.accept(self)) for key, value in node.items])
-    
+
+    def visit_dictcomp(self, node):
+        """return an astng.DictComp node as string"""
+        return '[%s: %s %s]' % (node.key.accept(self), node.value.accept(self),
+                ' '.join([n.accept(self) for n in node.generators]))
+
     def visit_discard(self, node):
         """return an astng.Discard node as string"""
         return node.value.accept(self)
@@ -233,7 +238,7 @@
                                         docs, self._stmt_list(node.body))
     
     def visit_genexpr(self, node):
-        """return an astng.ListComp node as string"""
+        """return an astng.GenExpr node as string"""
         return '(%s %s)' % (node.elt.accept(self), ' '.join([n.accept(self)
                                                     for n in node.generators]))
     
diff -r 24cc9d8273ce -r c50ddf5bf2e4 test/unittest_lookup.py
--- a/test/unittest_lookup.py   Tue Sep 28 14:33:56 2010 +0200
+++ b/test/unittest_lookup.py   Fri Oct 01 18:01:53 2010 +0000
@@ -169,6 +169,26 @@
         self.assertEqual(xnames[2].lookup('i')[1][0].lineno, 4)
 
 
+    def test_dict_comps(self):
+        if sys.version_info < (2, 7):
+            self.skipTest('this test require python >= 2.7')
+        astng = builder.string_build("""
+print { i: j for i in range(10) for j in range(10) }
+print { i: j for i in range(10) for j in range(10) }
+        """, __name__, __file__)
+        xnames = [n for n in astng.nodes_of_class(nodes.Name) if n.name == 'i']
+        self.assertEqual(len(xnames[0].lookup('i')[1]), 1)
+        self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2)
+        self.assertEqual(len(xnames[1].lookup('i')[1]), 1)
+        self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3)
+
+        xnames = [n for n in astng.nodes_of_class(nodes.Name) if n.name == 'j']
+        self.assertEqual(len(xnames[0].lookup('i')[1]), 1)
+        self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2)
+        self.assertEqual(len(xnames[1].lookup('i')[1]), 1)
+        self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3)
+
+
     def test_explicit___name__(self):
         code = '''
 class Pouet:
diff -r 24cc9d8273ce -r c50ddf5bf2e4 utils.py
--- a/utils.py  Tue Sep 28 14:33:56 2010 +0200
+++ b/utils.py  Fri Oct 01 18:01:53 2010 +0000
@@ -114,6 +114,9 @@
     def visit_dict(self, node):
         """dummy method for visiting an Dict node"""
 
+    def visit_dictcomp(self, node):
+        """dummy method for visiting an DictComp node"""
+
     def visit_discard(self, node):
         """dummy method for visiting an Discard node"""
 
# HG changeset patch
# User Daniel Harding <[email protected]>
# Date 1285956119 0
# Branch stable
# Node ID f9d932900b24a1da313d0df56b55937a4f5b05ca
# Parent  c50ddf5bf2e4c4643a453b968138340551bdea17
add support for set comprehensions

diff -r c50ddf5bf2e4 -r f9d932900b24 _nodes_ast.py
--- a/_nodes_ast.py     Fri Oct 01 18:01:53 2010 +0000
+++ b/_nodes_ast.py     Fri Oct 01 18:01:59 2010 +0000
@@ -590,6 +590,16 @@
         newnode.set_line_info(newnode.last_child())
         return newnode
 
+    def visit_setcomp(self, node, parent):
+        """visit a SetComp node by returning a fresh instance of it"""
+        newnode = new.SetComp()
+        _lineno_parent(node, newnode, parent)
+        newnode.elt = self.visit(node.elt, newnode)
+        newnode.generators = [self.visit(child, newnode)
+                              for child in node.generators]
+        newnode.set_line_info(newnode.last_child())
+        return newnode
+
     def visit_slice(self, node, parent):
         """visit a Slice node by returning a fresh instance of it"""
         newnode = new.Slice()
diff -r c50ddf5bf2e4 -r f9d932900b24 node_classes.py
--- a/node_classes.py   Fri Oct 01 18:01:53 2010 +0000
+++ b/node_classes.py   Fri Oct 01 18:01:59 2010 +0000
@@ -697,6 +697,13 @@
     value = None
 
 
+class SetComp(NodeNG):
+    """class representing a SetComp node"""
+    _astng_fields = ('elt', 'generators')
+    elt = None
+    generators = None
+
+
 class Slice(NodeNG):
     """class representing a Slice node"""
     _astng_fields = ('lower', 'upper', 'step')
diff -r c50ddf5bf2e4 -r f9d932900b24 nodes.py
--- a/nodes.py  Fri Oct 01 18:01:53 2010 +0000
+++ b/nodes.py  Fri Oct 01 18:01:59 2010 +0000
@@ -56,8 +56,9 @@
     Comprehension, Const, Continue, Decorators, DelAttr, DelName, Delete, \
     Dict, DictComp, Discard, Ellipsis, EmptyNode, ExceptHandler, Exec, \
     ExtSlice, For, From, Getattr, Global, If, IfExp, Import, Index, Keyword, \
-    List, ListComp, Name, Pass, Print, Raise, Return, Slice, Subscript, \
-    TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, const_factory
+    List, ListComp, Name, Pass, Print, Raise, Return, SetComp, Slice, \
+    Subscript, TryExcept, TryFinally, Tuple, UnaryOp, While, With, Yield, \
+    const_factory
 from logilab.astng.scoped_nodes import Module, GenExpr, Lambda, Function, Class
 
 ALL_NODE_CLASSES = (
@@ -76,7 +77,7 @@
     Module,
     Pass, Print,
     Raise, Return,
-    Slice, Subscript,
+    SetComp, Slice, Subscript,
     TryExcept, TryFinally, Tuple,
     UnaryOp,
     While, With,
diff -r c50ddf5bf2e4 -r f9d932900b24 nodes_as_string.py
--- a/nodes_as_string.py        Fri Oct 01 18:01:53 2010 +0000
+++ b/nodes_as_string.py        Fri Oct 01 18:01:59 2010 +0000
@@ -330,6 +330,11 @@
         """return a astng.Index node as string"""
         return node.value.accept(self)
 
+    def visit_setcomp(self, node):
+        """return an astng.SetComp node as string"""
+        return '[%s %s]' % (node.elt.accept(self), ' '.join([n.accept(self)
+                                                for n in node.generators]))
+
     def visit_slice(self, node):
         """return a astng.Slice node as string"""
         lower = node.lower and node.lower.accept(self) or ''
diff -r c50ddf5bf2e4 -r f9d932900b24 test/unittest_lookup.py
--- a/test/unittest_lookup.py   Fri Oct 01 18:01:53 2010 +0000
+++ b/test/unittest_lookup.py   Fri Oct 01 18:01:59 2010 +0000
@@ -189,6 +189,20 @@
         self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3)
 
 
+    def test_set_comps(self):
+        if sys.version_info < (2, 7):
+            self.skipTest('this test require python >= 2.7')
+        astng = builder.string_build("""
+print { i for i in range(10) }
+print { i for i in range(10) }
+        """, __name__, __file__)
+        xnames = [n for n in astng.nodes_of_class(nodes.Name) if n.name == 'i']
+        self.assertEqual(len(xnames[0].lookup('i')[1]), 1)
+        self.assertEqual(xnames[0].lookup('i')[1][0].lineno, 2)
+        self.assertEqual(len(xnames[1].lookup('i')[1]), 1)
+        self.assertEqual(xnames[1].lookup('i')[1][0].lineno, 3)
+
+
     def test_explicit___name__(self):
         code = '''
 class Pouet:
diff -r c50ddf5bf2e4 -r f9d932900b24 utils.py
--- a/utils.py  Fri Oct 01 18:01:53 2010 +0000
+++ b/utils.py  Fri Oct 01 18:01:59 2010 +0000
@@ -198,6 +198,9 @@
     def visit_return(self, node):
         """dummy method for visiting an Return node"""
 
+    def visit_setcomp(self, node):
+        """dummy method for visiting an SetComp node"""
+
     def visit_slice(self, node):
         """dummy method for visiting an Slice node"""
 
_______________________________________________
Python-Projects mailing list
[email protected]
http://lists.logilab.org/mailman/listinfo/python-projects

Reply via email to