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) * ![]() |
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) * ![]() |
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) * ![]() |
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) * ![]() |
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) * ![]() |
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) * ![]() |
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) * ![]() |
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 |