Search code examples
pythonpylintf-stringstring.format

Pylint doesn't like string.format() and wants me to use f-strings. Is this fixable?


I've upgraded to pylint 2.15.2, and suddenly I'm getting lots of consider-using-f-string warnings whenever I run pylint, where I've used % formatting for strings. I understand why Pylint doesn't want to use the old % formatting, but I also get this error when I try to use string.format() instead. Take the following code as an example:

"""Example module"""
def some_long_complicated_function(a, b):
    """Do something"""
    return a + b

def main():
    """Main function"""
    a = 2
    b = 3

    percent_string = "The result of %s + %s is %s" % (
        a, b, some_long_complicated_function(a, b)
    )

    format_string = "The result of {} + {} is {}".format(
        a, b, some_long_complicated_function(a, b)
    )

    f_string = f"The result of {a} + {b} is {some_long_complicated_function(a, b)}"

    print(percent_string)
    print(format_string)
    print(f_string)

if __name__ == "__main__":
    main()

When I run pylint on this code, I get the following output:

************* Module pyexample
./pyexample.py:11:21: C0209: Formatting a regular string which could be a f-string (consider-using-f-string)
./pyexample.py:15:20: C0209: Formatting a regular string which could be a f-string (consider-using-f-string)

------------------------------------------------------------------
Your code has been rated at 8.46/10 (previous run: 6.15/10, +2.31)

There are instances like this where I don't want to use an f-string, because I think it actually hampers - not helps - readability, especially in cases like these where I may be writing long function calls inline within the string. In these places I'd rather use string.format(), because you can nicely separate out the format specifiers {} from the functions to generate the strings I want by putting them on a separate line. With f-strings, my lines may end up being too long and I have to resort to using line continuation characters, which again harms the readability IMO.

The problem is, Pylint doesn't like string.format() - it only wants me to use f-strings. I know that this is a 'Convention' not 'Error', but my code has to pass Pylint 100%. I could waive this message, but that's not good practice and there are places in my code where I do want to swap out the %-string formats.

My question:

Is there a way to configure Pylint so that when I run it, it will not flag a consider-using-f-string warning when I use string.format() (only when I use % strings)? I've had a look in the rc-file but I can't see any obvious setting like this.

Or is the only way to fix this to waive the warning entirely?


Solution

  • I agree with you. I don't think f-strings are such a great idea. I don't like hiding expressions inside literal strings which probably defeats some checks and I'm not convinced it's not a security issue. It doesn't seem Pythonic either, as using format strings forces the evaluation of the expressions properly in a clear order instead of compressing code inside a string literal.

    Also format strings can take a dictionary which then very readably allows distribution of names within the template, so I'm not sure f-strings are really more readable either, as I believe you are also arguing. There's even an answer to this question that proposes a workaround to improve readability of f-strings that include too much code pushed inside a string literal!

    Maybe we should write entire Python modules inside a single great big string literal? Back to PHP anyone?

    Even Real Python seems to think the only downside of Python format is readability but then goes on to provide a contrived example, and glosses over the succinct, elegant solution of providing variables to the template in a dict, as if that wasn't the whole point of designing format that way!

    But I'm not sure what difference you mean by "not flag" and "waive", since you either want to have these warnings or not.

    https://pylint.readthedocs.io/en/latest/user_guide/messages/convention/consider-using-f-string.html

    So to just turn off pylint convention notice consider-using-f-string / C0209, just add that code to the disable list in your .pylintrc:

    [MESSAGES CONTROL]
    disable = C0209
    

    Or if you prefer the meaningful name instead:

    [MESSAGES CONTROL]
    disable = consider-using-f-string
    

    And if you already have some messages disabled then just add it to the list:

    [MESSAGES CONTROL]
    disable = E0602, E1101, C0103, C0209, C3001
    

    And never worry about it ever again.

    May be one day f-strings will be depreciated and eventually removed ;-)