Skip to content

Commit

Permalink
pythongh-104783: Remove locale.getdefaultlocale()
Browse files Browse the repository at this point in the history
Remove locale.getdefaultlocale() and locale.resetlocale() functions.

locale.getencoding() now uses sys.getfilesystemencoding() if
_locale.getencoding() is missing.
  • Loading branch information
gpshead authored and vstinner committed May 23, 2023
1 parent 2e5d8a9 commit 099fbf5
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 180 deletions.
35 changes: 0 additions & 35 deletions Doc/library/locale.rst
Expand Up @@ -281,31 +281,6 @@ The :mod:`locale` module defines the following exception and functions:
0 to 99.


.. function:: getdefaultlocale([envvars])

Tries to determine the default locale settings and returns them as a tuple of
the form ``(language code, encoding)``.

According to POSIX, a program which has not called ``setlocale(LC_ALL, '')``
runs using the portable ``'C'`` locale. Calling ``setlocale(LC_ALL, '')`` lets
it use the default locale as defined by the :envvar:`LANG` variable. Since we
do not want to interfere with the current locale setting we thus emulate the
behavior in the way described above.

To maintain compatibility with other platforms, not only the :envvar:`LANG`
variable is tested, but a list of variables given as envvars parameter. The
first found to be defined will be used. *envvars* defaults to the search
path used in GNU gettext; it must always contain the variable name
``'LANG'``. The GNU gettext search path contains ``'LC_ALL'``,
``'LC_CTYPE'``, ``'LANG'`` and ``'LANGUAGE'``, in that order.

Except for the code ``'C'``, the language code corresponds to :rfc:`1766`.
*language code* and *encoding* may be ``None`` if their values cannot be
determined.

.. deprecated-removed:: 3.11 3.13


.. function:: getlocale(category=LC_CTYPE)

Returns the current setting for the given locale category as sequence containing
Expand Down Expand Up @@ -370,16 +345,6 @@ The :mod:`locale` module defines the following exception and functions:
encoding for the locale code just like :func:`setlocale`.


.. function:: resetlocale(category=LC_ALL)

Sets the locale for *category* to the default setting.

The default setting is determined by calling :func:`getdefaultlocale`.
*category* defaults to :const:`LC_ALL`.

.. deprecated-removed:: 3.11 3.13


.. function:: strcoll(string1, string2)

Compares two strings according to the current :const:`LC_COLLATE` setting. As
Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.13.rst
Expand Up @@ -102,6 +102,14 @@ Deprecated
Removed
=======

* Remove two :mod:`locale` functions deprecated in Python 3.11:

* ``getdefaultlocale()``: use :func:`locale.setlocale`,
:func:`locale.getpreferredencoding(False) <locale.getpreferredencoding>`
and :func:`locale.getlocale` functions instead.
* ``resetlocale()``: use ``locale.setlocale(locale.LC_ALL, "")`` instead.

(Contributed by Victor Stinner in :gh:`104783`.)


Porting to Python 3.13
Expand Down
116 changes: 6 additions & 110 deletions Lib/locale.py
Expand Up @@ -24,8 +24,8 @@

