classification
Title: % formating - TypeError: not all arguments converted during string formatting
Type: behavior Stage:
Components: Interpreter Core Versions: Python 3.2, Python 2.7
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: amiadb, dpm, eric.smith, georg.brandl, sneetsher
Priority: normal Keywords:

Created on 2010-04-10 09:37 by sneetsher, last changed 2010-10-06 11:51 by amiadb. This issue is now closed.

Messages (10)
msg102764 - (view) Author: عبدالله شلي (Abdellah Chelli) (sneetsher) Date: 2010-04-10 09:37
c/printf accepts this:

n=1;
printf("One hour.", n);

in other hand python/print rises an error:

n=1
print "One hour." % n

Exactly the % formatting operation.
(TypeError: not all arguments converted during string formatting)

This feature is very important when we come to I18n (translation using gettext).

As most translator don't know this work around "%i hour." or "(%i) One hour.". This is not correct for many languages as I know like Arabic where they should write some thing like "One hour." or "An hour.".

https://bugs.launchpad.net/python/+bug/341015

Could this fixed to have same behaviour as in c? More robust.
msg102765 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2010-04-10 10:45
Can you use str.format instead? It doesn't have this restriction. It's available in 2.6 and 3.0.
msg102766 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2010-04-10 10:47
Also, if you use the 'mapping' version of %-formatting you also don't have this restriction:

>>> 'One hour' % {'n': 3}
msg102769 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010-04-10 11:25
I think we won't add new features to %-formatting, when it is considered old-style anyway.
msg102771 - (view) Author: عبدالله شلي (Abdellah Chelli) (sneetsher) Date: 2010-04-10 11:55
'One hour' % {'n': 3} / mapping will not work gettext replaces the string for each language.

str.format works well.

The problem we couldn't submit a bug to change the code for all packages using it.

I think it's better to be fixed here. At lease this problem must be mentioned within the "% formatting" on Documentation. So developers will avoid using it on internationalized tools.

I have already written this.
So is str.format the new way for formatting?
msg102774 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2010-04-10 12:31
I don't understand how this:
n=1
print "One hour." % n

is different from this:
map={'n': 3}
print "One hour." % map

In any event, if str.format works for you, use that. It's the new style.
msg102778 - (view) Author: عبدالله شلي (Abdellah Chelli) (sneetsher) Date: 2010-04-10 13:26
The full example:
===
import gettext

gettext.bindtextdomain("pygettext_test","./locale")
gettext.textdomain("pygettext_test")
_=gettext.gettext
n_=gettext.ngettext

n1=1
n2=3

print n_("there is %i command","there are %i commands",n1) % n1
print n_("there is %i command","there are %i commands",n2) % n2
===

the result of n_("there is %i command","there are %i commands",n2) will be:

"there is %i command"
or
"there are %i commands"
or
different string from translation file in case of other language then English as in Arabic we have 6 forms, 3 of them don't include %i.

"لا يوجد أي أمر"
"يوجد أمر واحد"
"يوجد أمران"
"يوجد %i أوامر"
"يوجد %i أمرا"
"يوجد %i أمر"

(You may not see the Arabic well aligned because it's a RTL language).

So format string is open to fit all languages.
That's why mapping good only for predefined strings.

Then these will be our solution:
===
print n_("there is {0} command","there are {0} commands",n1).format(n1)
print n_("there is {0} command","there are {0} commands",n2).format(n2)
===
msg102925 - (view) Author: عبدالله شلي (Abdellah Chelli) (sneetsher) Date: 2010-04-12 08:38
Mapping  works too, I don't know how I didn't get it. Thank you Eric.

Ex:
gettext.ngettext("%(package)d package", "%(package)d packages", countInstall) % { 'package': countInstall}

https://bugs.launchpad.net/ubuntu/+source/language-selector/+bug/409785/comments/9

Thank you guys, Eric & Georg.
msg103023 - (view) Author: David Planella (dpm) Date: 2010-04-13 09:01
It would be nice that %-formatting had the same functionality as in C when it comes to discarding unnamed arguments, but from the comments I understand that being deprecated no changes in functionality are contemplated.

However, before recommending using str.format, the fact that gettext does not yet seem to support it should also be taken into account. Some examples:

= %-formatting =

print gettext.ngettext("%(package)d package", "%(package)d packages", countInstall) % { 'package': countInstall}

Renders the following in a POT template:

#, python-format
msgid "%(package)d package"
msgid_plural "%(package)d packages"
msgstr[0] ""
msgstr[1] ""

-- All good. The string is marked as a python-format one and the %(package) argument can be dropped in the translation for the languages which need it. No program crash.

= str.format() formatting =

print gettext.ngettext("{no_of_packages} package", "{no_of_packages} packages", countInstall).format(no_of_packages=countInstall)

Renders the following in a POT template:

msgid "{no_of_packages} package"
msgid_plural "{no_of_packages} packages"
msgstr[0] ""
msgstr[1] ""

-- Not marked as python-format, since gettext does not seem to support the {} notation. No error-checking can take place for arguments. Not good.

print _("{day} day").format(day=countInstall)

msgid "{day} day"
msgstr ""

-- Same comment as above.

print _("{0} package").format(countInstall)

Extracted string in a POT template:

msgid "{0} package"
msgstr ""

-- Same comment as above

I understand that part of the error is in gettext, but I thought I'd mention it here as well, since this has caused quite a lot of crashes in Hebrew and Arabic translations in Ubuntu in the past, and will continue to do it until addressed.
msg118065 - (view) Author: (amiadb) Date: 2010-10-06 11:51
This bug is very disturbing in Hebrew too.
I need to translate "% hour" to "‫% שעה‬" and its wrong in Hebrew. in Hebrew I need to write "שעה אחת" (one hour).
History
Date User Action Args
2010-10-06 11:51:06amiadbsetnosy: + amiadb
messages: + msg118065
2010-04-13 09:01:59dpmsetnosy: + dpm
messages: + msg103023
2010-04-12 08:38:55sneetshersetmessages: + msg102925
2010-04-10 13:26:35sneetshersetmessages: + msg102778
2010-04-10 12:31:22eric.smithsetmessages: + msg102774
2010-04-10 11:55:57sneetshersetmessages: + msg102771
2010-04-10 11:25:30georg.brandlsetstatus: open -> closed

nosy: + georg.brandl
messages: + msg102769

resolution: wont fix
2010-04-10 10:47:30eric.smithsetmessages: + msg102766
2010-04-10 10:45:43eric.smithsetnosy: + eric.smith

messages: + msg102765
versions: + Python 2.7, Python 3.2, - Python 2.6, Python 2.5, Python 3.1
2010-04-10 09:37:58sneetshercreate