summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2021-11-24 10:12:01 +0100
committerGitHub <noreply@github.com>2021-11-24 10:12:01 +0100
commite8fa46928d91893723a9a038fde2d274d535fd1f (patch)
tree9a8803b19061fe5d244f6fd34348bf9f838a0ed4
parente3a1e359704a48d8bbe8ce00e54f4ddfebcf620e (diff)
downloadpylint-git-e8fa46928d91893723a9a038fde2d274d535fd1f.tar.gz
Fix a crash on psycopg2 for elif used (#5369)
* Fix a crash in the ``check_elif`` extensions where an undetected if in a comprehension with an if statement within a f-string resulted in an out of range error. The checker no longer relies on counting if statements anymore and uses known if statements locations instead. It should not crash on badly parsed if statements anymore. specify the confidence of the message * Remove disable for else-if-used in pylint/checkers/classes.py Co-authored-by: Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>
-rw-r--r--ChangeLog5
-rw-r--r--pylint/checkers/classes.py26
-rw-r--r--pylint/extensions/check_elif.py38
-rw-r--r--tests/functional/ext/check_elif/check_elif.py23
-rw-r--r--tests/functional/ext/check_elif/check_elif.txt6
5 files changed, 57 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index 6c81c2e6a..30b15d0ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,11 @@ Release date: TBA
* Fix ``install graphiz`` message which isn't needed for puml output format.
+* Fix a crash in the ``check_elif`` extensions where an undetected if in a comprehension
+ with an if statement within a f-string resulted in an out of range error. The checker no
+ longer relies on counting if statements anymore and uses known if statements locations instead.
+ It should not crash on badly parsed if statements anymore.
+
* Fix ``simplify-boolean-expression`` when condition can be inferred as False.
Closes #5200
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 319a37f73..37651cdfd 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -1848,20 +1848,18 @@ a metaclass class method.",
"bad-mcs-method-argument",
node.name,
)
- # regular class
- else: # pylint: disable=else-if-used
- # class method
- if node.type == "classmethod" or node.name == "__class_getitem__":
- self._check_first_arg_config(
- first,
- self.config.valid_classmethod_first_arg,
- node,
- "bad-classmethod-argument",
- node.name,
- )
- # regular method without self as argument
- elif first != "self":
- self.add_message("no-self-argument", node=node)
+ # regular class with class method
+ elif node.type == "classmethod" or node.name == "__class_getitem__":
+ self._check_first_arg_config(
+ first,
+ self.config.valid_classmethod_first_arg,
+ node,
+ "bad-classmethod-argument",
+ node.name,
+ )
+ # regular class with regular method without self as argument
+ elif first != "self":
+ self.add_message("no-self-argument", node=node)
def _check_first_arg_config(self, first, config, node, message, method_name):
if first not in config:
diff --git a/pylint/extensions/check_elif.py b/pylint/extensions/check_elif.py
index 8dcfb74b3..aa4457748 100644
--- a/pylint/extensions/check_elif.py
+++ b/pylint/extensions/check_elif.py
@@ -15,7 +15,7 @@ from astroid import nodes
from pylint.checkers import BaseTokenChecker
from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker, ITokenChecker
+from pylint.interfaces import HIGH, IAstroidChecker, ITokenChecker
class ElseifUsedChecker(BaseTokenChecker):
@@ -38,37 +38,27 @@ class ElseifUsedChecker(BaseTokenChecker):
self._init()
def _init(self):
- self._elifs = []
- self._if_counter = 0
+ self._elifs = {}
def process_tokens(self, tokens):
- # Process tokens and look for 'if' or 'elif'
- for _, token, _, _, _ in tokens:
- if token == "elif":
- self._elifs.append(True)
- elif token == "if":
- self._elifs.append(False)
+ """Process tokens and look for 'if' or 'elif'"""
+ self._elifs = {
+ begin: token for _, token, begin, _, _ in tokens if token in {"elif", "if"}
+ }
def leave_module(self, _: nodes.Module) -> None:
self._init()
- def visit_ifexp(self, node: nodes.IfExp) -> None:
- if isinstance(node.parent, nodes.FormattedValue):
- return
- self._if_counter += 1
-
- def visit_comprehension(self, node: nodes.Comprehension) -> None:
- self._if_counter += len(node.ifs)
-
@check_messages("else-if-used")
def visit_if(self, node: nodes.If) -> None:
- if isinstance(node.parent, nodes.If):
- orelse = node.parent.orelse
- # current if node must directly follow an "else"
- if orelse and orelse == [node]:
- if not self._elifs[self._if_counter]:
- self.add_message("else-if-used", node=node)
- self._if_counter += 1
+ """Current if node must directly follow an 'else'"""
+ if (
+ isinstance(node.parent, nodes.If)
+ and node.parent.orelse == [node]
+ and (node.lineno, node.col_offset) in self._elifs
+ and self._elifs[(node.lineno, node.col_offset)] == "if"
+ ):
+ self.add_message("else-if-used", node=node, confidence=HIGH)
def register(linter):
diff --git a/tests/functional/ext/check_elif/check_elif.py b/tests/functional/ext/check_elif/check_elif.py
index b9722f349..f03c76839 100644
--- a/tests/functional/ext/check_elif/check_elif.py
+++ b/tests/functional/ext/check_elif/check_elif.py
@@ -1,4 +1,7 @@
+# pylint: disable=no-else-raise,unsupported-membership-test,using-constant-test
+
"""Checks use of "else if" triggers a refactor message"""
+from typing import Union, Sequence, Any, Mapping
def my_function():
@@ -7,7 +10,7 @@ def my_function():
if myint > 5:
pass
else:
- if myint <= 5: # [else-if-used]
+ if myint <= 5: # [else-if-used]
pass
else:
myint = 3
@@ -25,3 +28,21 @@ def my_function():
if myint:
pass
myint = 4
+
+
+def _if_in_fstring_comprehension_with_elif(
+ params: Union[Sequence[Any], Mapping[str, Any]]
+):
+ order = {}
+ if "z" not in "false":
+ raise TypeError(
+ f" {', '.join(sorted(i for i in order or () if i not in params))}"
+ )
+ elif "z" not in "true":
+ pass
+ else:
+ if "t" not in "false": # [else-if-used]
+ raise TypeError("d")
+ else:
+ if "y" in "life": # [else-if-used]
+ print("e")
diff --git a/tests/functional/ext/check_elif/check_elif.txt b/tests/functional/ext/check_elif/check_elif.txt
index 43d1e3b1e..88853eb95 100644
--- a/tests/functional/ext/check_elif/check_elif.txt
+++ b/tests/functional/ext/check_elif/check_elif.txt
@@ -1,2 +1,4 @@
-else-if-used:10:8:my_function:"Consider using ""elif"" instead of ""else if""":HIGH
-else-if-used:22:20:my_function:"Consider using ""elif"" instead of ""else if""":HIGH
+else-if-used:13:8:my_function:"Consider using ""elif"" instead of ""else if""":HIGH
+else-if-used:25:20:my_function:"Consider using ""elif"" instead of ""else if""":HIGH
+else-if-used:44:8:_if_in_fstring_comprehension_with_elif:"Consider using ""elif"" instead of ""else if""":HIGH
+else-if-used:47:12:_if_in_fstring_comprehension_with_elif:"Consider using ""elif"" instead of ""else if""":HIGH