Skip to content

Commit 5b017d1

Browse files
committed
Fix false positive superfluous parens for walrus operator
Close #3383
1 parent ba0c794 commit 5b017d1

File tree

3 files changed

+41
-4
lines changed

3 files changed

+41
-4
lines changed

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ Release date: TBA
3030

3131
* Fix `pre-commit` config that could lead to undetected duplicate lines of code
3232

33+
* Fix superfluous-parens false-positive for the walrus operator
34+
35+
Close #3383
36+
37+
3338
What's New in Pylint 2.5.3?
3439
===========================
3540

pylint/checkers/format.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@
5252

5353
import tokenize
5454
from functools import reduce # pylint: disable=redefined-builtin
55-
from typing import List
5655
from tokenize import TokenInfo
56+
from typing import List
5757

5858
from astroid import nodes
5959

@@ -371,11 +371,18 @@ def _check_keyword_parentheses(self, tokens: List[TokenInfo], start: int) -> Non
371371
if tokens[start + 1].string != "(":
372372
return
373373
found_and_or = False
374+
contains_walrus_operator = False
375+
walrus_operator_depth = 0
374376
depth = 0
375377
keyword_token = str(tokens[start].string)
376378
line_num = tokens[start].start[0]
377379
for i in range(start, len(tokens) - 1):
378380
token = tokens[i]
381+
382+
if token.string == ":=":
383+
contains_walrus_operator = True
384+
walrus_operator_depth = depth
385+
379386
# If we hit a newline, then assume any parens were for continuation.
380387
if token.type == tokenize.NL:
381388
return
@@ -386,10 +393,14 @@ def _check_keyword_parentheses(self, tokens: List[TokenInfo], start: int) -> Non
386393
if depth:
387394
continue
388395
# ')' can't happen after if (foo), since it would be a syntax error.
389-
if (tokens[i + 1].string in (":", ")", "]", "}", "in") or
390-
tokens[i + 1].type in
391-
(tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT)):
396+
if tokens[i + 1].string in (":", ")", "]", "}", "in") or tokens[
397+
i + 1
398+
].type in (tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT):
392399
# The empty tuple () is always accepted.
400+
if contains_walrus_operator and walrus_operator_depth - 1 == depth:
401+
# Reset variable for possible following expressions
402+
contains_walrus_operator = False
403+
continue
393404
if i == start + 2:
394405
return
395406
if keyword_token == "not":

tests/checkers/unittest_format.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,27 @@ def testCheckKeywordParensHandlesUnnecessaryParens(self):
184184
with self.assertAddsMessages(msg):
185185
self.checker._check_keyword_parentheses(_tokenize_str(code), offset)
186186

187+
def testNoSuperfluousParensWalrusOperatorIf(self):
188+
"""Parenthesis change the meaning of assignment in the walrus operator
189+
and so are not superfluous:"""
190+
code = "if (odd := is_odd(i))"
191+
offset = 0
192+
with self.assertNoMessages():
193+
self.checker._check_keyword_parentheses(_tokenize_str(code), offset)
194+
195+
def testPositiveSuperfluousParensWalrusOperatorIf(self):
196+
"""Test positive superfluous parens with the walrus operator"""
197+
code = "if ((odd := is_odd(i))):"
198+
msg = Message("superfluous-parens", line=1, args="if")
199+
with self.assertAddsMessages(msg):
200+
self.checker._check_keyword_parentheses(_tokenize_str(code), 0)
201+
202+
def testNoSuperfluousParensWalrusOperatorNot(self):
203+
"""Test superfluous-parens with the not operator"""
204+
code = "not (foo := 5)"
205+
with self.assertNoMessages():
206+
self.checker._check_keyword_parentheses(_tokenize_str(code), 0)
207+
187208
def testCheckIfArgsAreNotUnicode(self):
188209
cases = [("if (foo):", 0), ("assert (1 == 1)", 0)]
189210

0 commit comments

Comments
 (0)