mirror of
https://github.com/python/cpython
synced 2024-10-07 03:17:39 +00:00
gh-110519: Improve deprecation warning in the gettext module (#110520)
Deprecation warning about non-integer numbers in gettext now always refers to the line in the user code where gettext function or method is used. Previously, it could refer to a line in gettext code. Also, increase test coverage for NullTranslations and domain-aware functions like dngettext().
This commit is contained in:
parent
7bd560ce8d
commit
326c6c4e07
|
@ -46,6 +46,7 @@
|
|||
# find this format documented anywhere.
|
||||
|
||||
|
||||
import operator
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
@ -166,14 +167,21 @@ def _parse(tokens, priority=-1):
|
|||
|
||||
def _as_int(n):
|
||||
try:
|
||||
i = round(n)
|
||||
round(n)
|
||||
except TypeError:
|
||||
raise TypeError('Plural value must be an integer, got %s' %
|
||||
(n.__class__.__name__,)) from None
|
||||
|
||||
import warnings
|
||||
frame = sys._getframe(1)
|
||||
stacklevel = 2
|
||||
while frame.f_back is not None and frame.f_globals.get('__name__') == __name__:
|
||||
stacklevel += 1
|
||||
frame = frame.f_back
|
||||
warnings.warn('Plural value must be an integer, got %s' %
|
||||
(n.__class__.__name__,),
|
||||
DeprecationWarning, 4)
|
||||
DeprecationWarning,
|
||||
stacklevel)
|
||||
return n
|
||||
|
||||
|
||||
|
@ -200,7 +208,7 @@ def c2py(plural):
|
|||
elif c == ')':
|
||||
depth -= 1
|
||||
|
||||
ns = {'_as_int': _as_int}
|
||||
ns = {'_as_int': _as_int, '__name__': __name__}
|
||||
exec('''if True:
|
||||
def func(n):
|
||||
if not isinstance(n, int):
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import base64
|
||||
import gettext
|
||||
import unittest
|
||||
from functools import partial
|
||||
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
|
@ -122,8 +123,9 @@ def reset_gettext():
|
|||
|
||||
|
||||
class GettextBaseTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.addCleanup(os_helper.rmtree, os.path.split(LOCALEDIR)[0])
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.addClassCleanup(os_helper.rmtree, os.path.split(LOCALEDIR)[0])
|
||||
if not os.path.isdir(LOCALEDIR):
|
||||
os.makedirs(LOCALEDIR)
|
||||
with open(MOFILE, 'wb') as fp:
|
||||
|
@ -136,6 +138,8 @@ def setUp(self):
|
|||
fp.write(base64.decodebytes(UMO_DATA))
|
||||
with open(MMOFILE, 'wb') as fp:
|
||||
fp.write(base64.decodebytes(MMO_DATA))
|
||||
|
||||
def setUp(self):
|
||||
self.env = self.enterContext(os_helper.EnvironmentVarGuard())
|
||||
self.env['LANGUAGE'] = 'xx'
|
||||
reset_gettext()
|
||||
|
@ -316,59 +320,137 @@ def test_multiline_strings(self):
|
|||
trggrkg zrffntr pngnybt yvoenel.''')
|
||||
|
||||
|
||||
class PluralFormsTestCase(GettextBaseTest):
|
||||
class PluralFormsTests:
|
||||
|
||||
def _test_plural_forms(self, ngettext, gettext,
|
||||
singular, plural, tsingular, tplural,
|
||||
numbers_only=True):
|
||||
x = ngettext(singular, plural, 1)
|
||||
self.assertEqual(x, tsingular)
|
||||
x = ngettext(singular, plural, 2)
|
||||
self.assertEqual(x, tplural)
|
||||
x = gettext(singular)
|
||||
self.assertEqual(x, tsingular)
|
||||
|
||||
if numbers_only:
|
||||
lineno = self._test_plural_forms.__code__.co_firstlineno + 9
|
||||
with self.assertWarns(DeprecationWarning) as cm:
|
||||
x = ngettext(singular, plural, 1.0)
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
self.assertEqual(cm.lineno, lineno + 4)
|
||||
self.assertEqual(x, tsingular)
|
||||
with self.assertWarns(DeprecationWarning) as cm:
|
||||
x = ngettext(singular, plural, 1.1)
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
self.assertEqual(cm.lineno, lineno + 9)
|
||||
self.assertEqual(x, tplural)
|
||||
with self.assertRaises(TypeError):
|
||||
ngettext(singular, plural, None)
|
||||
else:
|
||||
x = ngettext(singular, plural, None)
|
||||
self.assertEqual(x, tplural)
|
||||
|
||||
def test_plural_forms(self):
|
||||
self._test_plural_forms(
|
||||
self.ngettext, self.gettext,
|
||||
'There is %s file', 'There are %s files',
|
||||
'Hay %s fichero', 'Hay %s ficheros')
|
||||
self._test_plural_forms(
|
||||
self.ngettext, self.gettext,
|
||||
'%d file deleted', '%d files deleted',
|
||||
'%d file deleted', '%d files deleted')
|
||||
|
||||
def test_plural_context_forms(self):
|
||||
ngettext = partial(self.npgettext, 'With context')
|
||||
gettext = partial(self.pgettext, 'With context')
|
||||
self._test_plural_forms(
|
||||
ngettext, gettext,
|
||||
'There is %s file', 'There are %s files',
|
||||
'Hay %s fichero (context)', 'Hay %s ficheros (context)')
|
||||
self._test_plural_forms(
|
||||
ngettext, gettext,
|
||||
'%d file deleted', '%d files deleted',
|
||||
'%d file deleted', '%d files deleted')
|
||||
|
||||
def test_plural_wrong_context_forms(self):
|
||||
self._test_plural_forms(
|
||||
partial(self.npgettext, 'Unknown context'),
|
||||
partial(self.pgettext, 'Unknown context'),
|
||||
'There is %s file', 'There are %s files',
|
||||
'There is %s file', 'There are %s files')
|
||||
|
||||
|
||||
class GNUTranslationsPluralFormsTestCase(PluralFormsTests, GettextBaseTest):
|
||||
def setUp(self):
|
||||
GettextBaseTest.setUp(self)
|
||||
self.localedir = os.curdir
|
||||
# Set up the bindings
|
||||
gettext.bindtextdomain('gettext', self.localedir)
|
||||
gettext.bindtextdomain('gettext', os.curdir)
|
||||
gettext.textdomain('gettext')
|
||||
self.mofile = MOFILE
|
||||
|
||||
def test_plural_forms1(self):
|
||||
eq = self.assertEqual
|
||||
x = gettext.ngettext('There is %s file', 'There are %s files', 1)
|
||||
eq(x, 'Hay %s fichero')
|
||||
x = gettext.ngettext('There is %s file', 'There are %s files', 2)
|
||||
eq(x, 'Hay %s ficheros')
|
||||
x = gettext.gettext('There is %s file')
|
||||
eq(x, 'Hay %s fichero')
|
||||
self.gettext = gettext.gettext
|
||||
self.ngettext = gettext.ngettext
|
||||
self.pgettext = gettext.pgettext
|
||||
self.npgettext = gettext.npgettext
|
||||
|
||||
def test_plural_context_forms1(self):
|
||||
eq = self.assertEqual
|
||||
x = gettext.npgettext('With context',
|
||||
'There is %s file', 'There are %s files', 1)
|
||||
eq(x, 'Hay %s fichero (context)')
|
||||
x = gettext.npgettext('With context',
|
||||
'There is %s file', 'There are %s files', 2)
|
||||
eq(x, 'Hay %s ficheros (context)')
|
||||
x = gettext.pgettext('With context', 'There is %s file')
|
||||
eq(x, 'Hay %s fichero (context)')
|
||||
|
||||
def test_plural_forms2(self):
|
||||
eq = self.assertEqual
|
||||
with open(self.mofile, 'rb') as fp:
|
||||
class GNUTranslationsWithDomainPluralFormsTestCase(PluralFormsTests, GettextBaseTest):
|
||||
def setUp(self):
|
||||
GettextBaseTest.setUp(self)
|
||||
# Set up the bindings
|
||||
gettext.bindtextdomain('gettext', os.curdir)
|
||||
|
||||
self.gettext = partial(gettext.dgettext, 'gettext')
|
||||
self.ngettext = partial(gettext.dngettext, 'gettext')
|
||||
self.pgettext = partial(gettext.dpgettext, 'gettext')
|
||||
self.npgettext = partial(gettext.dnpgettext, 'gettext')
|
||||
|
||||
def test_plural_forms_wrong_domain(self):
|
||||
self._test_plural_forms(
|
||||
partial(gettext.dngettext, 'unknown'),
|
||||
partial(gettext.dgettext, 'unknown'),
|
||||
'There is %s file', 'There are %s files',
|
||||
'There is %s file', 'There are %s files',
|
||||
numbers_only=False)
|
||||
|
||||
def test_plural_context_forms_wrong_domain(self):
|
||||
self._test_plural_forms(
|
||||
partial(gettext.dnpgettext, 'unknown', 'With context'),
|
||||
partial(gettext.dpgettext, 'unknown', 'With context'),
|
||||
'There is %s file', 'There are %s files',
|
||||
'There is %s file', 'There are %s files',
|
||||
numbers_only=False)
|
||||
|
||||
|
||||
class GNUTranslationsClassPluralFormsTestCase(PluralFormsTests, GettextBaseTest):
|
||||
def setUp(self):
|
||||
GettextBaseTest.setUp(self)
|
||||
with open(MOFILE, 'rb') as fp:
|
||||
t = gettext.GNUTranslations(fp)
|
||||
x = t.ngettext('There is %s file', 'There are %s files', 1)
|
||||
eq(x, 'Hay %s fichero')
|
||||
x = t.ngettext('There is %s file', 'There are %s files', 2)
|
||||
eq(x, 'Hay %s ficheros')
|
||||
x = t.gettext('There is %s file')
|
||||
eq(x, 'Hay %s fichero')
|
||||
|
||||
def test_plural_context_forms2(self):
|
||||
eq = self.assertEqual
|
||||
with open(self.mofile, 'rb') as fp:
|
||||
t = gettext.GNUTranslations(fp)
|
||||
x = t.npgettext('With context',
|
||||
'There is %s file', 'There are %s files', 1)
|
||||
eq(x, 'Hay %s fichero (context)')
|
||||
x = t.npgettext('With context',
|
||||
'There is %s file', 'There are %s files', 2)
|
||||
eq(x, 'Hay %s ficheros (context)')
|
||||
x = t.pgettext('With context', 'There is %s file')
|
||||
eq(x, 'Hay %s fichero (context)')
|
||||
self.gettext = t.gettext
|
||||
self.ngettext = t.ngettext
|
||||
self.pgettext = t.pgettext
|
||||
self.npgettext = t.npgettext
|
||||
|
||||
def test_plural_forms_null_translations(self):
|
||||
t = gettext.NullTranslations()
|
||||
self._test_plural_forms(
|
||||
t.ngettext, t.gettext,
|
||||
'There is %s file', 'There are %s files',
|
||||
'There is %s file', 'There are %s files',
|
||||
numbers_only=False)
|
||||
|
||||
def test_plural_context_forms_null_translations(self):
|
||||
t = gettext.NullTranslations()
|
||||
self._test_plural_forms(
|
||||
partial(t.npgettext, 'With context'),
|
||||
partial(t.pgettext, 'With context'),
|
||||
'There is %s file', 'There are %s files',
|
||||
'There is %s file', 'There are %s files',
|
||||
numbers_only=False)
|
||||
|
||||
|
||||
class PluralFormsInternalTestCase:
|
||||
# Examples from http://www.gnu.org/software/gettext/manual/gettext.html
|
||||
|
||||
def test_ja(self):
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Deprecation warning about non-integer number in :mod:`gettext` now alwais
|
||||
refers to the line in the user code where gettext function or method is
|
||||
used. Previously it could refer to a line in ``gettext`` code.
|
Loading…
Reference in a new issue