diff options
author | Dani Alcala <112832187+clavedeluna@users.noreply.github.com> | 2022-11-13 11:56:38 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-13 14:56:38 +0000 |
commit | 80a9d4a82e1297fbb110c9f4726eb4aa9b65ef61 (patch) | |
tree | 8bc787ad6af1482d78cfc2b3f615704921491052 | |
parent | 131b315fe6c70f171501fa75b45d7062b3428d73 (diff) | |
download | pylint-git-80a9d4a82e1297fbb110c9f4726eb4aa9b65ef61.tar.gz |
Flag `superfluous-parens` if parentheses are used during string concatenation (#7752)
-rw-r--r-- | doc/whatsnew/fragments/4792.false_negative | 3 | ||||
-rw-r--r-- | pylint/checkers/format.py | 2 | ||||
-rw-r--r-- | tests/functional/a/alternative/alternative_union_syntax.py | 2 | ||||
-rw-r--r-- | tests/functional/i/implicit/implicit_str_concat.py | 2 | ||||
-rw-r--r-- | tests/functional/i/invalid/invalid_all_format.py | 2 | ||||
-rw-r--r-- | tests/functional/i/invalid/invalid_all_format.txt | 1 | ||||
-rw-r--r-- | tests/functional/s/slots_checks.py | 2 | ||||
-rw-r--r-- | tests/functional/s/slots_checks.txt | 1 | ||||
-rw-r--r-- | tests/functional/s/superfluous_parens.py | 20 | ||||
-rw-r--r-- | tests/functional/s/superfluous_parens.txt | 6 | ||||
-rw-r--r-- | tests/functional/s/superfluous_parens_walrus_py38.py | 24 | ||||
-rw-r--r-- | tests/functional/s/superfluous_parens_walrus_py38.txt | 5 |
12 files changed, 58 insertions, 12 deletions
diff --git a/doc/whatsnew/fragments/4792.false_negative b/doc/whatsnew/fragments/4792.false_negative new file mode 100644 index 000000000..6d05ef565 --- /dev/null +++ b/doc/whatsnew/fragments/4792.false_negative @@ -0,0 +1,3 @@ +Flag ``superfluous-parens`` if parentheses are used during string concatenation. + +Closes #4792 diff --git a/pylint/checkers/format.py b/pylint/checkers/format.py index 247385f2a..cde34b5d7 100644 --- a/pylint/checkers/format.py +++ b/pylint/checkers/format.py @@ -55,6 +55,8 @@ _KEYWORD_TOKENS = { "while", "yield", "with", + "=", + ":=", } _JUNK_TOKENS = {tokenize.COMMENT, tokenize.NL} diff --git a/tests/functional/a/alternative/alternative_union_syntax.py b/tests/functional/a/alternative/alternative_union_syntax.py index 4492323a2..d25d9e8f4 100644 --- a/tests/functional/a/alternative/alternative_union_syntax.py +++ b/tests/functional/a/alternative/alternative_union_syntax.py @@ -1,6 +1,6 @@ """Test PEP 604 - Alternative Union syntax""" # pylint: disable=missing-function-docstring,unused-argument,invalid-name,missing-class-docstring -# pylint: disable=inherit-non-class,too-few-public-methods,unnecessary-direct-lambda-call +# pylint: disable=inherit-non-class,too-few-public-methods,unnecessary-direct-lambda-call,superfluous-parens import dataclasses import typing from dataclasses import dataclass diff --git a/tests/functional/i/implicit/implicit_str_concat.py b/tests/functional/i/implicit/implicit_str_concat.py index 920b29258..7e28b4cc2 100644 --- a/tests/functional/i/implicit/implicit_str_concat.py +++ b/tests/functional/i/implicit/implicit_str_concat.py @@ -1,4 +1,4 @@ -# pylint: disable=invalid-name, missing-docstring, redundant-u-string-prefix, line-too-long +# pylint: disable=invalid-name, missing-docstring, redundant-u-string-prefix, line-too-long, superfluous-parens # Basic test with a list TEST_LIST1 = ['a' 'b'] # [implicit-str-concat] diff --git a/tests/functional/i/invalid/invalid_all_format.py b/tests/functional/i/invalid/invalid_all_format.py index 1d1c0b18f..10537c6fb 100644 --- a/tests/functional/i/invalid/invalid_all_format.py +++ b/tests/functional/i/invalid/invalid_all_format.py @@ -2,6 +2,6 @@ Tuples with one element MUST contain a comma! Otherwise it's a string. """ -__all__ = ("CONST") # [invalid-all-format] +__all__ = ("CONST") # [invalid-all-format, superfluous-parens] CONST = 42 diff --git a/tests/functional/i/invalid/invalid_all_format.txt b/tests/functional/i/invalid/invalid_all_format.txt index 2ba8dc17f..2f6ac363b 100644 --- a/tests/functional/i/invalid/invalid_all_format.txt +++ b/tests/functional/i/invalid/invalid_all_format.txt @@ -1 +1,2 @@ invalid-all-format:5:11:None:None::Invalid format for __all__, must be tuple or list:UNDEFINED +superfluous-parens:5:0:None:None::Unnecessary parens after '=' keyword:UNDEFINED diff --git a/tests/functional/s/slots_checks.py b/tests/functional/s/slots_checks.py index e8d55d967..2c22e968e 100644 --- a/tests/functional/s/slots_checks.py +++ b/tests/functional/s/slots_checks.py @@ -64,7 +64,7 @@ class SixthBad: # [single-string-used-for-slots] __slots__ = "a" class SeventhBad: # [single-string-used-for-slots] - __slots__ = ('foo') + __slots__ = ('foo') # [superfluous-parens] class EighthBad: # [single-string-used-for-slots] __slots__ = deque.__name__ diff --git a/tests/functional/s/slots_checks.txt b/tests/functional/s/slots_checks.txt index 3abccff8f..d63ad2517 100644 --- a/tests/functional/s/slots_checks.txt +++ b/tests/functional/s/slots_checks.txt @@ -5,6 +5,7 @@ invalid-slots:57:0:57:15:FourthBad:Invalid __slots__ object:UNDEFINED invalid-slots-object:61:27:61:29:FifthBad:"Invalid object ""''"" in __slots__, must contain only non empty strings":INFERENCE single-string-used-for-slots:63:0:63:14:SixthBad:Class __slots__ should be a non-string iterable:UNDEFINED single-string-used-for-slots:66:0:66:16:SeventhBad:Class __slots__ should be a non-string iterable:UNDEFINED +superfluous-parens:67:0:None:None::Unnecessary parens after '=' keyword:UNDEFINED single-string-used-for-slots:69:0:69:15:EighthBad:Class __slots__ should be a non-string iterable:UNDEFINED invalid-slots-object:73:17:73:20:NinthBad:Invalid object 'str' in __slots__, must contain only non empty strings:INFERENCE invalid-slots-object:76:17:76:26:TenthBad:Invalid object '1 + 2 + 3' in __slots__, must contain only non empty strings:INFERENCE diff --git a/tests/functional/s/superfluous_parens.py b/tests/functional/s/superfluous_parens.py index db9349cce..35acfd5d3 100644 --- a/tests/functional/s/superfluous_parens.py +++ b/tests/functional/s/superfluous_parens.py @@ -47,13 +47,6 @@ def function_B(var): def function_C(first, second): return (first or second) in (0, 1) -# TODO: Test string combinations, see https://github.com/PyCQA/pylint/issues/4792 -# The lines with "+" should raise the superfluous-parens message -J = "TestString" -K = ("Test " + "String") -L = ("Test " + "String") in I -assert "" + ("Version " + "String") in I - # Test numpy def function_numpy_A(var_1: int, var_2: int) -> np.ndarray: result = (((var_1 & var_2)) > 0) @@ -72,6 +65,19 @@ class ClassA: if (A == 2) is not (B == 2): pass +K = ("Test " + "String") # [superfluous-parens] M = A is not (A <= H) M = True is not (M == K) M = True is not (True is not False) # pylint: disable=comparison-of-constants + +Z = "TestString" +X = ("Test " + "String") # [superfluous-parens] +Y = ("Test " + "String") in Z # [superfluous-parens] +assert ("Test " + "String") in "hello" # [superfluous-parens] +assert ("Version " + "String") in ("Version " + "String") # [superfluous-parens] + +hi = ("CONST") # [superfluous-parens] +hi = ("CONST",) + +#TODO: maybe get this line to report [superfluous-parens] without causing other false positives. +assert "" + ("Version " + "String") in Z diff --git a/tests/functional/s/superfluous_parens.txt b/tests/functional/s/superfluous_parens.txt index f830922bc..08b2dd390 100644 --- a/tests/functional/s/superfluous_parens.txt +++ b/tests/functional/s/superfluous_parens.txt @@ -4,3 +4,9 @@ superfluous-parens:12:0:None:None::Unnecessary parens after 'for' keyword:UNDEFI superfluous-parens:14:0:None:None::Unnecessary parens after 'if' keyword:UNDEFINED superfluous-parens:19:0:None:None::Unnecessary parens after 'del' keyword:UNDEFINED superfluous-parens:31:0:None:None::Unnecessary parens after 'assert' keyword:UNDEFINED +superfluous-parens:68:0:None:None::Unnecessary parens after '=' keyword:UNDEFINED +superfluous-parens:74:0:None:None::Unnecessary parens after '=' keyword:UNDEFINED +superfluous-parens:75:0:None:None::Unnecessary parens after '=' keyword:UNDEFINED +superfluous-parens:76:0:None:None::Unnecessary parens after 'assert' keyword:UNDEFINED +superfluous-parens:77:0:None:None::Unnecessary parens after 'assert' keyword:UNDEFINED +superfluous-parens:79:0:None:None::Unnecessary parens after '=' keyword:UNDEFINED diff --git a/tests/functional/s/superfluous_parens_walrus_py38.py b/tests/functional/s/superfluous_parens_walrus_py38.py index cf155954e..43b7c2aee 100644 --- a/tests/functional/s/superfluous_parens_walrus_py38.py +++ b/tests/functional/s/superfluous_parens_walrus_py38.py @@ -1,5 +1,5 @@ """Test the superfluous-parens warning with python 3.8 functionality (walrus operator)""" -# pylint: disable=missing-function-docstring, invalid-name, missing-class-docstring, import-error +# pylint: disable=missing-function-docstring, invalid-name, missing-class-docstring, import-error, pointless-statement import numpy # Test parens in if statements @@ -49,3 +49,25 @@ class TestYieldClass: @classmethod def function_C(cls): yield (1 + 1) # [superfluous-parens] + + +if (x := "Test " + "String"): + print(x) + +if (x := ("Test " + "String")): # [superfluous-parens] + print(x) + +if not (foo := "Test " + "String" in "hello"): + print(foo) + +if not (foo := ("Test " + "String") in "hello"): # [superfluous-parens] + print(foo) + +assert (ret := "Test " + "String") +assert (ret := ("Test " + "String")) # [superfluous-parens] + +(walrus := False) +(walrus := (False)) # [superfluous-parens] + +(hi := ("CONST")) # [superfluous-parens] +(hi := ("CONST",)) diff --git a/tests/functional/s/superfluous_parens_walrus_py38.txt b/tests/functional/s/superfluous_parens_walrus_py38.txt index 58097f520..da8f1b999 100644 --- a/tests/functional/s/superfluous_parens_walrus_py38.txt +++ b/tests/functional/s/superfluous_parens_walrus_py38.txt @@ -3,3 +3,8 @@ superfluous-parens:19:0:None:None::Unnecessary parens after 'if' keyword:UNDEFIN superfluous-parens:22:0:None:None::Unnecessary parens after 'not' keyword:UNDEFINED superfluous-parens:25:0:None:None::Unnecessary parens after 'not' keyword:UNDEFINED superfluous-parens:51:0:None:None::Unnecessary parens after 'yield' keyword:UNDEFINED +superfluous-parens:57:0:None:None::"Unnecessary parens after ':=' keyword":UNDEFINED +superfluous-parens:63:0:None:None::"Unnecessary parens after ':=' keyword":UNDEFINED +superfluous-parens:67:0:None:None::"Unnecessary parens after ':=' keyword":UNDEFINED +superfluous-parens:70:0:None:None::"Unnecessary parens after ':=' keyword":UNDEFINED +superfluous-parens:72:0:None:None::"Unnecessary parens after ':=' keyword":UNDEFINED |