diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index ec2c12806b4..d7d779da3d3 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -46,16 +46,6 @@ class-based API instead. returned. [#]_ -.. function:: bind_textdomain_codeset(domain, codeset=None) - - Bind the *domain* to *codeset*, changing the encoding of byte strings - returned by the :func:`lgettext`, :func:`ldgettext`, :func:`lngettext` - and :func:`ldngettext` functions. - If *codeset* is omitted, then the current binding is returned. - - .. deprecated-removed:: 3.8 3.10 - - .. function:: textdomain(domain=None) Change or query the current global domain. If *domain* is ``None``, then the @@ -108,29 +98,6 @@ class-based API instead. .. versionadded:: 3.8 -.. function:: lgettext(message) -.. function:: ldgettext(domain, message) -.. function:: lngettext(singular, plural, n) -.. function:: ldngettext(domain, singular, plural, n) - - Equivalent to the corresponding functions without the ``l`` prefix - (:func:`.gettext`, :func:`dgettext`, :func:`ngettext` and :func:`dngettext`), - but the translation is returned as a byte string encoded in the preferred - system encoding if no other encoding was explicitly set with - :func:`bind_textdomain_codeset`. - - .. warning:: - - These functions should be avoided in Python 3, because they return - encoded bytes. It's much better to use alternatives which return - Unicode strings instead, since most Python applications will want to - manipulate human readable text as strings instead of bytes. Further, - it's possible that you may get unexpected Unicode-related exceptions - if there are encoding problems with the translated strings. - - .. deprecated-removed:: 3.8 3.10 - - Note that GNU :program:`gettext` also defines a :func:`dcgettext` method, but this was deemed not useful and so it is currently unimplemented. @@ -181,7 +148,7 @@ install themselves in the built-in namespace as the function :func:`_`. the environment variables. -.. function:: translation(domain, localedir=None, languages=None, class_=None, fallback=False, codeset=None) +.. function:: translation(domain, localedir=None, languages=None, class_=None, fallback=False) Return a :class:`*Translations` instance based on the *domain*, *localedir*, and *languages*, which are first passed to :func:`find` to get a list of the @@ -205,11 +172,11 @@ install themselves in the built-in namespace as the function :func:`_`. .. versionchanged:: 3.3 :exc:`IOError` used to be raised instead of :exc:`OSError`. - .. deprecated-removed:: 3.8 3.10 - The *codeset* parameter. + .. versionchanged:: 3.10 + The *codeset* parameter has been removed. -.. function:: install(domain, localedir=None, codeset=None, names=None) +.. function:: install(domain, localedir=None, names=None) This installs the function :func:`_` in Python's builtins namespace, based on *domain*, *localedir*, and *codeset* which are passed to the function @@ -228,8 +195,8 @@ install themselves in the built-in namespace as the function :func:`_`. builtins namespace, so it is easily accessible in all modules of your application. - .. deprecated-removed:: 3.8 3.10 - The *codeset* parameter. + .. versionchanged:: 3.10 + The *codeset* parameter has been removed. The :class:`NullTranslations` class @@ -294,22 +261,6 @@ are the methods of :class:`!NullTranslations`: .. versionadded:: 3.8 - .. method:: lgettext(message) - .. method:: lngettext(singular, plural, n) - - Equivalent to :meth:`.gettext` and :meth:`.ngettext`, but the translation - is returned as a byte string encoded in the preferred system encoding - if no encoding was explicitly set with :meth:`set_output_charset`. - Overridden in derived classes. - - .. warning:: - - These methods should be avoided in Python 3. See the warning for the - :func:`lgettext` function. - - .. deprecated-removed:: 3.8 3.10 - - .. method:: info() Return the "protected" :attr:`_info` variable, a dictionary containing @@ -321,21 +272,6 @@ are the methods of :class:`!NullTranslations`: Return the encoding of the message catalog file. - .. method:: output_charset() - - Return the encoding used to return translated messages in :meth:`.lgettext` - and :meth:`.lngettext`. - - .. deprecated-removed:: 3.8 3.10 - - - .. method:: set_output_charset(charset) - - Change the encoding used to return translated messages. - - .. deprecated-removed:: 3.8 3.10 - - .. method:: install(names=None) This method installs :meth:`.gettext` into the built-in namespace, @@ -450,22 +386,6 @@ unexpected, or if other problems occur while reading the file, instantiating a .. versionadded:: 3.8 - .. method:: lgettext(message) - .. method:: lngettext(singular, plural, n) - - Equivalent to :meth:`.gettext` and :meth:`.ngettext`, but the translation - is returned as a byte string encoded in the preferred system encoding - if no encoding was explicitly set with - :meth:`~NullTranslations.set_output_charset`. - - .. warning:: - - These methods should be avoided in Python 3. See the warning for the - :func:`lgettext` function. - - .. deprecated-removed:: 3.8 3.10 - - Solaris message catalog support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Lib/gettext.py b/Lib/gettext.py index 77b67aef420..23dfccfe114 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -51,12 +51,10 @@ import re import sys -__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog', - 'find', 'translation', 'install', 'textdomain', 'bindtextdomain', - 'bind_textdomain_codeset', - 'dgettext', 'dngettext', 'gettext', 'lgettext', 'ldgettext', - 'ldngettext', 'lngettext', 'ngettext', - 'pgettext', 'dpgettext', 'npgettext', 'dnpgettext', +__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog', 'find', + 'translation', 'install', 'textdomain', 'bindtextdomain', + 'dgettext', 'dngettext', 'gettext', 'ngettext', 'pgettext', + 'dpgettext', 'npgettext', 'dnpgettext', ] _default_localedir = os.path.join(sys.base_prefix, 'share', 'locale') @@ -274,20 +272,6 @@ class NullTranslations: return self._fallback.gettext(message) return message - def lgettext(self, message): - import warnings - warnings.warn('lgettext() is deprecated, use gettext() instead', - DeprecationWarning, 2) - import locale - if self._fallback: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\blgettext\b.*', - DeprecationWarning) - return self._fallback.lgettext(message) - if self._output_charset: - return message.encode(self._output_charset) - return message.encode(locale.getpreferredencoding()) - def ngettext(self, msgid1, msgid2, n): if self._fallback: return self._fallback.ngettext(msgid1, msgid2, n) @@ -296,24 +280,6 @@ class NullTranslations: else: return msgid2 - def lngettext(self, msgid1, msgid2, n): - import warnings - warnings.warn('lngettext() is deprecated, use ngettext() instead', - DeprecationWarning, 2) - import locale - if self._fallback: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\blngettext\b.*', - DeprecationWarning) - return self._fallback.lngettext(msgid1, msgid2, n) - if n == 1: - tmsg = msgid1 - else: - tmsg = msgid2 - if self._output_charset: - return tmsg.encode(self._output_charset) - return tmsg.encode(locale.getpreferredencoding()) - def pgettext(self, context, message): if self._fallback: return self._fallback.pgettext(context, message) @@ -333,24 +299,11 @@ class NullTranslations: def charset(self): return self._charset - def output_charset(self): - import warnings - warnings.warn('output_charset() is deprecated', - DeprecationWarning, 2) - return self._output_charset - - def set_output_charset(self, charset): - import warnings - warnings.warn('set_output_charset() is deprecated', - DeprecationWarning, 2) - self._output_charset = charset - def install(self, names=None): import builtins builtins.__dict__['_'] = self.gettext if names is not None: - allowed = {'gettext', 'lgettext', 'lngettext', - 'ngettext', 'npgettext', 'pgettext'} + allowed = {'gettext', 'ngettext', 'npgettext', 'pgettext'} for name in allowed & set(names): builtins.__dict__[name] = getattr(self, name) @@ -460,39 +413,6 @@ class GNUTranslations(NullTranslations): masteridx += 8 transidx += 8 - def lgettext(self, message): - import warnings - warnings.warn('lgettext() is deprecated, use gettext() instead', - DeprecationWarning, 2) - import locale - missing = object() - tmsg = self._catalog.get(message, missing) - if tmsg is missing: - if self._fallback: - return self._fallback.lgettext(message) - tmsg = message - if self._output_charset: - return tmsg.encode(self._output_charset) - return tmsg.encode(locale.getpreferredencoding()) - - def lngettext(self, msgid1, msgid2, n): - import warnings - warnings.warn('lngettext() is deprecated, use ngettext() instead', - DeprecationWarning, 2) - import locale - try: - tmsg = self._catalog[(msgid1, self.plural(n))] - except KeyError: - if self._fallback: - return self._fallback.lngettext(msgid1, msgid2, n) - if n == 1: - tmsg = msgid1 - else: - tmsg = msgid2 - if self._output_charset: - return tmsg.encode(self._output_charset) - return tmsg.encode(locale.getpreferredencoding()) - def gettext(self, message): missing = object() tmsg = self._catalog.get(message, missing) @@ -581,7 +501,7 @@ _translations = {} _unspecified = ['unspecified'] def translation(domain, localedir=None, languages=None, - class_=None, fallback=False, codeset=_unspecified): + class_=None, fallback=False): if class_ is None: class_ = GNUTranslations mofiles = find(domain, localedir, languages, all=True) @@ -607,15 +527,6 @@ def translation(domain, localedir=None, languages=None, # are not used. import copy t = copy.copy(t) - if codeset is not _unspecified: - import warnings - warnings.warn('parameter codeset is deprecated', - DeprecationWarning, 2) - if codeset: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\bset_output_charset\b.*', - DeprecationWarning) - t.set_output_charset(codeset) if result is None: result = t else: @@ -623,8 +534,8 @@ def translation(domain, localedir=None, languages=None, return result -def install(domain, localedir=None, codeset=_unspecified, names=None): - t = translation(domain, localedir, fallback=True, codeset=codeset) +def install(domain, localedir=None, names=None): + t = translation(domain, localedir, fallback=True) t.install(names) @@ -651,16 +562,6 @@ def bindtextdomain(domain, localedir=None): return _localedirs.get(domain, _default_localedir) -def bind_textdomain_codeset(domain, codeset=None): - import warnings - warnings.warn('bind_textdomain_codeset() is deprecated', - DeprecationWarning, 2) - global _localecodesets - if codeset is not None: - _localecodesets[domain] = codeset - return _localecodesets.get(domain) - - def dgettext(domain, message): try: t = translation(domain, _localedirs.get(domain, None)) @@ -668,23 +569,6 @@ def dgettext(domain, message): return message return t.gettext(message) -def ldgettext(domain, message): - import warnings - warnings.warn('ldgettext() is deprecated, use dgettext() instead', - DeprecationWarning, 2) - import locale - codeset = _localecodesets.get(domain) - try: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*', - DeprecationWarning) - t = translation(domain, _localedirs.get(domain, None), codeset=codeset) - except OSError: - return message.encode(codeset or locale.getpreferredencoding()) - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\blgettext\b.*', - DeprecationWarning) - return t.lgettext(message) def dngettext(domain, msgid1, msgid2, n): try: @@ -696,28 +580,6 @@ def dngettext(domain, msgid1, msgid2, n): return msgid2 return t.ngettext(msgid1, msgid2, n) -def ldngettext(domain, msgid1, msgid2, n): - import warnings - warnings.warn('ldngettext() is deprecated, use dngettext() instead', - DeprecationWarning, 2) - import locale - codeset = _localecodesets.get(domain) - try: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*', - DeprecationWarning) - t = translation(domain, _localedirs.get(domain, None), codeset=codeset) - except OSError: - if n == 1: - tmsg = msgid1 - else: - tmsg = msgid2 - return tmsg.encode(codeset or locale.getpreferredencoding()) - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\blngettext\b.*', - DeprecationWarning) - return t.lngettext(msgid1, msgid2, n) - def dpgettext(domain, context, message): try: @@ -741,27 +603,10 @@ def dnpgettext(domain, context, msgid1, msgid2, n): def gettext(message): return dgettext(_current_domain, message) -def lgettext(message): - import warnings - warnings.warn('lgettext() is deprecated, use gettext() instead', - DeprecationWarning, 2) - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\bldgettext\b.*', - DeprecationWarning) - return ldgettext(_current_domain, message) def ngettext(msgid1, msgid2, n): return dngettext(_current_domain, msgid1, msgid2, n) -def lngettext(msgid1, msgid2, n): - import warnings - warnings.warn('lngettext() is deprecated, use ngettext() instead', - DeprecationWarning, 2) - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', r'.*\bldngettext\b.*', - DeprecationWarning) - return ldngettext(_current_domain, msgid1, msgid2, n) - def pgettext(context, message): return dpgettext(_current_domain, context, message) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index baf300b0572..91b5e687fed 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -214,12 +214,10 @@ trggrkg zrffntr pngnybt yvoenel.''') eq(_('mullusk'), 'bacon') # Test installation of other methods import builtins - t.install(names=["gettext", "lgettext"]) + t.install(names=["gettext"]) eq(_, t.gettext) eq(builtins.gettext, t.gettext) - eq(lgettext, t.lgettext) del builtins.gettext - del builtins.lgettext class GettextTestCase2(GettextBaseTest): @@ -501,180 +499,6 @@ class PluralFormsTestCase(GettextBaseTest): self.assertRaises(TypeError, f, object()) -class LGettextTestCase(GettextBaseTest): - def setUp(self): - GettextBaseTest.setUp(self) - self.mofile = MOFILE - - @contextlib.contextmanager - def assertDeprecated(self, name): - with self.assertWarnsRegex(DeprecationWarning, - fr'^{name}\(\) is deprecated'): - yield - - def test_lgettext(self): - lgettext = gettext.lgettext - ldgettext = gettext.ldgettext - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('mullusk'), b'bacon') - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('spam'), b'spam') - with self.assertDeprecated('ldgettext'): - self.assertEqual(ldgettext('gettext', 'mullusk'), b'bacon') - with self.assertDeprecated('ldgettext'): - self.assertEqual(ldgettext('gettext', 'spam'), b'spam') - - def test_lgettext_2(self): - with open(self.mofile, 'rb') as fp: - t = gettext.GNUTranslations(fp) - lgettext = t.lgettext - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('mullusk'), b'bacon') - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('spam'), b'spam') - - def test_lgettext_bind_textdomain_codeset(self): - lgettext = gettext.lgettext - ldgettext = gettext.ldgettext - with self.assertDeprecated('bind_textdomain_codeset'): - saved_codeset = gettext.bind_textdomain_codeset('gettext') - try: - with self.assertDeprecated('bind_textdomain_codeset'): - gettext.bind_textdomain_codeset('gettext', 'utf-16') - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('mullusk'), 'bacon'.encode('utf-16')) - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('spam'), 'spam'.encode('utf-16')) - with self.assertDeprecated('ldgettext'): - self.assertEqual(ldgettext('gettext', 'mullusk'), 'bacon'.encode('utf-16')) - with self.assertDeprecated('ldgettext'): - self.assertEqual(ldgettext('gettext', 'spam'), 'spam'.encode('utf-16')) - finally: - del gettext._localecodesets['gettext'] - with self.assertDeprecated('bind_textdomain_codeset'): - gettext.bind_textdomain_codeset('gettext', saved_codeset) - - def test_lgettext_output_encoding(self): - with open(self.mofile, 'rb') as fp: - t = gettext.GNUTranslations(fp) - lgettext = t.lgettext - with self.assertDeprecated('set_output_charset'): - t.set_output_charset('utf-16') - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('mullusk'), 'bacon'.encode('utf-16')) - with self.assertDeprecated('lgettext'): - self.assertEqual(lgettext('spam'), 'spam'.encode('utf-16')) - - def test_lngettext(self): - lngettext = gettext.lngettext - ldngettext = gettext.ldngettext - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 1) - self.assertEqual(x, b'Hay %s fichero') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 2) - self.assertEqual(x, b'Hay %s ficheros') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 1) - self.assertEqual(x, b'There is %s directory') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 2) - self.assertEqual(x, b'There are %s directories') - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s file', 'There are %s files', 1) - self.assertEqual(x, b'Hay %s fichero') - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s file', 'There are %s files', 2) - self.assertEqual(x, b'Hay %s ficheros') - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 1) - self.assertEqual(x, b'There is %s directory') - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 2) - self.assertEqual(x, b'There are %s directories') - - def test_lngettext_2(self): - with open(self.mofile, 'rb') as fp: - t = gettext.GNUTranslations(fp) - lngettext = t.lngettext - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 1) - self.assertEqual(x, b'Hay %s fichero') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 2) - self.assertEqual(x, b'Hay %s ficheros') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 1) - self.assertEqual(x, b'There is %s directory') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 2) - self.assertEqual(x, b'There are %s directories') - - def test_lngettext_bind_textdomain_codeset(self): - lngettext = gettext.lngettext - ldngettext = gettext.ldngettext - with self.assertDeprecated('bind_textdomain_codeset'): - saved_codeset = gettext.bind_textdomain_codeset('gettext') - try: - with self.assertDeprecated('bind_textdomain_codeset'): - gettext.bind_textdomain_codeset('gettext', 'utf-16') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 1) - self.assertEqual(x, 'Hay %s fichero'.encode('utf-16')) - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 2) - self.assertEqual(x, 'Hay %s ficheros'.encode('utf-16')) - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 1) - self.assertEqual(x, 'There is %s directory'.encode('utf-16')) - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 2) - self.assertEqual(x, 'There are %s directories'.encode('utf-16')) - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s file', 'There are %s files', 1) - self.assertEqual(x, 'Hay %s fichero'.encode('utf-16')) - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s file', 'There are %s files', 2) - self.assertEqual(x, 'Hay %s ficheros'.encode('utf-16')) - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 1) - self.assertEqual(x, 'There is %s directory'.encode('utf-16')) - with self.assertDeprecated('ldngettext'): - x = ldngettext('gettext', 'There is %s directory', 'There are %s directories', 2) - self.assertEqual(x, 'There are %s directories'.encode('utf-16')) - finally: - del gettext._localecodesets['gettext'] - with self.assertDeprecated('bind_textdomain_codeset'): - gettext.bind_textdomain_codeset('gettext', saved_codeset) - - def test_lngettext_output_encoding(self): - with open(self.mofile, 'rb') as fp: - t = gettext.GNUTranslations(fp) - lngettext = t.lngettext - with self.assertDeprecated('set_output_charset'): - t.set_output_charset('utf-16') - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 1) - self.assertEqual(x, 'Hay %s fichero'.encode('utf-16')) - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s file', 'There are %s files', 2) - self.assertEqual(x, 'Hay %s ficheros'.encode('utf-16')) - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 1) - self.assertEqual(x, 'There is %s directory'.encode('utf-16')) - with self.assertDeprecated('lngettext'): - x = lngettext('There is %s directory', 'There are %s directories', 2) - self.assertEqual(x, 'There are %s directories'.encode('utf-16')) - - def test_output_encoding(self): - with open(self.mofile, 'rb') as fp: - t = gettext.GNUTranslations(fp) - with self.assertDeprecated('set_output_charset'): - t.set_output_charset('utf-16') - with self.assertDeprecated('output_charset'): - self.assertEqual(t.output_charset(), 'utf-16') - - class GNUTranslationParsingTest(GettextBaseTest): def test_plural_form_error_issue17898(self): with open(MOFILE, 'wb') as fp: @@ -806,16 +630,6 @@ class GettextCacheTestCase(GettextBaseTest): self.assertEqual(len(gettext._translations), 2) self.assertEqual(t.__class__, DummyGNUTranslations) - # Test deprecated parameter codeset - with self.assertWarnsRegex(DeprecationWarning, 'parameter codeset'): - t = gettext.translation('gettext', self.localedir, - class_=DummyGNUTranslations, - codeset='utf-16') - self.assertEqual(len(gettext._translations), 2) - self.assertEqual(t.__class__, DummyGNUTranslations) - with self.assertWarns(DeprecationWarning): - self.assertEqual(t.output_charset(), 'utf-16') - class MiscTestCase(unittest.TestCase): def test__all__(self): diff --git a/Misc/NEWS.d/next/Library/2020-06-10-11-17-54.bpo-40936.KiwzdI.rst b/Misc/NEWS.d/next/Library/2020-06-10-11-17-54.bpo-40936.KiwzdI.rst new file mode 100644 index 00000000000..cb81bd99d29 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-06-10-11-17-54.bpo-40936.KiwzdI.rst @@ -0,0 +1,6 @@ +:func:`gettext.bind_textdomain_codeset`, :func:`gettext.lgettext`, +:func:`gettext.ldgettext`, :func:`gettext.lngettext`, +:func:`gettext.ldngettext`, :meth:`gettext.NullTranslations.output_charset` +and :meth:`gettext.NullTranslations.set_output_charset` have been removed. +The codeset parameter in :func:`gettext.translation` and +:func:`gettext.install` has been removed. Patch contributed by RĂ©mi Lapeyre.