Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explanation of pylint bad-format-string

Tags:

python

pylint

In the following file:

"""hello I am the module spam.py"""
from __future__ import unicode_literals
'hello {world}'.format(world='potato')

We have the following pylint violation for bad-format-string:

wim@SDFA100461C:/tmp$ pylint --reports=n spam.py
No config file found, using default configuration
************* Module spam
W:  3, 0: Invalid format string (bad-format-string)

I don't understand this suggestion, pylint devs say the check is about PEP 3101 style but I don't see anything in the PEP which is violated here.

What is the problem? What does pylint wish us to do about it?

Version numbers below.

wim@SDFA100461C:/tmp$ pylint --version
No config file found, using default configuration
pylint 1.3.0, 
astroid 1.2.0, common 0.62.1
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2]
like image 638
wim Avatar asked Jul 31 '14 11:07

wim


1 Answers

This is a bug in pylint; it assumes that all string formats are byte strings.

The linter parses the format and then the placeholder names. Because you are using Unicode literals, this produces a unicode name too, but the parser makes the assumption that it'll only encounter bytestrings; if not, it assumes it found an integer instead:

if not isinstance(keyname, str):
    # In Python 2 it will return long which will lead
    # to different output between 2 and 3
    keyname = int(keyname)

This raises a ValueError for your format string as world is parsed to a unicode value instead:

>>> import string
>>> formatter = string.Formatter()
>>> parseiterator = formatter.parse(u'hello {world}')
>>> result = next(parseiterator)
>>> result
(u'hello ', u'world', u'', None)
>>> keyname, fielditerator = result[1]._formatter_field_name_split()
>>> keyname
u'world'

The ValueError exception then in turn is caught and converted to a IncompleteFormatString exception, which then results in the W1302 error code.

See the parse_format_method_string function.

The test there should be altered to test for the same type as format_string instead:

if not isinstance(keyname, type(format_string)):
    # In Python 2 it will return long which will lead
    # to different output between 2 and 3
    keyname = int(keyname)

This'll do the correct thing in both Python 2 and 3.

like image 127
Martijn Pieters Avatar answered Sep 28 '22 07:09

Martijn Pieters