summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2021-12-16 16:34:14 +0100
committerGitHub <noreply@github.com>2021-12-16 16:34:14 +0100
commitc285fae493a7a272639a969d6ea914db8c9e1d18 (patch)
tree1843118a59f818b7717447f75142c14665801e48
parent9909daec8e3089e350decf8c1a837a2f6fe95cb9 (diff)
downloadpylint-git-c285fae493a7a272639a969d6ea914db8c9e1d18.tar.gz
Add ``future=True`` to all ``NodeNG.statement()`` calls (#5310)
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r--pylint/checkers/base.py2
-rw-r--r--pylint/checkers/classes.py8
-rw-r--r--pylint/checkers/format.py4
-rw-r--r--pylint/checkers/typecheck.py11
-rw-r--r--pylint/checkers/utils.py2
-rw-r--r--pylint/checkers/variables.py51
-rw-r--r--tests/functional/r/regression_02/regression_node_statement.py18
7 files changed, 64 insertions, 32 deletions
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index 0206b1202..9d61cf10f 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -606,7 +606,7 @@ class BasicErrorChecker(_BasicChecker):
# PEP 448 unpacking.
return
- stmt = node.statement()
+ stmt = node.statement(future=True)
if not isinstance(stmt, nodes.Assign):
return
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 478197b0f..da9bf074f 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -1052,7 +1052,9 @@ a metaclass class method.",
nodes_lst = [
n
for n in nodes_lst
- if not isinstance(n.statement(), (nodes.Delete, nodes.AugAssign))
+ if not isinstance(
+ n.statement(future=True), (nodes.Delete, nodes.AugAssign)
+ )
and n.root() is current_module
]
if not nodes_lst:
@@ -1651,7 +1653,7 @@ a metaclass class method.",
# class A:
# b = property(lambda: self._b)
- stmt = node.parent.statement()
+ stmt = node.parent.statement(future=True)
if (
isinstance(stmt, nodes.Assign)
and len(stmt.targets) == 1
@@ -1796,7 +1798,7 @@ a metaclass class method.",
_node.frame() is frame
and _node.fromlineno < lno
and not astroid.are_exclusive(
- _node.statement(), defstmt, excs
+ _node.statement(future=True), defstmt, excs
)
):
self.add_message(
diff --git a/pylint/checkers/format.py b/pylint/checkers/format.py
index cdbacd4cf..0c0cb8752 100644
--- a/pylint/checkers/format.py
+++ b/pylint/checkers/format.py
@@ -602,8 +602,10 @@ class FormatChecker(BaseTokenChecker):
isinstance(node.parent, nodes.TryFinally) and node in node.parent.finalbody
):
prev_line = node.parent.body[0].tolineno + 1
+ elif isinstance(node.parent, nodes.Module):
+ prev_line = 0
else:
- prev_line = node.parent.statement().fromlineno
+ prev_line = node.parent.statement(future=True).fromlineno
line = node.fromlineno
assert line, node
if prev_line == line and self._visited_lines.get(line) != 2:
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py
index c5203adf7..df01cc2fe 100644
--- a/pylint/checkers/typecheck.py
+++ b/pylint/checkers/typecheck.py
@@ -72,6 +72,7 @@ from functools import singledispatch
from typing import Any, Callable, Iterator, List, Optional, Pattern, Tuple
import astroid
+import astroid.exceptions
from astroid import bases, nodes
from pylint.checkers import BaseChecker, utils
@@ -615,7 +616,7 @@ def _has_parent_of_type(node, node_type, statement):
def _no_context_variadic_keywords(node, scope):
- statement = node.statement()
+ statement = node.statement(future=True)
variadics = ()
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):
is_in_lambda_scope = not isinstance(scope, nodes.FunctionDef) and isinstance(
scope, nodes.Lambda
)
- statement = node.statement()
+ statement = node.statement(future=True)
for name in statement.nodes_of_class(nodes.Name):
if name.name != variadic_name:
continue
@@ -667,7 +668,7 @@ def _no_context_variadic(node, variadic_name, variadic_type, variadics):
# so we need to go the lambda instead
inferred_statement = inferred.parent.parent
else:
- inferred_statement = inferred.statement()
+ inferred_statement = inferred.statement(future=True)
if not length and isinstance(inferred_statement, nodes.Lambda):
is_in_starred_context = _has_parent_of_type(node, variadic_type, statement)
@@ -1029,10 +1030,12 @@ accessed. Python regular expressions are accepted.",
if not [
n
for n in owner.getattr(node.attrname)
- if not isinstance(n.statement(), nodes.AugAssign)
+ if not isinstance(n.statement(future=True), nodes.AugAssign)
]:
missingattr.add((owner, name))
continue
+ except astroid.exceptions.StatementMissing:
+ continue
except AttributeError:
continue
except astroid.DuplicateBasesError:
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index d71669729..1f85399a7 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -401,7 +401,7 @@ def is_defined_before(var_node: nodes.Name) -> bool:
if is_defined_in_scope(var_node, varname, parent):
return True
# possibly multiple statements on the same line using semi colon separator
- stmt = var_node.statement()
+ stmt = var_node.statement(future=True)
_node = stmt.previous_sibling()
lineno = stmt.fromlineno
while _node and _node.fromlineno == lineno:
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index 86b7eb669..a1cee36a0 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -1110,7 +1110,7 @@ class VariablesChecker(BaseChecker):
It's important that all 'Name' nodes are visited, otherwise the
'NamesConsumers' won't be correct.
"""
- stmt = node.statement()
+ stmt = node.statement(future=True)
if stmt.fromlineno is None:
# name node from an astroid built from live code, skip
assert not stmt.root().file.endswith(".py")
@@ -1261,7 +1261,7 @@ class VariablesChecker(BaseChecker):
return (VariableVisitConsumerAction.CONSUME, found_nodes)
defnode = utils.assign_parent(found_nodes[0])
- defstmt = defnode.statement()
+ defstmt = defnode.statement(future=True)
defframe = defstmt.frame()
# The class reuses itself in the class scope.
@@ -1515,7 +1515,10 @@ class VariablesChecker(BaseChecker):
@staticmethod
def _defined_in_function_definition(node, frame):
in_annotation_or_default_or_decorator = False
- if isinstance(frame, nodes.FunctionDef) and node.statement() is frame:
+ if (
+ isinstance(frame, nodes.FunctionDef)
+ and node.statement(future=True) is frame
+ ):
in_annotation_or_default_or_decorator = (
(
node in frame.args.annotations
@@ -1563,8 +1566,8 @@ class VariablesChecker(BaseChecker):
def _is_variable_violation(
node: nodes.Name,
defnode,
- stmt,
- defstmt,
+ stmt: nodes.Statement,
+ defstmt: nodes.Statement,
frame, # scope of statement of node
defframe,
base_scope_type,
@@ -1753,12 +1756,8 @@ class VariablesChecker(BaseChecker):
return maybe_before_assign, annotation_return, use_outer_definition
- # pylint: disable-next=fixme
- # TODO: The typing of `NodeNG.statement()` in astroid is non-specific
- # After this has been updated the typing of `defstmt` should reflect this
- # See: https://github.com/PyCQA/astroid/pull/1217
@staticmethod
- def _is_only_type_assignment(node: nodes.Name, defstmt: nodes.NodeNG) -> bool:
+ def _is_only_type_assignment(node: nodes.Name, defstmt: nodes.Statement) -> bool:
"""Check if variable only gets assigned a type and never a value"""
if not isinstance(defstmt, nodes.AnnAssign) or defstmt.value:
return False
@@ -1866,7 +1865,7 @@ class VariablesChecker(BaseChecker):
# ...
name = node.name
- frame = node.statement().scope()
+ frame = node.statement(future=True).scope()
in_annotation_or_default_or_decorator = self._defined_in_function_definition(
node, frame
)
@@ -1890,29 +1889,36 @@ class VariablesChecker(BaseChecker):
# the variable is not defined.
scope = node.scope()
if isinstance(scope, nodes.FunctionDef) and any(
- asmt.statement().parent_of(scope) for asmt in astmts
+ asmt.scope().parent_of(scope) for asmt in astmts
):
return
-
- # filter variables according their respective scope test is_statement
- # and parent to avoid #74747. This is not a total fix, which would
+ # Filter variables according to their respective scope. Test parent
+ # and statement to avoid #74747. This is not a total fix, which would
# introduce a mechanism similar to special attribute lookup in
# modules. Also, in order to get correct inference in this case, the
# scope lookup rules would need to be changed to return the initial
# assignment (which does not exist in code per se) as well as any later
# modifications.
+ # pylint: disable-next=too-many-boolean-expressions
if (
not astmts
- or (astmts[0].is_statement or astmts[0].parent)
- and astmts[0].statement().parent_of(node)
+ or (
+ astmts[0].parent == astmts[0].root()
+ and astmts[0].parent.parent_of(node)
+ )
+ or (
+ astmts[0].is_statement
+ or not isinstance(astmts[0].parent, nodes.Module)
+ and astmts[0].statement(future=True).parent_of(node)
+ )
):
_astmts = []
else:
_astmts = astmts[:1]
for i, stmt in enumerate(astmts[1:]):
- if astmts[i].statement().parent_of(stmt) and not in_for_else_branch(
- astmts[i].statement(), stmt
- ):
+ if astmts[i].statement(future=True).parent_of(
+ stmt
+ ) and not in_for_else_branch(astmts[i].statement(future=True), stmt):
continue
_astmts.append(stmt)
astmts = _astmts
@@ -1922,7 +1928,7 @@ class VariablesChecker(BaseChecker):
assign = astmts[0].assign_type()
if not (
isinstance(assign, (nodes.For, nodes.Comprehension, nodes.GeneratorExp))
- and assign.statement() is not node.statement()
+ and assign.statement(future=True) is not node.statement(future=True)
):
return
@@ -2136,7 +2142,8 @@ class VariablesChecker(BaseChecker):
maybe_for
and maybe_for.parent_of(node_scope)
and not utils.is_being_called(node_scope)
- and not isinstance(node_scope.statement(), nodes.Return)
+ and node_scope.parent
+ and not isinstance(node_scope.statement(future=True), nodes.Return)
):
self.add_message("cell-var-from-loop", node=node, args=node.name)
diff --git a/tests/functional/r/regression_02/regression_node_statement.py b/tests/functional/r/regression_02/regression_node_statement.py
new file mode 100644
index 000000000..bd982480b
--- /dev/null
+++ b/tests/functional/r/regression_02/regression_node_statement.py
@@ -0,0 +1,18 @@
+"""Test to see we don't crash on this code in pandas.
+See: https://github.com/pandas-dev/pandas/blob/master/pandas/core/arrays/sparse/array.py
+Code written by Guido van Rossum here: https://github.com/python/typing/issues/684"""
+# pylint: disable=no-member, redefined-builtin, invalid-name, missing-class-docstring
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from enum import Enum
+
+ class ellipsis(Enum):
+ Ellipsis = "..."
+
+ Ellipsis = ellipsis.Ellipsis
+
+
+else:
+ ellipsis = type(Ellipsis)