summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--astroid/node_classes.py4
-rw-r--r--astroid/rebuilder.py16
-rw-r--r--astroid/tests/unittest_nodes.py21
4 files changed, 45 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 2b76b8fa..35688bd3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,18 @@
astroid's ChangeLog
===================
+What's New in astroid 2.3.2?
+============================
+Release Date: TBA
+
+* All type comments have as parent the corresponding `astroid` node
+
+ Until now they had as parent the builtin `ast` node which meant
+ we were operating with primitive objects instead of our own.
+
+ Close PyCQA/pylint#3174
+
+
What's New in astroid 2.3.1?
============================
Release Date: 2019-09-30
diff --git a/astroid/node_classes.py b/astroid/node_classes.py
index b9af5983..994c96bd 100644
--- a/astroid/node_classes.py
+++ b/astroid/node_classes.py
@@ -496,7 +496,9 @@ class NodeNG:
:returns: The first parent scope node.
:rtype: Module or FunctionDef or ClassDef or Lambda or GenExpr
"""
- return self.parent.scope()
+ if self.parent:
+ return self.parent.scope()
+ return None
def root(self):
"""Return the root node of the syntax tree.
diff --git a/astroid/rebuilder.py b/astroid/rebuilder.py
index 09c9304b..fb78f7bb 100644
--- a/astroid/rebuilder.py
+++ b/astroid/rebuilder.py
@@ -218,7 +218,9 @@ class TreeRebuilder:
self.visit(arg.annotation, newnode) if arg.annotation else None
for arg in node.posonlyargs
]
- type_comment_args = [self.check_type_comment(child) for child in node.args]
+ type_comment_args = [
+ self.check_type_comment(child, parent=newnode) for child in node.args
+ ]
newnode.postinit(
args=args,
@@ -250,7 +252,7 @@ class TreeRebuilder:
newnode.postinit(self.visit(node.test, newnode), msg)
return newnode
- def check_type_comment(self, node):
+ def check_type_comment(self, node, parent):
type_comment = getattr(node, "type_comment", None)
if not type_comment:
return None
@@ -261,7 +263,7 @@ class TreeRebuilder:
# Invalid type comment, just skip it.
return None
- type_object = self.visit(type_comment_ast.body[0], node)
+ type_object = self.visit(type_comment_ast.body[0], parent=parent)
if not isinstance(type_object, nodes.Expr):
return None
@@ -289,8 +291,8 @@ class TreeRebuilder:
def visit_assign(self, node, parent):
"""visit a Assign node by returning a fresh instance of it"""
- type_annotation = self.check_type_comment(node)
newnode = nodes.Assign(node.lineno, node.col_offset, parent)
+ type_annotation = self.check_type_comment(node, parent=newnode)
newnode.postinit(
targets=[self.visit(child, newnode) for child in node.targets],
value=self.visit(node.value, newnode),
@@ -550,7 +552,7 @@ class TreeRebuilder:
def _visit_for(self, cls, node, parent):
"""visit a For node by returning a fresh instance of it"""
newnode = cls(node.lineno, node.col_offset, parent)
- type_annotation = self.check_type_comment(node)
+ type_annotation = self.check_type_comment(node, parent=newnode)
newnode.postinit(
target=self.visit(node.target, newnode),
iter=self.visit(node.iter, newnode),
@@ -912,7 +914,7 @@ class TreeRebuilder:
else:
optional_vars = None
- type_annotation = self.check_type_comment(node)
+ type_annotation = self.check_type_comment(node, parent=newnode)
newnode.postinit(
items=[(expr, optional_vars)],
body=[self.visit(child, newnode) for child in node.body],
@@ -1026,7 +1028,7 @@ class TreeRebuilder3(TreeRebuilder):
var = _visit_or_none(child, "optional_vars", self, newnode)
return expr, var
- type_annotation = self.check_type_comment(node)
+ type_annotation = self.check_type_comment(node, parent=newnode)
newnode.postinit(
items=[visit_child(child) for child in node.items],
body=[self.visit(child, newnode) for child in node.body],
diff --git a/astroid/tests/unittest_nodes.py b/astroid/tests/unittest_nodes.py
index ff1cca07..79b9936e 100644
--- a/astroid/tests/unittest_nodes.py
+++ b/astroid/tests/unittest_nodes.py
@@ -1195,5 +1195,26 @@ def test_parse_fstring_debug_mode():
assert node.as_string() == "f'3={3}'"
+@pytest.mark.skipif(not HAS_TYPED_AST, reason="requires typed_ast")
+def test_parse_type_comments_with_proper_parent():
+ code = """
+ class D: #@
+ @staticmethod
+ def g(
+ x # type: np.array
+ ):
+ pass
+ """
+ node = astroid.extract_node(code)
+ func = node.getattr("g")[0]
+ type_comments = func.args.type_comment_args
+ assert len(type_comments) == 1
+
+ type_comment = type_comments[0]
+ assert isinstance(type_comment, astroid.Attribute)
+ assert isinstance(type_comment.parent, astroid.Expr)
+ assert isinstance(type_comment.parent.parent, astroid.Arguments)
+
+
if __name__ == "__main__":
unittest.main()