Issue 33669: str.format should raise exception when placeholder number doesn't match argument number (original) (raw)

Issue33669

Created on 2018-05-28 14:57 by xiang.zhang, last changed 2022-04-11 14:59 by admin. 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 "", line 1, in 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 "", line 1, in TypeError: not enough arguments for format string >>> "%s %s" % (1,2,3) Traceback (most recent call last): File "", line 1, in TypeError: not all arguments converted during string formatting >>> "" % 1 Traceback (most recent call last): File "", line 1, in 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 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
2022-04-11 14:59:00 admin set github: 77850
2018-06-08 14:22:19 xiang.zhang set status: open -> closedresolution: not a bugmessages: + stage: resolved
2018-05-28 17:44:35 eric.smith set messages: +
2018-05-28 17:31:17 serhiy.storchaka set messages: +
2018-05-28 17:02:15 eric.smith set nosy: + eric.smithmessages: +
2018-05-28 15:22:58 xiang.zhang set messages: +
2018-05-28 15:13:43 serhiy.storchaka set nosy: + serhiy.storchakamessages: +
2018-05-28 14:57:29 xiang.zhang create