Skip to content

Commit df738d5

Browse files
authored
bpo-35336: Fix PYTHONCOERCECLOCALE=1 (GH-10806) (GH-10813)
Fix PYTHONCOERCECLOCALE=1 environment variable: only coerce the C locale if the LC_CTYPE locale is "C". (cherry picked from commit 55e4980)
1 parent 0df1f45 commit df738d5

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

Lib/test/test_c_locale_coercion.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Tests the attempted automatic coercion of the C locale to a UTF-8 locale
22

3-
import unittest
43
import locale
54
import os
5+
import shutil
6+
import subprocess
67
import sys
78
import sysconfig
8-
import shutil
9+
import unittest
910
from collections import namedtuple
1011

1112
import test.support
@@ -25,6 +26,8 @@
2526
# Set our expectation for the default locale used when none is specified
2627
EXPECT_COERCION_IN_DEFAULT_LOCALE = True
2728

29+
TARGET_LOCALES = ["C.UTF-8", "C.utf8", "UTF-8"]
30+
2831
# Apply some platform dependent overrides
2932
if sys.platform.startswith("linux"):
3033
if test.support.is_android:
@@ -404,6 +407,27 @@ def test_LC_ALL_set_to_C(self):
404407
expected_warnings=[LEGACY_LOCALE_WARNING],
405408
coercion_expected=False)
406409

410+
def test_PYTHONCOERCECLOCALE_set_to_one(self):
411+
# skip the test if the LC_CTYPE locale is C or coerced
412+
old_loc = locale.setlocale(locale.LC_CTYPE, None)
413+
self.addCleanup(locale.setlocale, locale.LC_CTYPE, old_loc)
414+
loc = locale.setlocale(locale.LC_CTYPE, "")
415+
if loc == "C":
416+
self.skipTest("test requires LC_CTYPE locale different than C")
417+
if loc in TARGET_LOCALES :
418+
self.skipTest("coerced LC_CTYPE locale: %s" % loc)
419+
420+
# bpo-35336: PYTHONCOERCECLOCALE=1 must not coerce the LC_CTYPE locale
421+
# if it's not equal to "C"
422+
code = 'import locale; print(locale.setlocale(locale.LC_CTYPE, None))'
423+
env = dict(os.environ, PYTHONCOERCECLOCALE='1')
424+
cmd = subprocess.run([sys.executable, '-c', code],
425+
stdout=subprocess.PIPE,
426+
env=env,
427+
text=True)
428+
self.assertEqual(cmd.stdout.rstrip(), loc)
429+
430+
407431
def test_main():
408432
test.support.run_unittest(
409433
LocaleConfigurationTests,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix PYTHONCOERCECLOCALE=1 environment variable: only coerce the C locale
2+
if the LC_CTYPE locale is "C".

Modules/main.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,11 +2191,17 @@ pymain_read_conf(_PyMain *pymain, _PyCoreConfig *config, _PyCmdline *cmdline)
21912191
static void
21922192
config_init_locale(_PyCoreConfig *config)
21932193
{
2194-
if (config->coerce_c_locale < 0) {
2194+
/* Test also if coerce_c_locale equals 1: PYTHONCOERCECLOCALE=1 doesn't
2195+
imply that the C locale is always coerced. It is only coerced if
2196+
if the LC_CTYPE locale is "C". */
2197+
if (config->coerce_c_locale != 0) {
21952198
/* The C locale enables the C locale coercion (PEP 538) */
21962199
if (_Py_LegacyLocaleDetected()) {
21972200
config->coerce_c_locale = 1;
21982201
}
2202+
else {
2203+
config->coerce_c_locale = 0;
2204+
}
21992205
}
22002206

22012207
#ifndef MS_WINDOWS
@@ -2376,7 +2382,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
23762382
}
23772383
}
23782384

2379-
if (config->utf8_mode < 0 || config->coerce_c_locale < 0) {
2385+
if (config->coerce_c_locale != 0 || config->utf8_mode < 0) {
23802386
config_init_locale(config);
23812387
}
23822388

0 commit comments

Comments
 (0)