diff --git a/astroid/brain/brain_dataclasses.py b/astroid/brain/brain_dataclasses.py index 7bb2a60f01..6ea145117a 100644 --- a/astroid/brain/brain_dataclasses.py +++ b/astroid/brain/brain_dataclasses.py @@ -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) diff --git a/astroid/brain/brain_namedtuple_enum.py b/astroid/brain/brain_namedtuple_enum.py index 2ce69a90a3..1ca661fad8 100644 --- a/astroid/brain/brain_namedtuple_enum.py +++ b/astroid/brain/brain_namedtuple_enum.py @@ -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() diff --git a/astroid/mixins.py b/astroid/mixins.py index d7c027a14a..3241ecea2e 100644 --- a/astroid/mixins.py +++ b/astroid/mixins.py @@ -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""" @@ -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 @@ -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 diff --git a/astroid/nodes/node_classes.py b/astroid/nodes/node_classes.py index 0dcb685da3..df2d70dff6 100644 --- a/astroid/nodes/node_classes.py +++ b/astroid/nodes/node_classes.py @@ -386,8 +386,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( @@ -437,15 +439,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: @@ -566,7 +575,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): @@ -1830,13 +1839,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) diff --git a/astroid/nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes.py index 444e8a6511..57df442801 100644 --- a/astroid/nodes/scoped_nodes.py +++ b/astroid/nodes/scoped_nodes.py @@ -2587,7 +2587,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 diff --git a/astroid/protocols.py b/astroid/protocols.py index 4ec92a2a22..674766e163 100644 --- a/astroid/protocols.py +++ b/astroid/protocols.py @@ -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.", diff --git a/tests/unittest_builder.py b/tests/unittest_builder.py index d0afbc8a2e..7d516b54ac 100644 --- a/tests/unittest_builder.py +++ b/tests/unittest_builder.py @@ -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)