Method: pylint.checkers.format.FormatChecker._check_keyword_parentheses
Calls: 11184, Exceptions: 8, Paths: 51Back
Path 1: 10760 calls (0.96)
list (10760)
16 (110) 19 (79) 21 (70) 28 (51) 22 (49) 23 (47) 27 (47) 18 (47) 24 (46) 29 (45)
None (10760)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 2: 162 calls (0.01)
list (162)
110 (4) 39 (4) 23 (4) 47 (4) 488 (3) 31 (3) 5 (3) 297 (3) 28 (2) 86 (2)
None (162)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 3: 41 calls (0.0)
list (41)
71 (2) 41 (1) 55 (1) 163 (1) 180 (1) 208 (1) 255 (1) 354 (1) 431 (1) 458 (1)
None (41)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 4: 25 calls (0.0)
list (25)
140 (1) 303 (1) 379 (1) 945 (1) 982 (1) 1025 (1) 1050 (1) 1083 (1) 21 (1) 734 (1)
None (25)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 5: 17 calls (0.0)
list (17)
0 (3) 356 (2) 165 (1) 742 (1) 201 (1) 346 (1) 244 (1) 120 (1) 362 (1) 68 (1)
None (17)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 6: 15 calls (0.0)
list (15)
0 (4) 292 (1) 16 (1) 56 (1) 78 (1) 268 (1) 643 (1) 653 (1) 663 (1) 14 (1)
None (15)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 7: 15 calls (0.0)
list (15)
14 (1) 4 (1) 28 (1) 315 (1) 36 (1) 23 (1) 56 (1) 113 (1) 144 (1) 237 (1)
None (15)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 8: 13 calls (0.0)
list (13)
91 (1) 654 (1) 41 (1) 59 (1) 99 (1) 118 (1) 160 (1) 227 (1) 112 (1) 220 (1)
None (13)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 9: 12 calls (0.0)
list (12)
77 (1) 923 (1) 943 (1) 1014 (1) 1037 (1) 38 (1) 281 (1) 116 (1) 83 (1) 58 (1)
None (12)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 10: 11 calls (0.0)
list (11)
67 (2) 831 (1) 1003 (1) 52 (1) 31 (1) 393 (1) 564 (1) 143 (1) 231 (1) 7 (1)
None (11)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 11: 11 calls (0.0)
list (11)
90 (1) 101 (1) 4 (1) 716 (1) 312 (1) 129 (1) 585 (1) 634 (1) 679 (1) 303 (1)
None (11)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 12: 7 calls (0.0)
list (7)
126 (2) 122 (1) 53 (1) 905 (1) 302 (1) 0 (1)
None (7)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 13: 7 calls (0.0)
list (7)
1423 (1) 243 (1) 23 (1) 346 (1) 212 (1) 274 (1) 1887 (1)
None (7)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 14: 7 calls (0.0)
list (7)
175 (2) 67 (1) 213 (1) 74 (1) 70 (1) 168 (1)
None (7)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 15: 5 calls (0.0)
list (5)
846 (1) 33 (1) 98 (1) 251 (1) 29 (1)
None (5)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 16: 5 calls (0.0)
list (5)
265 (1) 571 (1) 597 (1) 608 (1) 619 (1)
None (5)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 17: 5 calls (0.0)
list (5)
0 (2) 455 (1) 498 (1) 541 (1)
None (5)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 18: 5 calls (0.0)
list (5)
336 (1) 379 (1) 411 (1) 429 (1) 439 (1)
None (5)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 19: 4 calls (0.0)
list (4)
63 (1) 96 (1) 113 (1) 1 (1)
None (4)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 20: 4 calls (0.0)
list (4)
333 (1) 86 (1) 38 (1) 175 (1)
None (4)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 21: 3 calls (0.0)
list (3)
32 (1) 287 (1) 78 (1)
None (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 22: 3 calls (0.0)
list (3)
30 (1) 1 (1) 2 (1)
None (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 23: 3 calls (0.0)
list (3)
167 (1) 194 (1) 223 (1)
None (3)
GeneratorExit (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 24: 3 calls (0.0)
list (3)
419 (1) 0 (1) 2 (1)
None (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 25: 3 calls (0.0)
list (3)
12 (1) 29 (1) 355 (1)
None (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 26: 3 calls (0.0)
list (3)
135 (1) 408 (1) 0 (1)
None (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 27: 3 calls (0.0)
list (3)
97 (1) 115 (1) 133 (1)
None (3)
GeneratorExit (3)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 28: 2 calls (0.0)
list (2)
99 (1) 237 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 29: 2 calls (0.0)
list (2)
44 (1) 216 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 30: 2 calls (0.0)
list (2)
151 (1) 367 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 31: 2 calls (0.0)
list (2)
79 (1) 0 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 32: 2 calls (0.0)
list (2)
167 (1) 185 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 33: 2 calls (0.0)
list (2)
203 (1) 220 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 34: 2 calls (0.0)
list (2)
255 (1) 399 (1)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 35: 2 calls (0.0)
list (2)
0 (2)
None (2)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 36: 1 calls (0.0)
list (1)
294 (1)
None (1)
GeneratorExit (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 37: 1 calls (0.0)
list (1)
374 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 38: 1 calls (0.0)
list (1)
54 (1)
None (1)
GeneratorExit (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 39: 1 calls (0.0)
list (1)
472 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 40: 1 calls (0.0)
list (1)
524 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 41: 1 calls (0.0)
list (1)
118 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 42: 1 calls (0.0)
list (1)
334 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 43: 1 calls (0.0)
list (1)
387 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 44: 1 calls (0.0)
list (1)
669 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 45: 1 calls (0.0)
list (1)
376 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 46: 1 calls (0.0)
list (1)
448 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 47: 1 calls (0.0)
list (1)
0 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 48: 1 calls (0.0)
list (1)
0 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 49: 1 calls (0.0)
list (1)
0 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 50: 1 calls (0.0)
list (1)
0 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return
Path 51: 1 calls (0.0)
list (1)
0 (1)
None (1)
1def _check_keyword_parentheses(
2 self, tokens: list[tokenize.TokenInfo], start: int
3 ) -> None:
4 """Check that there are not unnecessary parentheses after a keyword.
5
6 Parens are unnecessary if there is exactly one balanced outer pair on a
7 line and contains no commas (i.e. is not a tuple).
8
9 Args:
10 tokens: The entire list of Tokens.
11 start: The position of the keyword in the token list.
12 """
13 # If the next token is not a paren, we're fine.
14 if tokens[start + 1].string != "(":
15 return
16 if (
17 tokens[start].string == "not"
18 and start > 0
19 and tokens[start - 1].string == "is"
20 ):
21 # If this is part of an `is not` expression, we have a binary operator
22 # so the parentheses are not necessarily redundant.
23 return
24 found_and_or = False
25 contains_walrus_operator = False
26 walrus_operator_depth = 0
27 contains_double_parens = 0
28 depth = 0
29 keyword_token = str(tokens[start].string)
30 line_num = tokens[start].start[0]
31 for i in range(start, len(tokens) - 1):
32 token = tokens[i]
33
34 # If we hit a newline, then assume any parens were for continuation.
35 if token.type == tokenize.NL:
36 return
37 # Since the walrus operator doesn't exist below python3.8, the tokenizer
38 # generates independent tokens
39 if (
40 token.string == ":=" # <-- python3.8+ path
41 or token.string + tokens[i + 1].string == ":="
42 ):
43 contains_walrus_operator = True
44 walrus_operator_depth = depth
45 if token.string == "(":
46 depth += 1
47 if tokens[i + 1].string == "(":
48 contains_double_parens = 1
49 elif token.string == ")":
50 depth -= 1
51 if depth:
52 if contains_double_parens and tokens[i + 1].string == ")":
53 # For walrus operators in `if (not)` conditions and comprehensions
54 if keyword_token in {"in", "if", "not"}:
55 continue
56 return
57 contains_double_parens -= 1
58 continue
59 # ')' can't happen after if (foo), since it would be a syntax error.
60 if tokens[i + 1].string in {":", ")", "]", "}", "in"} or tokens[
61 i + 1
62 ].type in {tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT}:
63 if contains_walrus_operator and walrus_operator_depth - 1 == depth:
64 return
65 # The empty tuple () is always accepted.
66 if i == start + 2:
67 return
68 if found_and_or:
69 return
70 if keyword_token == "in":
71 # This special case was added in https://github.com/PyCQA/pylint/pull/4948
72 # but it could be removed in the future. Avoid churn for now.
73 return
74 self.add_message(
75 "superfluous-parens", line=line_num, args=keyword_token
76 )
77 return
78 elif depth == 1:
79 # This is a tuple, which is always acceptable.
80 if token[1] == ",":
81 return
82 # 'and' and 'or' are the only boolean operators with lower precedence
83 # than 'not', so parens are only required when they are found.
84 if token[1] in {"and", "or"}:
85 found_and_or = True
86 # A yield inside an expression must always be in parentheses,
87 # quit early without error.
88 elif token[1] == "yield":
89 return
90 # A generator expression always has a 'for' token in it, and
91 # the 'for' token is only legal inside parens when it is in a
92 # generator expression. The parens are necessary here, so bail
93 # without an error.
94 elif token[1] == "for":
95 return
96 # A generator expression can have an 'else' token in it.
97 # We check the rest of the tokens to see if any problems occur after
98 # the 'else'.
99 elif token[1] == "else":
100 if "(" in (i.string for i in tokens[i:]):
101 self._check_keyword_parentheses(tokens[i:], 0)
102 return