Path 1: 688 calls (0.84)

BinOp (688)

None (688)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 2: 30 calls (0.04)

BinOp (30)

None (30)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 3: 24 calls (0.03)

BinOp (24)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 4: 10 calls (0.01)

BinOp (10)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 5: 9 calls (0.01)

BinOp (9)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 6: 8 calls (0.01)

BinOp (8)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 7: 7 calls (0.01)

BinOp (7)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 8: 6 calls (0.01)

BinOp (6)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 9: 4 calls (0.0)

BinOp (4)

None (4)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 10: 3 calls (0.0)

BinOp (3)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 11: 3 calls (0.0)

BinOp (3)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 12: 3 calls (0.0)

BinOp (3)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 13: 2 calls (0.0)

BinOp (2)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 14: 2 calls (0.0)

BinOp (2)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 15: 2 calls (0.0)

BinOp (2)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 16: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 17: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 18: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 19: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 20: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 21: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 22: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 23: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 24: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 25: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 26: 1 calls (0.0)

BinOp (1)

None (1)

UnsupportedFormatCharacter (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 27: 1 calls (0.0)

BinOp (1)

None (1)

IncompleteFormatString (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 28: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )
            

Path 29: 1 calls (0.0)

BinOp (1)

1@only_required_for_messages(
2        "bad-format-character",
3        "truncated-format-string",
4        "mixed-format-string",
5        "bad-format-string-key",
6        "missing-format-string-key",
7        "unused-format-string-key",
8        "bad-string-format-type",
9        "format-needs-mapping",
10        "too-many-format-args",
11        "too-few-format-args",
12        "format-string-without-interpolation",
13    )
14    def visit_binop(self, node: nodes.BinOp) -> None:
15        if node.op != "%":
16            return
17        left = node.left
18        args = node.right
19
20        if not (isinstance(left, nodes.Const) and isinstance(left.value, str)):
21            return
22        format_string = left.value
23        try:
24            (
25                required_keys,
26                required_num_args,
27                required_key_types,
28                required_arg_types,
29            ) = utils.parse_format_string(format_string)
30        except utils.UnsupportedFormatCharacter as exc:
31            formatted = format_string[exc.index]
32            self.add_message(
33                "bad-format-character",
34                node=node,
35                args=(formatted, ord(formatted), exc.index),
36            )
37            return
38        except utils.IncompleteFormatString:
39            self.add_message("truncated-format-string", node=node)
40            return
41        if not required_keys and not required_num_args:
42            self.add_message("format-string-without-interpolation", node=node)
43            return
44        if required_keys and required_num_args:
45            # The format string uses both named and unnamed format
46            # specifiers.
47            self.add_message("mixed-format-string", node=node)
48        elif required_keys:
49            # The format string uses only named format specifiers.
50            # Check that the RHS of the % operator is a mapping object
51            # that contains precisely the set of keys required by the
52            # format string.
53            if isinstance(args, nodes.Dict):
54                keys = set()
55                unknown_keys = False
56                for k, _ in args.items:
57                    if isinstance(k, nodes.Const):
58                        key = k.value
59                        if isinstance(key, str):
60                            keys.add(key)
61                        else:
62                            self.add_message(
63                                "bad-format-string-key", node=node, args=key
64                            )
65                    else:
66                        # One of the keys was something other than a
67                        # constant.  Since we can't tell what it is,
68                        # suppress checks for missing keys in the
69                        # dictionary.
70                        unknown_keys = True
71                if not unknown_keys:
72                    for key in required_keys:
73                        if key not in keys:
74                            self.add_message(
75                                "missing-format-string-key", node=node, args=key
76                            )
77                for key in keys:
78                    if key not in required_keys:
79                        self.add_message(
80                            "unused-format-string-key", node=node, args=key
81                        )
82                for key, arg in args.items:
83                    if not isinstance(key, nodes.Const):
84                        continue
85                    format_type = required_key_types.get(key.value, None)
86                    arg_type = utils.safe_infer(arg)
87                    if (
88                        format_type is not None
89                        and arg_type
90                        and arg_type != astroid.Uninferable
91                        and not arg_matches_format_type(arg_type, format_type)
92                    ):
93                        self.add_message(
94                            "bad-string-format-type",
95                            node=node,
96                            args=(arg_type.pytype(), format_type),
97                        )
98            elif isinstance(args, (OTHER_NODES, nodes.Tuple)):
99                type_name = type(args).__name__
100                self.add_message("format-needs-mapping", node=node, args=type_name)
101            # else:
102            # The RHS of the format specifier is a name or
103            # expression.  It may be a mapping object, so
104            # there's nothing we can check.
105        else:
106            # The format string uses only unnamed format specifiers.
107            # Check that the number of arguments passed to the RHS of
108            # the % operator matches the number required by the format
109            # string.
110            args_elts = []
111            if isinstance(args, nodes.Tuple):
112                rhs_tuple = utils.safe_infer(args)
113                num_args = None
114                if isinstance(rhs_tuple, nodes.BaseContainer):
115                    args_elts = rhs_tuple.elts
116                    num_args = len(args_elts)
117            elif isinstance(args, (OTHER_NODES, (nodes.Dict, nodes.DictComp))):
118                args_elts = [args]
119                num_args = 1
120            elif isinstance(args, nodes.Name):
121                inferred = utils.safe_infer(args)
122                if isinstance(inferred, nodes.Tuple):
123                    # The variable is a tuple, so we need to get the elements
124                    # from it for further inspection
125                    args_elts = inferred.elts
126                    num_args = len(args_elts)
127                elif isinstance(inferred, nodes.Const):
128                    args_elts = [inferred]
129                    num_args = 1
130                else:
131                    num_args = None
132            else:
133                # The RHS of the format specifier is an expression.
134                # It could be a tuple of unknown size, so
135                # there's nothing we can check.
136                num_args = None
137            if num_args is not None:
138                if num_args > required_num_args:
139                    self.add_message("too-many-format-args", node=node)
140                elif num_args < required_num_args:
141                    self.add_message("too-few-format-args", node=node)
142                for arg, format_type in zip(args_elts, required_arg_types):
143                    if not arg:
144                        continue
145                    arg_type = utils.safe_infer(arg)
146                    if (
147                        arg_type
148                        and arg_type != astroid.Uninferable
149                        and not arg_matches_format_type(arg_type, format_type)
150                    ):
151                        self.add_message(
152                            "bad-string-format-type",
153                            node=node,
154                            args=(arg_type.pytype(), format_type),
155                        )