Issue #28563: Make plural form selection more lenient and accepting

non-integer numbers.  Django tests depend on this.
This commit is contained in:
Serhiy Storchaka 2016-11-14 19:30:36 +02:00
commit 39d2dfef44
2 changed files with 20 additions and 8 deletions

View File

@ -158,6 +158,14 @@ def _parse(tokens, priority=-1):
return result, nexttok return result, nexttok
def _as_int(n):
try:
i = round(n)
except TypeError:
raise TypeError('Plural value must be an integer, got %s' %
(n.__class__.__name__,)) from None
return n
def c2py(plural): def c2py(plural):
"""Gets a C expression as used in PO files for plural forms and returns a """Gets a C expression as used in PO files for plural forms and returns a
Python function that implements an equivalent expression. Python function that implements an equivalent expression.
@ -181,11 +189,11 @@ def c2py(plural):
elif c == ')': elif c == ')':
depth -= 1 depth -= 1
ns = {} ns = {'_as_int': _as_int}
exec('''if True: exec('''if True:
def func(n): def func(n):
if not isinstance(n, int): if not isinstance(n, int):
raise ValueError('Plural value must be an integer.') n = _as_int(n)
return int(%s) return int(%s)
''' % result, ns) ''' % result, ns)
return ns['func'] return ns['func']

View File

@ -440,12 +440,16 @@ class PluralFormsTestCase(GettextBaseTest):
self.assertRaises(ZeroDivisionError, f, 0) self.assertRaises(ZeroDivisionError, f, 0)
def test_plural_number(self): def test_plural_number(self):
f = gettext.c2py('1') f = gettext.c2py('n != 1')
self.assertEqual(f(1), 1) self.assertEqual(f(1), 0)
self.assertRaises(ValueError, f, 1.0) self.assertEqual(f(2), 1)
self.assertRaises(ValueError, f, '1') self.assertEqual(f(1.0), 0)
self.assertRaises(ValueError, f, []) self.assertEqual(f(2.0), 1)
self.assertRaises(ValueError, f, object()) self.assertEqual(f(1.1), 1)
self.assertRaises(TypeError, f, '2')
self.assertRaises(TypeError, f, b'2')
self.assertRaises(TypeError, f, [])
self.assertRaises(TypeError, f, object())
class GNUTranslationParsingTest(GettextBaseTest): class GNUTranslationParsingTest(GettextBaseTest):