Skip to content

Commit c285fae

Browse files
Add future=True to all NodeNG.statement() calls (#5310)
Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 9909dae commit c285fae

File tree

7 files changed

+64
-32
lines changed

7 files changed

+64
-32
lines changed

pylint/checkers/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ def visit_starred(self, node: nodes.Starred) -> None:
606606
# PEP 448 unpacking.
607607
return
608608

609-
stmt = node.statement()
609+
stmt = node.statement(future=True)
610610
if not isinstance(stmt, nodes.Assign):
611611
return
612612

pylint/checkers/classes.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,9 @@ def _check_attribute_defined_outside_init(self, cnode: nodes.ClassDef) -> None:
10521052
nodes_lst = [
10531053
n
10541054
for n in nodes_lst
1055-
if not isinstance(n.statement(), (nodes.Delete, nodes.AugAssign))
1055+
if not isinstance(
1056+
n.statement(future=True), (nodes.Delete, nodes.AugAssign)
1057+
)
10561058
and n.root() is current_module
10571059
]
10581060
if not nodes_lst:
@@ -1651,7 +1653,7 @@ def _check_protected_attribute_access(self, node: nodes.Attribute):
16511653
# class A:
16521654
# b = property(lambda: self._b)
16531655

1654-
stmt = node.parent.statement()
1656+
stmt = node.parent.statement(future=True)
16551657
if (
16561658
isinstance(stmt, nodes.Assign)
16571659
and len(stmt.targets) == 1
@@ -1796,7 +1798,7 @@ def _check_accessed_members(self, node, accessed):
17961798
_node.frame() is frame
17971799
and _node.fromlineno < lno
17981800
and not astroid.are_exclusive(
1799-
_node.statement(), defstmt, excs
1801+
_node.statement(future=True), defstmt, excs
18001802
)
18011803
):
18021804
self.add_message(

pylint/checkers/format.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,10 @@ def visit_default(self, node: nodes.NodeNG) -> None:
602602
isinstance(node.parent, nodes.TryFinally) and node in node.parent.finalbody
603603
):
604604
prev_line = node.parent.body[0].tolineno + 1
605+
elif isinstance(node.parent, nodes.Module):
606+
prev_line = 0
605607
else:
606-
prev_line = node.parent.statement().fromlineno
608+
prev_line = node.parent.statement(future=True).fromlineno
607609
line = node.fromlineno
608610
assert line, node
609611
if prev_line == line and self._visited_lines.get(line) != 2:

pylint/checkers/typecheck.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
from typing import Any, Callable, Iterator, List, Optional, Pattern, Tuple
7373

7474
import astroid
75+
import astroid.exceptions
7576
from astroid import bases, nodes
7677

7778
from pylint.checkers import BaseChecker, utils
@@ -615,7 +616,7 @@ def _has_parent_of_type(node, node_type, statement):
615616

616617

617618
def _no_context_variadic_keywords(node, scope):
618-
statement = node.statement()
619+
statement = node.statement(future=True)
619620
variadics = ()
620621

621622
if isinstance(scope, nodes.Lambda) and not isinstance(scope, nodes.FunctionDef):
@@ -649,7 +650,7 @@ def _no_context_variadic(node, variadic_name, variadic_type, variadics):
649650
is_in_lambda_scope = not isinstance(scope, nodes.FunctionDef) and isinstance(
650651
scope, nodes.Lambda
651652
)
652-
statement = node.statement()
653+
statement = node.statement(future=True)
653654
for name in statement.nodes_of_class(nodes.Name):
654655
if name.name != variadic_name:
655656
continue
@@ -667,7 +668,7 @@ def _no_context_variadic(node, variadic_name, variadic_type, variadics):
667668
# so we need to go the lambda instead
668669
inferred_statement = inferred.parent.parent
669670
else:
670-
inferred_statement = inferred.statement()
671+
inferred_statement = inferred.statement(future=True)
671672

672673
if not length and isinstance(inferred_statement, nodes.Lambda):
673674
is_in_starred_context = _has_parent_of_type(node, variadic_type, statement)
@@ -1029,10 +1030,12 @@ def visit_attribute(self, node: nodes.Attribute) -> None:
10291030
if not [
10301031
n
10311032
for n in owner.getattr(node.attrname)
1032-
if not isinstance(n.statement(), nodes.AugAssign)
1033+
if not isinstance(n.statement(future=True), nodes.AugAssign)
10331034
]:
10341035
missingattr.add((owner, name))
10351036
continue
1037+
except astroid.exceptions.StatementMissing:
1038+
continue
10361039
except AttributeError:
10371040
continue
10381041
except astroid.DuplicateBasesError:

pylint/checkers/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ def is_defined_before(var_node: nodes.Name) -> bool:
401401
if is_defined_in_scope(var_node, varname, parent):
402402
return True
403403
# possibly multiple statements on the same line using semi colon separator
404-
stmt = var_node.statement()
404+
stmt = var_node.statement(future=True)
405405
_node = stmt.previous_sibling()
406406
lineno = stmt.fromlineno
407407
while _node and _node.fromlineno == lineno:

pylint/checkers/variables.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,7 @@ def visit_name(self, node: nodes.Name) -> None:
11101110
It's important that all 'Name' nodes are visited, otherwise the
11111111
'NamesConsumers' won't be correct.
11121112
"""
1113-
stmt = node.statement()
1113+
stmt = node.statement(future=True)
11141114
if stmt.fromlineno is None:
11151115
# name node from an astroid built from live code, skip
11161116
assert not stmt.root().file.endswith(".py")
@@ -1261,7 +1261,7 @@ def _check_consumer(
12611261
return (VariableVisitConsumerAction.CONSUME, found_nodes)
12621262

12631263
defnode = utils.assign_parent(found_nodes[0])
1264-
defstmt = defnode.statement()
1264+
defstmt = defnode.statement(future=True)
12651265
defframe = defstmt.frame()
12661266

12671267
# The class reuses itself in the class scope.
@@ -1515,7 +1515,10 @@ def _allow_global_unused_variables(self):
15151515
@staticmethod
15161516
def _defined_in_function_definition(node, frame):
15171517
in_annotation_or_default_or_decorator = False
1518-
if isinstance(frame, nodes.FunctionDef) and node.statement() is frame:
1518+
if (
1519+
isinstance(frame, nodes.FunctionDef)
1520+
and node.statement(future=True) is frame
1521+
):
15191522
in_annotation_or_default_or_decorator = (
15201523
(
15211524
node in frame.args.annotations
@@ -1563,8 +1566,8 @@ def _in_lambda_or_comprehension_body(
15631566
def _is_variable_violation(
15641567
node: nodes.Name,
15651568
defnode,
1566-
stmt,
1567-
defstmt,
1569+
stmt: nodes.Statement,
1570+
defstmt: nodes.Statement,
15681571
frame, # scope of statement of node
15691572
defframe,
15701573
base_scope_type,
@@ -1753,12 +1756,8 @@ def _is_variable_violation(
17531756

17541757
return maybe_before_assign, annotation_return, use_outer_definition
17551758

1756-
# pylint: disable-next=fixme
1757-
# TODO: The typing of `NodeNG.statement()` in astroid is non-specific
1758-
# After this has been updated the typing of `defstmt` should reflect this
1759-
# See: https://github.com/PyCQA/astroid/pull/1217
17601759
@staticmethod
1761-
def _is_only_type_assignment(node: nodes.Name, defstmt: nodes.NodeNG) -> bool:
1760+
def _is_only_type_assignment(node: nodes.Name, defstmt: nodes.Statement) -> bool:
17621761
"""Check if variable only gets assigned a type and never a value"""
17631762
if not isinstance(defstmt, nodes.AnnAssign) or defstmt.value:
17641763
return False
@@ -1866,7 +1865,7 @@ def _ignore_class_scope(self, node):
18661865
# ...
18671866

18681867
name = node.name
1869-
frame = node.statement().scope()
1868+
frame = node.statement(future=True).scope()
18701869
in_annotation_or_default_or_decorator = self._defined_in_function_definition(
18711870
node, frame
18721871
)
@@ -1890,29 +1889,36 @@ def _loopvar_name(self, node: astroid.Name) -> None:
18901889
# the variable is not defined.
18911890
scope = node.scope()
18921891
if isinstance(scope, nodes.FunctionDef) and any(
1893-
asmt.statement().parent_of(scope) for asmt in astmts
1892+
asmt.scope().parent_of(scope) for asmt in astmts
18941893
):
18951894
return
1896-
1897-
# filter variables according their respective scope test is_statement
1898-
# and parent to avoid #74747. This is not a total fix, which would
1895+
# Filter variables according to their respective scope. Test parent
1896+
# and statement to avoid #74747. This is not a total fix, which would
18991897
# introduce a mechanism similar to special attribute lookup in
19001898
# modules. Also, in order to get correct inference in this case, the
19011899
# scope lookup rules would need to be changed to return the initial
19021900
# assignment (which does not exist in code per se) as well as any later
19031901
# modifications.
1902+
# pylint: disable-next=too-many-boolean-expressions
19041903
if (
19051904
not astmts
1906-
or (astmts[0].is_statement or astmts[0].parent)
1907-
and astmts[0].statement().parent_of(node)
1905+
or (
1906+
astmts[0].parent == astmts[0].root()
1907+
and astmts[0].parent.parent_of(node)
1908+
)
1909+
or (
1910+
astmts[0].is_statement
1911+
or not isinstance(astmts[0].parent, nodes.Module)
1912+
and astmts[0].statement(future=True).parent_of(node)
1913+
)
19081914
):
19091915
_astmts = []
19101916
else:
19111917
_astmts = astmts[:1]
19121918
for i, stmt in enumerate(astmts[1:]):
1913-
if astmts[i].statement().parent_of(stmt) and not in_for_else_branch(
1914-
astmts[i].statement(), stmt
1915-
):
1919+
if astmts[i].statement(future=True).parent_of(
1920+
stmt
1921+
) and not in_for_else_branch(astmts[i].statement(future=True), stmt):
19161922
continue
19171923
_astmts.append(stmt)
19181924
astmts = _astmts
@@ -1922,7 +1928,7 @@ def _loopvar_name(self, node: astroid.Name) -> None:
19221928
assign = astmts[0].assign_type()
19231929
if not (
19241930
isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
1925-
and assign.statement() is not node.statement()
1931+
and assign.statement(future=True) is not node.statement(future=True)
19261932
):
19271933
return
19281934

@@ -2136,7 +2142,8 @@ def _check_late_binding_closure(self, node: nodes.Name) -> None:
21362142
maybe_for
21372143
and maybe_for.parent_of(node_scope)
21382144
and not utils.is_being_called(node_scope)
2139-
and not isinstance(node_scope.statement(), nodes.Return)
2145+
and node_scope.parent
2146+
and not isinstance(node_scope.statement(future=True), nodes.Return)
21402147
):
21412148
self.add_message("cell-var-from-loop", node=node, args=node.name)
21422149

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Test to see we don't crash on this code in pandas.
2+
See: https://github.com/pandas-dev/pandas/blob/master/pandas/core/arrays/sparse/array.py
3+
Code written by Guido van Rossum here: https://github.com/python/typing/issues/684"""
4+
# pylint: disable=no-member, redefined-builtin, invalid-name, missing-class-docstring
5+
6+
from typing import TYPE_CHECKING
7+
8+
if TYPE_CHECKING:
9+
from enum import Enum
10+
11+
class ellipsis(Enum):
12+
Ellipsis = "..."
13+
14+
Ellipsis = ellipsis.Ellipsis
15+
16+
17+
else:
18+
ellipsis = type(Ellipsis)

0 commit comments

Comments
 (0)