pylint icon indicating copy to clipboard operation
pylint copied to clipboard

``bad-string-format-type``: only works on old-style string formatting and can't infer values

Open DudeNr33 opened this issue 3 years ago • 1 comments

Bug description

Two issues with bad-string-format-type:

  1. Just like bad-format-character the bad-string-format-type message is currently only raised for old-style string formatting.
  2. 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

DudeNr33 avatar Apr 03 '22 13:04 DudeNr33

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_binop of StringFormatChecker
  • When using a variable as format value (third example print("%d" % WORD), we end up in this else block: https://github.com/PyCQA/pylint/blob/30302f2555008a83db77aa0d61696bf5da4b3c51/pylint/checkers/strings.py#L360 It should be enough to add another elif just above:
            elif isinstance(args, nodes.Name):
                args_elts = [args]
                num_args = 1

DudeNr33 avatar Apr 03 '22 13:04 DudeNr33

@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 avatar Nov 30 '22 11:11 clavedeluna

@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!

DudeNr33 avatar Dec 01 '22 04:12 DudeNr33