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