diff --git a/Lib/test/test_c_locale_coercion.py b/Lib/test/test_c_locale_coercion.py index 1db293b9c37359..134f07a17ec139 100644 --- a/Lib/test/test_c_locale_coercion.py +++ b/Lib/test/test_c_locale_coercion.py @@ -1,11 +1,12 @@ # Tests the attempted automatic coercion of the C locale to a UTF-8 locale -import unittest import locale import os +import shutil +import subprocess import sys import sysconfig -import shutil +import unittest from collections import namedtuple import test.support @@ -25,6 +26,8 @@ # Set our expectation for the default locale used when none is specified EXPECT_COERCION_IN_DEFAULT_LOCALE = True +TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"] + # Apply some platform dependent overrides if sys.platform.startswith("linux"): if test.support.is_android: @@ -404,6 +407,27 @@ def test_LC_ALL_set_to_C(self): expected_warnings=[LEGACY_LOCALE_WARNING], coercion_expected=False) + def test_PYTHONCOERCECLOCALE_set_to_one(self): + # skip the test if the LC_CTYPE locale is C or coerced + old_loc = locale.setlocale(locale.LC_CTYPE, None) + self.addCleanup(locale.setlocale, locale.LC_CTYPE, old_loc) + loc = locale.setlocale(locale.LC_CTYPE, "") + if loc == "C": + self.skipTest("test requires LC_CTYPE locale different than C") + if loc in TARGET_LOCALES : + self.skipTest("coerced LC_CTYPE locale: %s" % loc) + + # bpo-35336: PYTHONCOERCECLOCALE=1 must not coerce the LC_CTYPE locale + # if it's not equal to "C" + code = 'import locale; print(locale.setlocale(locale.LC_CTYPE, None))' + env = dict(os.environ, PYTHONCOERCECLOCALE='1') + cmd = subprocess.run([sys.executable, '-c', code], + stdout=subprocess.PIPE, + env=env, + text=True) + self.assertEqual(cmd.stdout.rstrip(), loc) + + def test_main(): test.support.run_unittest( LocaleConfigurationTests, diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-11-29-23-59-52.bpo-35336.8LOz4F.rst b/Misc/NEWS.d/next/Core and Builtins/2018-11-29-23-59-52.bpo-35336.8LOz4F.rst new file mode 100644 index 00000000000000..28f8f9bd4db761 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-11-29-23-59-52.bpo-35336.8LOz4F.rst @@ -0,0 +1,2 @@ +Fix PYTHONCOERCECLOCALE=1 environment variable: only coerce the C locale +if the LC_CTYPE locale is "C". diff --git a/Modules/main.c b/Modules/main.c index 6dbe6a30786b1d..af2c191b9b9b32 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -2191,11 +2191,17 @@ pymain_read_conf(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdline) static void config_init_locale(_PyCoreConfig *config) { - if (config->coerce_c_locale < 0) { + /* Test also if coerce_c_locale equals 1: PYTHONCOERCECLOCALE=1 doesn't + imply that the C locale is always coerced. It is only coerced if + if the LC_CTYPE locale is "C". */ + if (config->coerce_c_locale != 0) { /* The C locale enables the C locale coercion (PEP 538) */ if (_Py_LegacyLocaleDetected()) { config->coerce_c_locale = 1; } + else { + config->coerce_c_locale = 0; + } } #ifndef MS_WINDOWS @@ -2376,7 +2382,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config) } } - if (config->utf8_mode < 0 || config->coerce_c_locale < 0) { + if (config->coerce_c_locale != 0 || config->utf8_mode < 0) { config_init_locale(config); }