Skip to content

Commit 55e4980

Browse files
authored
bpo-35336: Fix PYTHONCOERCECLOCALE=1 (GH-10806)
Fix PYTHONCOERCECLOCALE=1 environment variable: only coerce the C locale if the LC_CTYPE locale is "C".
1 parent a407004 commit 55e4980

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
from test import 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 support.is_android:
@@ -413,6 +416,27 @@ def test_LC_ALL_set_to_C(self):
413416
expected_warnings=[LEGACY_LOCALE_WARNING],
414417
coercion_expected=False)
415418

419+
def test_PYTHONCOERCECLOCALE_set_to_one(self):
420+
# skip the test if the LC_CTYPE locale is C or coerced
421+
old_loc = locale.setlocale(locale.LC_CTYPE, None)
422+
self.addCleanup(locale.setlocale, locale.LC_CTYPE, old_loc)
423+
loc = locale.setlocale(locale.LC_CTYPE, "")
424+
if loc == "C":
425+
self.skipTest("test requires LC_CTYPE locale different than C")
426+
if loc in TARGET_LOCALES :
427+
self.skipTest("coerced LC_CTYPE locale: %s" % loc)
428+
429+
# bpo-35336: PYTHONCOERCECLOCALE=1 must not coerce the LC_CTYPE locale
430+
# if it's not equal to "C"
431+
code = 'import locale; print(locale.setlocale(locale.LC_CTYPE, None))'
432+
env = dict(os.environ, PYTHONCOERCECLOCALE='1')
433+
cmd = subprocess.run([sys.executable, '-c', code],
434+
stdout=subprocess.PIPE,
435+
env=env,
436+
text=True)
437+
self.assertEqual(cmd.stdout.rstrip(), loc)
438+
439+
416440
def test_main():
417441
support.run_unittest(
418442
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".

Python/coreconfig.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,11 +1061,17 @@ config_read_complex_options(_PyCoreConfig *config)
10611061
static void
10621062
config_init_locale(_PyCoreConfig *config)
10631063
{
1064-
if (config->coerce_c_locale < 0) {
1064+
/* Test also if coerce_c_locale equals 1: PYTHONCOERCECLOCALE=1 doesn't
1065+
imply that the C locale is always coerced. It is only coerced if
1066+
if the LC_CTYPE locale is "C". */
1067+
if (config->coerce_c_locale != 0) {
10651068
/* The C locale enables the C locale coercion (PEP 538) */
10661069
if (_Py_LegacyLocaleDetected()) {
10671070
config->coerce_c_locale = 1;
10681071
}
1072+
else {
1073+
config->coerce_c_locale = 0;
1074+
}
10691075
}
10701076

10711077
#ifndef MS_WINDOWS
@@ -1394,7 +1400,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
13941400
}
13951401
}
13961402

1397-
if (config->utf8_mode < 0 || config->coerce_c_locale < 0) {
1403+
if (config->coerce_c_locale != 0 || config->utf8_mode < 0) {
13981404
config_init_locale(config);
13991405
}
14001406

0 commit comments

Comments
 (0)