1

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?

Lou
  • 2,200
  • 2
  • 33
  • 66
  • See https://stackoverflow.com/questions/4341746/how-do-i-disable-a-pylint-warning. – chepner Nov 28 '22 at 13:03
  • @chepner - I know how to waive a specific message, but we're not encouraged to use global waivers in our team. I'm wondering if there is a setting that adjusts the warning itself, so that it doesn't trigger if you use `string.format()` – Lou Nov 28 '22 at 13:25
  • If you don't want the long function calls to be in-line with the f-string, you could use a new variable `c = some_long_complicated_function(a, b)` and use `c` in the f-string. – cstoltze Apr 18 '23 at 03:49

2 Answers2

2

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 ;-)

NeilG
  • 3,886
  • 2
  • 22
  • 30
  • 1
    Makes sense! This is what I eventually did - waived the f-string warning. What I wanted, I think, was a half-way house solution where I allow Pylint to complain about the `"%s %s" % (var1, var2)` format (which is reasonable, because that format is not very clear), but at the same time forbid Pylint from complaining about the use of `format` strings (which in my opinion is often superior to f-strings.) But I realise that that's not possible - Pylint just likes to complain for increasingly obscure reasons. I've put a waiver in for this warning and left it at that. – Lou Apr 18 '23 at 14:41
  • I see @Lou, I get that point. Yes, that would be the ideal. I don't think anyone wants to continue to support `%` formatting anymore but it remains because of important libraries that use it, or something. Unfortunately I think Pylint's approach is just to "complain if it's not an f string", so despite the massive configurability Pylint normally presents it *doesn't* actually have an option to ensure one particular style is used. For instance, we can't get it to warn when f-strings are used! ;-) "Warning! F-string! Unpythonic!". Please accept the answer if you think it's appropriate. – NeilG Apr 20 '23 at 10:21
1

If you just want to avoid long line or line continuation character, I usually choose to use parentheses:

f_string = (f"The result of {a} + {b} is "
            f"{some_long_complicated_function(a, b)}")
Mechanic Pig
  • 6,756
  • 3
  • 10
  • 31
  • 2
    That is an acceptable workaround for this scenario. I have other scenarios where I can't even use f-strings because the string I want to interpolate contains a backslash. Do you know if it's possible to introduce a custom warning that catches % string format but not, say, string.format()? – Lou Nov 28 '22 at 14:37
  • 2
    It's possible to use f-strings in almost all possible case, and doing so it best performance wise (even if you needs to have an assignment because of an inner join that is impossible to do inside an f-string). What's the issue with the backslash in the interpolated string ? – Pierre.Sassoulas Nov 28 '22 at 16:06
  • So f-strings are supposed to improve readability, but they put code inside strings making it inaccessible for checking, and now they're not as readable as `format` either, and we have to workaround their problems. I'm not sure f-strings are an improvement. – NeilG Apr 18 '23 at 03:01