Skip to content

Commit b62bdf7

Browse files
authored
bpo-42208: Add _locale._get_locale_encoding() (GH-23052)
* Add a new _locale._get_locale_encoding() function to get the current locale encoding. * Modify locale.getpreferredencoding() to use it. * Remove the _bootlocale module.
1 parent 710e826 commit b62bdf7

File tree

6 files changed

+85
-102
lines changed

6 files changed

+85
-102
lines changed

Lib/_bootlocale.py

Lines changed: 0 additions & 46 deletions
This file was deleted.

Lib/locale.py

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -619,53 +619,49 @@ def resetlocale(category=LC_ALL):
619619
"""
620620
_setlocale(category, _build_localename(getdefaultlocale()))
621621

622-
if sys.platform.startswith("win"):
623-
# On Win32, this will return the ANSI code page
624-
def getpreferredencoding(do_setlocale = True):
625-
"""Return the charset that the user is likely using."""
622+
623+
try:
624+
from _locale import _get_locale_encoding
625+
except ImportError:
626+
def _get_locale_encoding():
627+
if hasattr(sys, 'getandroidapilevel'):
628+
# On Android langinfo.h and CODESET are missing, and UTF-8 is
629+
# always used in mbstowcs() and wcstombs().
630+
return 'UTF-8'
626631
if sys.flags.utf8_mode:
627632
return 'UTF-8'
628-
import _bootlocale
629-
return _bootlocale.getpreferredencoding(False)
633+
encoding = getdefaultlocale()[1]
634+
if encoding is None:
635+
# LANG not set, default conservatively to ASCII
636+
encoding = 'ascii'
637+
return encoding
638+
639+
try:
640+
CODESET
641+
except NameError:
642+
def getpreferredencoding(do_setlocale=True):
643+
"""Return the charset that the user is likely using."""
644+
return _get_locale_encoding()
630645
else:
631646
# On Unix, if CODESET is available, use that.
632-
try:
633-
CODESET
634-
except NameError:
635-
if hasattr(sys, 'getandroidapilevel'):
636-
# On Android langinfo.h and CODESET are missing, and UTF-8 is
637-
# always used in mbstowcs() and wcstombs().
638-
def getpreferredencoding(do_setlocale = True):
639-
return 'UTF-8'
640-
else:
641-
# Fall back to parsing environment variables :-(
642-
def getpreferredencoding(do_setlocale = True):
643-
"""Return the charset that the user is likely using,
644-
by looking at environment variables."""
645-
if sys.flags.utf8_mode:
646-
return 'UTF-8'
647-
res = getdefaultlocale()[1]
648-
if res is None:
649-
# LANG not set, default conservatively to ASCII
650-
res = 'ascii'
651-
return res
652-
else:
653-
def getpreferredencoding(do_setlocale = True):
654-
"""Return the charset that the user is likely using,
655-
according to the system configuration."""
656-
if sys.flags.utf8_mode:
657-
return 'UTF-8'
658-
import _bootlocale
659-
if do_setlocale:
660-
oldloc = setlocale(LC_CTYPE)
661-
try:
662-
setlocale(LC_CTYPE, "")
663-
except Error:
664-
pass
665-
result = _bootlocale.getpreferredencoding(False)
666-
if do_setlocale:
667-
setlocale(LC_CTYPE, oldloc)
668-
return result
647+
def getpreferredencoding(do_setlocale=True):
648+
"""Return the charset that the user is likely using,
649+
according to the system configuration."""
650+
if sys.flags.utf8_mode:
651+
return 'UTF-8'
652+
653+
if not do_setlocale:
654+
return _get_locale_encoding()
655+
656+
old_loc = setlocale(LC_CTYPE)
657+
try:
658+
try:
659+
setlocale(LC_CTYPE, "")
660+
except Error:
661+
pass
662+
return _get_locale_encoding()
663+
finally:
664+
setlocale(LC_CTYPE, old_loc)
669665

670666

671667
### Database

Lib/test/test_mimetypes.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import mimetypes
44
import pathlib
55
import sys
6-
import unittest
6+
import unittest.mock
77

88
from test import support
99
from test.support import os_helper
@@ -71,14 +71,14 @@ def test_read_mime_types(self):
7171
# bpo-41048: read_mime_types should read the rule file with 'utf-8' encoding.
7272
# Not with locale encoding. _bootlocale has been imported because io.open(...)
7373
# uses it.
74-
with os_helper.temp_dir() as directory:
75-
data = "application/no-mans-land Fran\u00E7ais"
76-
file = pathlib.Path(directory, "sample.mimetype")
77-
file.write_text(data, encoding='utf-8')
78-
import _bootlocale
79-
with support.swap_attr(_bootlocale, 'getpreferredencoding', lambda do_setlocale=True: 'ASCII'):
80-
mime_dict = mimetypes.read_mime_types(file)
81-
eq(mime_dict[".Français"], "application/no-mans-land")
74+
data = "application/no-mans-land Fran\u00E7ais"
75+
filename = "filename"
76+
fp = io.StringIO(data)
77+
with unittest.mock.patch.object(mimetypes, 'open',
78+
return_value=fp) as mock_open:
79+
mime_dict = mimetypes.read_mime_types(filename)
80+
mock_open.assert_called_with(filename, encoding='utf-8')
81+
eq(mime_dict[".Français"], "application/no-mans-land")
8282

8383
def test_non_standard_types(self):
8484
eq = self.assertEqual

Modules/_localemodule.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,9 +768,24 @@ _locale_bind_textdomain_codeset_impl(PyObject *module, const char *domain,
768768
}
769769
Py_RETURN_NONE;
770770
}
771-
#endif
771+
#endif // HAVE_BIND_TEXTDOMAIN_CODESET
772+
773+
#endif // HAVE_LIBINTL_H
774+
775+
776+
/*[clinic input]
777+
_locale._get_locale_encoding
778+
779+
Get the current locale encoding.
780+
[clinic start generated code]*/
781+
782+
static PyObject *
783+
_locale__get_locale_encoding_impl(PyObject *module)
784+
/*[clinic end generated code: output=e8e2f6f6f184591a input=513d9961d2f45c76]*/
785+
{
786+
return _Py_GetLocaleEncoding();
787+
}
772788

773-
#endif
774789

775790
static struct PyMethodDef PyLocale_Methods[] = {
776791
_LOCALE_SETLOCALE_METHODDEF
@@ -797,6 +812,7 @@ static struct PyMethodDef PyLocale_Methods[] = {
797812
_LOCALE_BIND_TEXTDOMAIN_CODESET_METHODDEF
798813
#endif
799814
#endif
815+
_LOCALE__GET_LOCALE_ENCODING_METHODDEF
800816
{NULL, NULL}
801817
};
802818

Modules/clinic/_localemodule.c.h

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PCbuild/lib.pyproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1572,7 +1572,6 @@
15721572
<Compile Include="zoneinfo\__init__.py" />
15731573
<Compile Include="zoneinfo\_tzpath.py" />
15741574
<Compile Include="zoneinfo\_zoneinfo.py" />
1575-
<Compile Include="_bootlocale.py" />
15761575
<Compile Include="_collections_abc.py" />
15771576
<Compile Include="_compat_pickle.py" />
15781577
<Compile Include="_compression.py" />

0 commit comments

Comments
 (0)