classification
Title: str.format should raise exception when placeholder number doesn't match argument number
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.8
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: eric.smith, serhiy.storchaka, xiang.zhang
Priority: normal Keywords:

Created on 2018-05-28 14:57 by xiang.zhang, last changed 2018-06-08 14:22 by xiang.zhang. This issue is now closed.

Messages (7)
msg317859 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2018-05-28 14:57
I'm somewhat surprised when I have code like `"hello %s".format(person)` in my project there is no exception raised and "hello %s" returned. Have several tries it seems `str.format` won't check argument number.

>>> '{} {}'.format(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range
>>> '{} {}'.format(1, 2, 3)
'1 2'
>>> ''.format(1, 2, 3)
''
>>>

The IndexError is not ideal. I think this behavior could be improved since it's highly possible such code is an oversight bug. The old format string does a good job in this place:

>>> "%s %s" % 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> "%s %s" % (1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
>>> "" % 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
msg317865 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-05-28 15:13
This will break the following case:

def geterrmsg(n):
    return ('function doesn't have arguments' if n == 0 else
            'function have a single argument' if n == 1 else
            'function have %d arguments')

print(geterrmsg(n).format(n))

Actually geterrmsg() can take the error message from a translations database, and the number of different cases can be dependent on the language.
msg317867 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2018-05-28 15:22
Yes, this is a breaking change. A currently working piece of code suddenly raises an exception.

But, please note Serhiy in your example you have the same bug as me, you've gotten an oversight bug in it: it's {:d} not %s. That's why I want the improvement.
msg317890 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-28 17:02
This was a deliberate design choice, and as Serhiy notes, at least partially driven by translations. It seems to me it would be a job for a linter to point out a problem, if the string is a constant.
msg317891 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-05-28 17:31
If issue28308 be implemented, it may be that the Python compiler itself will emit a warning.
msg317894 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-28 17:44
I still think it's a job for a linter, even if the compiler optimizes away the call to .format().
msg319068 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2018-06-08 14:22
After reading PEP3101 and the archived mails, I think it's by design. Even if not, it might be too late to change.

I don't prefer either way, emitting warnings by compiler or linter. They can't give hints for runtime retrieved patterns, and not everyone turns on warning and uses linters.

I prefer using a customized string.Formatter, implementing my own `check_unused_args`, raising appropriate exceptions, and used it across my project instead of the default `str.format`. But there seems some problems with string.Formatter.
History
Date User Action Args
2018-06-08 14:22:19xiang.zhangsetstatus: open -> closed
resolution: not a bug
messages: + msg319068

stage: resolved
2018-05-28 17:44:35eric.smithsetmessages: + msg317894
2018-05-28 17:31:17serhiy.storchakasetmessages: + msg317891
2018-05-28 17:02:15eric.smithsetnosy: + eric.smith
messages: + msg317890
2018-05-28 15:22:58xiang.zhangsetmessages: + msg317867
2018-05-28 15:13:43serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg317865
2018-05-28 14:57:29xiang.zhangcreate