pylint
pylint copied to clipboard
``bad-string-format-type``: only works on old-style string formatting and can't infer values
Bug description
Two issues with bad-string-format-type:
- Just like
bad-format-characterthebad-string-format-typemessage is currently only raised for old-style string formatting. - If only a single value needs to be formatted, the check does not work if the value to format is passed in as a variable. Using variables in tuples however is fine.
Given a file a.py:
# pylint: disable=consider-using-f-string,missing-module-docstring
WORD = "abc"
print("%d" % "abc") # works
print("%d %d" % (WORD, 1)) # works
print("%d", WORD) # doesn't work
print("{:d}".format("abc")) # doesn't work
print(f"{'abc':d}") # doesn't work
Configuration
``pylintrc`` from ``pylint`` git repo.
Command used
pylint a.py
Pylint output
************* Module a
.notes/a.py:3:6: E1307: Argument 'builtins.str' does not match format type 'd' (bad-string-format-type)
.notes/a.py:4:6: E1307: Argument 'builtins.str' does not match format type 'd' (bad-string-format-type)
Expected behavior
All of the examples should raise the message.
Pylint version
pylint 2.14.0-dev0
astroid 2.11.2
Python 3.10.2 (main, Apr 3 2022, 14:46:07) [Clang 12.0.5 (clang-1205.0.22.9)]
OS / Environment
macOS BigSur 11.6
Additional dependencies
No response
When this is resolved, the doc/data/messages/b/bad-string-format-type/details.rst must be updated.
Two hints so far:
- The message is not raised for new-style formatting and f-strings because the logic for the check is only contained in
visit_binopofStringFormatChecker - When using a variable as format value (third example
print("%d" % WORD), we end up in thiselseblock: https://github.com/PyCQA/pylint/blob/30302f2555008a83db77aa0d61696bf5da4b3c51/pylint/checkers/strings.py#L360 It should be enough to add anotherelifjust above:
elif isinstance(args, nodes.Name):
args_elts = [args]
num_args = 1
@DudeNr33
print("%d", WORD) # doesn't work
is that third example which you also mention
third example print("%d" % WORD), we end up in this else block
supposed to be
print("%d" % WORD) # doesn't work ?
Because print("%d", WORD) doesn't emit a Python error though it does look like a mistake %d abc
Also
When using a variable as format value (third example print("%d" % WORD), we end up in this else block
has already been fixed.
So now the tests to correctly get to emit the msgs are these
WORD = "abc"
print("{:d}".format("abc")) # [bad-string-format-type]
print(f"{'abc':d}") # [bad-string-format-type]
@clavedeluna thanks for spotting this. You are correct, that's a typo and it should have been print("%d" % WORD).
If some of the problems are already fixed, even better!