Skip to content

Commit eadefe3

Browse files
ANSHUL SINGHclaude
authored andcommitted
Fix false positive bad-string-format-type for subclasses of builtin types
``arg_matches_format_type`` compared ``pytype()`` exactly with ``builtins.int``/``float``/``str``, so ``bool``, ``IntEnum`` members and user subclasses never matched and were reported for ``%d``, ``%i``, ``%x``, ``%f`` and so on. Use ``is_subtype_of`` so subclasses behave like their base. Closes #11315 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 10ba50f)
1 parent db00e3b commit eadefe3

4 files changed

Lines changed: 35 additions & 9 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix false positives for :ref:`bad-string-format-type` when the argument is an
2+
instance of a subclass of ``int``, ``float`` or ``str``, such as ``bool`` or an
3+
``IntEnum`` member formatted with ``%d``.
4+
5+
Closes #11315

pylint/checkers/strings.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,16 @@ def arg_matches_format_type(
227227
# All types can be printed with %s, %r and %a
228228
return True
229229
if isinstance(arg_type, astroid.Instance):
230-
match arg_type.pytype():
231-
case "builtins.str":
232-
return format_type == "c"
233-
case "builtins.float":
234-
# ``i`` and ``u`` accept a float at runtime (truncated like ``d``)
235-
return format_type in "diueEfFgGn%"
236-
case "builtins.int":
237-
# Integers allow all types
238-
return True
230+
# Subclasses behave like their builtin base: ``bool`` and ``IntEnum``
231+
# members format like ``int``, a ``float`` subclass like ``float``.
232+
if arg_type.is_subtype_of("builtins.str"):
233+
return format_type == "c"
234+
if arg_type.is_subtype_of("builtins.int"):
235+
# Integers allow all types
236+
return True
237+
if arg_type.is_subtype_of("builtins.float"):
238+
# ``i`` and ``u`` accept a float at runtime (truncated like ``d``)
239+
return format_type in "diueEfFgGn%"
239240
return False
240241
return True
241242

tests/functional/b/bad_string_format_type.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,22 @@ def test_format(my_input_value, my_other_input_value):
5454
print("%d %s" % (my_input_value, my_other_input_value))
5555
to_be_formatted = (my_input_value, my_other_input_value)
5656
print("%d %s" % to_be_formatted)
57+
58+
59+
# Subclasses of the builtin types format like their base type
60+
# pylint: disable=wrong-import-position, missing-class-docstring, expression-not-assigned
61+
import enum
62+
63+
64+
class Color(enum.IntEnum):
65+
RED = 1
66+
67+
68+
class MyFloat(float):
69+
pass
70+
71+
72+
"%i" % True
73+
"%d %x" % (Color.RED, Color.RED)
74+
"%f %d" % (MyFloat(1.5), MyFloat(1.5))
75+
"%x %s" % (MyFloat(1.5), "a") # [bad-string-format-type]

tests/functional/b/bad_string_format_type.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ bad-string-format-type:38:0:38:23::Argument 'builtins.list' does not match forma
88
bad-string-format-type:41:0:41:11::Argument 'builtins.str' does not match format type 'd':UNDEFINED
99
bad-string-format-type:42:0:42:22::Argument 'builtins.str' does not match format type 'd':UNDEFINED
1010
bad-string-format-type:46:0:46:29::Argument 'builtins.str' does not match format type 'd':UNDEFINED
11+
bad-string-format-type:75:0:75:29::Argument 'functional.b.bad_string_format_type.MyFloat' does not match format type 'x':UNDEFINED

0 commit comments

Comments
 (0)