Skip to content

Commit

Permalink
Add future argument to all NodeNG.statement() calls (#1235)
Browse files Browse the repository at this point in the history
* Add ``future`` argument to all ``NodeNG.statement()`` calls

* Add typing from ``statement()``

Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
  • Loading branch information
DanielNoord and cdce8p authored Nov 24, 2021
1 parent 7ed1ee9 commit 4443159
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 19 deletions.
2 changes: 1 addition & 1 deletion astroid/brain/brain_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ def _looks_like_dataclass_field_call(node: Call, check_scope: bool = True) -> bo
If check_scope is False, skips checking the statement and body.
"""
if check_scope:
stmt = node.statement()
stmt = node.statement(future=True)
scope = stmt.scope()
if not (
isinstance(stmt, AnnAssign)
Expand Down
2 changes: 1 addition & 1 deletion astroid/brain/brain_namedtuple_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ def infer_enum_class(node):
if any(not isinstance(value, nodes.AssignName) for value in values):
continue

stmt = values[0].statement()
stmt = values[0].statement(future=True)
if isinstance(stmt, nodes.Assign):
if isinstance(stmt.targets[0], nodes.Tuple):
targets = stmt.targets[0].itered()
Expand Down
14 changes: 10 additions & 4 deletions astroid/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@
"""This module contains some mixins for the different nodes.
"""
import itertools
from typing import TYPE_CHECKING, Optional

from astroid import decorators
from astroid.exceptions import AttributeInferenceError

if TYPE_CHECKING:
from astroid import nodes


class BlockRangeMixIn:
"""override block range"""
Expand All @@ -44,9 +48,9 @@ def _elsed_block_range(self, lineno, orelse, last=None):
class FilterStmtsMixin:
"""Mixin for statement filtering and assignment type"""

def _get_filtered_stmts(self, _, node, _stmts, mystmt):
def _get_filtered_stmts(self, _, node, _stmts, mystmt: Optional["nodes.Statement"]):
"""method used in _filter_stmts to get statements and trigger break"""
if self.statement() is mystmt:
if self.statement(future=True) is mystmt:
# original node's statement is the assignment, only keep
# current node (gen exp, list comp)
return [node], True
Expand All @@ -60,11 +64,13 @@ class AssignTypeMixin:
def assign_type(self):
return self

def _get_filtered_stmts(self, lookup_node, node, _stmts, mystmt):
def _get_filtered_stmts(
self, lookup_node, node, _stmts, mystmt: Optional["nodes.Statement"]
):
"""method used in filter_stmts"""
if self is mystmt:
return _stmts, True
if self.statement() is mystmt:
if self.statement(future=True) is mystmt:
# original node's statement is the assignment, only keep
# current node (gen exp, list comp)
return [node], True
Expand Down
29 changes: 20 additions & 9 deletions astroid/nodes/node_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,10 @@ def ilookup(self, name):
context = InferenceContext()
return _infer_stmts(stmts, context, frame)

def _get_filtered_node_statements(self, nodes):
statements = [(node, node.statement()) for node in nodes]
def _get_filtered_node_statements(
self, nodes: typing.List[NodeNG]
) -> typing.List[typing.Tuple[NodeNG, Statement]]:
statements = [(node, node.statement(future=True)) for node in nodes]
# Next we check if we have ExceptHandlers that are parent
# of the underlying variable, in which case the last one survives
if len(statements) > 1 and all(
Expand Down Expand Up @@ -451,15 +453,22 @@ def _filter_stmts(self, stmts, frame, offset):
#
# def test(b=1):
# ...

if self.statement() is myframe and myframe.parent:
if (
self.parent
and self.statement(future=True) is myframe
and myframe.parent
):
myframe = myframe.parent.frame()
mystmt = self.statement()

mystmt: Optional[Statement] = None
if self.parent:
mystmt = self.statement(future=True)

# line filtering if we are in the same frame
#
# take care node may be missing lineno information (this is the case for
# nodes inserted for living objects)
if myframe is frame and mystmt.fromlineno is not None:
if myframe is frame and mystmt and mystmt.fromlineno is not None:
assert mystmt.fromlineno is not None, mystmt
mylineno = mystmt.fromlineno + offset
else:
Expand Down Expand Up @@ -580,7 +589,7 @@ def _filter_stmts(self, stmts, frame, offset):
_stmt_parents = []
else:
continue
elif not optional_assign and stmt.parent is mystmt.parent:
elif not optional_assign and mystmt and stmt.parent is mystmt.parent:
_stmts = []
_stmt_parents = []
elif isinstance(node, DelName):
Expand Down Expand Up @@ -2022,13 +2031,15 @@ def assign_type(self):
"""
return self

def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt):
def _get_filtered_stmts(
self, lookup_node, node, stmts, mystmt: Optional[Statement]
):
"""method used in filter_stmts"""
if self is mystmt:
if isinstance(lookup_node, (Const, Name)):
return [lookup_node], True

elif self.statement() is mystmt:
elif self.statement(future=True) is mystmt:
# original node's statement is the assignment, only keeps
# current node (gen exp, list comp)

Expand Down
2 changes: 1 addition & 1 deletion astroid/nodes/scoped_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2739,7 +2739,7 @@ def getattr(self, name, context=None, class_context=True):
# Look for AnnAssigns, which are not attributes in the purest sense.
for value in values:
if isinstance(value, node_classes.AssignName):
stmt = value.statement()
stmt = value.statement(future=True)
if isinstance(stmt, node_classes.AnnAssign) and stmt.value is None:
raise AttributeInferenceError(
target=self, attribute=name, context=context
Expand Down
2 changes: 1 addition & 1 deletion astroid/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ def _determine_starred_iteration_lookups(starred, target, lookups):
lookups.append((index, len(element.itered())))
_determine_starred_iteration_lookups(starred, element, lookups)

stmt = self.statement()
stmt = self.statement(future=True)
if not isinstance(stmt, (nodes.Assign, nodes.For)):
raise InferenceError(
"Statement {stmt!r} enclosing {node!r} " "must be an Assign or For node.",
Expand Down
3 changes: 1 addition & 2 deletions tests/unittest_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,8 @@ def test_module_base_props(self) -> None:
self.assertEqual(module.pure_python, 1)
self.assertEqual(module.package, 0)
self.assertFalse(module.is_statement)
self.assertEqual(module.statement(), module)
with pytest.warns(DeprecationWarning) as records:
module.statement()
self.assertEqual(module.statement(), module)
assert len(records) == 1
with self.assertRaises(StatementMissing):
module.statement(future=True)
Expand Down

0 comments on commit 4443159

Please sign in to comment.