Skip to content

Commit

Permalink
Fix false positive superfluous-parens for tuples
Browse files Browse the repository at this point in the history
Tuples can be created with inner tuples. This creates double parenthesis
which we flagged incorrectly.
This closes #4907
  • Loading branch information
DanielNoord authored and Pierre-Sassoulas committed Sep 1, 2021
1 parent d57931b commit 3f122e0
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 27 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -59,6 +59,10 @@ Release date: TBA

Closes #4945

* Fix false positive ``superfluous-parens`` for tuples created with inner tuples

Closes #4907


What's New in Pylint 2.10.3?
============================
Expand Down
4 changes: 4 additions & 0 deletions doc/whatsnew/2.11.rst
Expand Up @@ -65,3 +65,7 @@ Other Changes
and ``pathlib.Path().write_text()``

Closes #4945

* Fix false positive ``superfluous-parens`` for tuples created with inner tuples

Closes #4907
8 changes: 4 additions & 4 deletions pylint/checkers/format.py
Expand Up @@ -401,11 +401,11 @@ def _check_keyword_parentheses(
depth -= 1
if depth:
if contains_double_parens and tokens[i + 1].string == ")":
self.add_message(
"superfluous-parens", line=line_num, args=keyword_token
)
# For walrus operators in `if (not)` conditions and comprehensions
if keyword_token in {"in", "if", "not"}:
continue
return
contains_double_parens = 0
contains_double_parens -= 1
continue
# ')' can't happen after if (foo), since it would be a syntax error.
if tokens[i + 1].string in (":", ")", "]", "}", "in") or tokens[
Expand Down
5 changes: 0 additions & 5 deletions tests/checkers/unittest_format.py
Expand Up @@ -165,11 +165,6 @@ def testCheckKeywordParensHandlesUnnecessaryParens(self):
(Message("superfluous-parens", line=1, args="if"), "if (foo):", 0),
(Message("superfluous-parens", line=1, args="if"), "if ((foo, bar)):", 0),
(Message("superfluous-parens", line=1, args="if"), "if (foo(bar)):", 0),
(
Message("superfluous-parens", line=1, args="return"),
"return ((x for x in x))",
0,
),
(Message("superfluous-parens", line=1, args="not"), "not (foo)", 0),
(Message("superfluous-parens", line=1, args="not"), "if not (foo):", 1),
(Message("superfluous-parens", line=1, args="if"), "if (not (foo)):", 0),
Expand Down
33 changes: 25 additions & 8 deletions tests/functional/s/super/superfluous_parens.py
@@ -1,6 +1,7 @@
"""Test the superfluous-parens warning."""
from __future__ import print_function
# pylint: disable=unneeded-not, unnecessary-comprehension, missing-function-docstring, invalid-name, fixme
# pylint: disable=import-error, missing-class-docstring, too-few-public-methods
import numpy as np
A = 3
if (A == 5): # [superfluous-parens]
pass
Expand All @@ -18,10 +19,10 @@
del(DICT['b']) # [superfluous-parens]
del DICT['a']

B = [x for x in ((3, 4))] # [superfluous-parens]
B = [x for x in ((3, 4))]
C = [x for x in ((3, 4) if 1 > 0 else (5, 6))]
D = [x for x in ((3, 4) if 1 > 0 else ((5, 6)))] # [superfluous-parens]
E = [x for x in ((3, 4) if 1 > 0 else ((((5, 6)))))] # [superfluous-parens]
D = [x for x in ((3, 4) if 1 > 0 else ((5, 6)))]
E = [x for x in ((3, 4) if 1 > 0 else ((((5, 6)))))]

# Test assertions
F = "Version 1.0"
Expand All @@ -34,14 +35,30 @@
NUMS_LIST = ['1', '2', '3']
NUMS_SET = {'1', '2', '3'}
NUMS_DICT = {'1': 1, '2': 2, '3': 3}
I = tuple(x for x in ((a, str(a)) for a in ()))

# Test functions
def function_A():
return (x for x in ((3, 4))) # [superfluous-parens]
return (x for x in ((3, 4)))

# TODO: Test string combinations, see https://github.com/PyCQA/pylint/issues/4792
# Lines 45, 46 & 47 should raise the superfluous-parens message
I = "TestString"
J = ("Test " + "String")
K = ("Test " + "String") in I
J = "TestString"
K = ("Test " + "String")
L = ("Test " + "String") in I
assert "" + ("Version " + "String") in I

# Test numpy
def function_B(var_1: int, var_2: int) -> np.ndarray:
result = (((var_1 & var_2)) > 0)
return result.astype(np.float32)

def function_C(var_1: int, var_2: int) -> np.ndarray:
return (((var_1 & var_2)) > 0).astype(np.float32)

# Test Class
class ClassA:
keys = []

def __iter__(self):
return ((k, getattr(self, k)) for k in self.keys)
16 changes: 6 additions & 10 deletions tests/functional/s/super/superfluous_parens.txt
@@ -1,10 +1,6 @@
superfluous-parens:5:0::Unnecessary parens after 'if' keyword:HIGH
superfluous-parens:7:0::Unnecessary parens after 'not' keyword:HIGH
superfluous-parens:11:0::Unnecessary parens after 'for' keyword:HIGH
superfluous-parens:13:0::Unnecessary parens after 'if' keyword:HIGH
superfluous-parens:18:0::Unnecessary parens after 'del' keyword:HIGH
superfluous-parens:21:0::Unnecessary parens after 'in' keyword:HIGH
superfluous-parens:23:0::Unnecessary parens after 'else' keyword:HIGH
superfluous-parens:24:0::Unnecessary parens after 'else' keyword:HIGH
superfluous-parens:30:0::Unnecessary parens after 'assert' keyword:HIGH
superfluous-parens:40:0::Unnecessary parens after 'in' keyword:HIGH
superfluous-parens:6:0::Unnecessary parens after 'if' keyword:HIGH
superfluous-parens:8:0::Unnecessary parens after 'not' keyword:HIGH
superfluous-parens:12:0::Unnecessary parens after 'for' keyword:HIGH
superfluous-parens:14:0::Unnecessary parens after 'if' keyword:HIGH
superfluous-parens:19:0::Unnecessary parens after 'del' keyword:HIGH
superfluous-parens:31:0::Unnecessary parens after 'assert' keyword:HIGH

0 comments on commit 3f122e0

Please sign in to comment.