# Yuck: LC_MESSAGES is non-standard: can't tell whether it exists before
# trying the import. So __all__ is also fiddled at the end of the file.
__all__ = ["getlocale", "getdefaultlocale", "getpreferredencoding", "Error",
"setlocale", "resetlocale", "localeconv", "strcoll", "strxfrm",
__all__ = ["getlocale", "getpreferredencoding", "Error",
"setlocale", "localeconv", "strcoll", "strxfrm",
"str", "atof", "atoi", "format_string", "currency",
"normalize", "LC_CTYPE", "LC_COLLATE", "LC_TIME", "LC_MONETARY",
"LC_NUMERIC", "LC_ALL", "CHAR_MAX", "getencoding"]
Expand Down Expand Up @@ -516,67 +516,6 @@ def _build_localename(localetuple):
raise TypeError('Locale must be None, a string, or an iterable of '
'two strings -- language code, encoding.') from None

def getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')):

""" Tries to determine the default locale settings and returns
them as tuple (language code, encoding).
According to POSIX, a program which has not called
setlocale(LC_ALL, "") runs using the portable 'C' locale.
Calling setlocale(LC_ALL, "") lets it use the default locale as
defined by the LANG variable. Since we don't want to interfere
with the current locale setting we thus emulate the behavior
in the way described above.
To maintain compatibility with other platforms, not only the
LANG variable is tested, but a list of variables given as
envvars parameter. The first found to be defined will be
used. envvars defaults to the search path used in GNU gettext;
it must always contain the variable name 'LANG'.
Except for the code 'C', the language code corresponds to RFC
1766. code and encoding can be None in case the values cannot
be determined.
"""

import warnings
warnings.warn(
"Use setlocale(), getencoding() and getlocale() instead",
DeprecationWarning, stacklevel=2
)
return _getdefaultlocale(envvars)

def _getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')):
try:
# check if it's supported by the _locale module
import _locale
code, encoding = _locale._getdefaultlocale()
except (ImportError, AttributeError):
pass
else:
# make sure the code/encoding values are valid
if sys.platform == "win32" and code and code[:2] == "0x":
# map windows language identifier to language name
code = windows_locale.get(int(code, 0))
# ...add other platform-specific processing here, if
# necessary...
return code, encoding

# fall back on POSIX behaviour
import os
lookup = os.environ.get
for variable in envvars:
localename = lookup(variable,None)
if localename:
if variable == 'LANGUAGE':
localename = localename.split(':')[0]
break
else:
localename = 'C'
return _parse_localename(localename)


def getlocale(category=LC_CTYPE):

""" Returns the current setting for the given locale category as
Expand Down Expand Up @@ -612,40 +551,15 @@ def setlocale(category, locale=None):
locale = normalize(_build_localename(locale))
return _setlocale(category, locale)

def resetlocale(category=LC_ALL):

""" Sets the locale for category to the default setting.
The default setting is determined by calling
getdefaultlocale(). category defaults to LC_ALL.
"""
import warnings
warnings.warn(
'Use locale.setlocale(locale.LC_ALL, "") instead',
DeprecationWarning, stacklevel=2
)

with warnings.catch_warnings():
warnings.simplefilter('ignore', category=DeprecationWarning)
loc = getdefaultlocale()

_setlocale(category, _build_localename(loc))


try:
from _locale import getencoding
except ImportError:
# When _locale.getencoding() is missing, use the Python filesystem
# encoding.
_encoding = sys.getfilesystemencoding()
def getencoding():
if hasattr(sys, 'getandroidapilevel'):
# On Android langinfo.h and CODESET are missing, and UTF-8 is
# always used in mbstowcs() and wcstombs().
return 'utf-8'
encoding = _getdefaultlocale()[1]
if encoding is None:
# LANG not set, default to UTF-8
encoding = 'utf-8'
return encoding
return _encoding

try:
CODESET
Expand Down Expand Up @@ -1713,13 +1627,6 @@ def _init_categories(categories=categories):
_init_categories()
del categories['LC_ALL']

print('Locale defaults as determined by getdefaultlocale():')
print('-'*72)
lang, enc = getdefaultlocale()
print('Language: ', lang or '(undefined)')
print('Encoding: ', enc or '(undefined)')
print()

print('Locale settings on startup:')
print('-'*72)
for name,category in categories.items():
Expand All @@ -1729,17 +1636,6 @@ def _init_categories(categories=categories):
print(' Encoding: ', enc or '(undefined)')
print()

print()
print('Locale settings after calling resetlocale():')
print('-'*72)
resetlocale()
for name,category in categories.items():
print(name, '...')
lang, enc = getlocale(category)
print(' Language: ', lang or '(undefined)')
print(' Encoding: ', enc or '(undefined)')
print()

try:
setlocale(LC_ALL, "")
except:
Expand Down
36 changes: 1 addition & 35 deletions Lib/test/test_locale.py
Expand Up @@ -478,43 +478,9 @@ def test_japanese(self):


class TestMiscellaneous(unittest.TestCase):
def test_defaults_UTF8(self):
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
# valid. Furthermore LC_CTYPE=UTF is used by the UTF-8 locale coercing
# during interpreter startup (on macOS).
import _locale
import os

def test_parse_localename(self):
self.assertEqual(locale._parse_localename('UTF-8'), (None, 'UTF-8'))

if hasattr(_locale, '_getdefaultlocale'):
orig_getlocale = _locale._getdefaultlocale
del _locale._getdefaultlocale
else:
orig_getlocale = None

orig_env = {}
try:
for key in ('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE'):
if key in os.environ:
orig_env[key] = os.environ[key]
del os.environ[key]

os.environ['LC_CTYPE'] = 'UTF-8'

with check_warnings(('', DeprecationWarning)):
self.assertEqual(locale.getdefaultlocale(), (None, 'UTF-8'))

finally:
for k in orig_env:
os.environ[k] = orig_env[k]

if 'LC_CTYPE' not in orig_env:
del os.environ['LC_CTYPE']

if orig_getlocale is not None:
_locale._getdefaultlocale = orig_getlocale

def test_getencoding(self):
# Invoke getencoding to make sure it does not cause exceptions.
enc = locale.getencoding()
Expand Down
@@ -0,0 +1,2 @@
Remove two :mod:`locale` functions deprecated in Python 3.11:
``getdefaultlocale()`` and ``resetlocale()``. Patch by Victor Stinner.

0 comments on commit 099fbf5

Please sign in to comment.