Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bcfbbd7

Browse files
authored
bpo-36945: Add _PyPreConfig.configure_locale (GH-13368)
_PyPreConfig_InitIsolatedConfig() sets configure_locale to 0 to prevent Python to modify the LC_CTYPE locale. In that case, coerce_c_locale an coerce_c_locale_warn are set to 0 as well.
1 parent 98ff4d5 commit bcfbbd7

4 files changed

Lines changed: 82 additions & 10 deletions

File tree

Include/cpython/coreconfig.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ typedef struct {
7979
set to !Py_IgnoreEnvironmentFlag. */
8080
int use_environment;
8181

82+
/* Set the LC_CTYPE locale to the user preferred locale? If equals to 0,
83+
set coerce_c_locale and coerce_c_locale_warn to 0. */
84+
int configure_locale;
85+
8286
/* Coerce the LC_CTYPE locale if it's equal to "C"? (PEP 538)
8387
8488
Set to 0 by PYTHONCOERCECLOCALE=0. Set to 1 by PYTHONCOERCECLOCALE=1.
@@ -147,6 +151,7 @@ typedef struct {
147151
._config_version = _Py_CONFIG_VERSION, \
148152
.isolated = -1, \
149153
.use_environment = -1, \
154+
.configure_locale = 1, \
150155
.utf8_mode = -2, \
151156
.dev_mode = -1, \
152157
.allocator = PYMEM_ALLOCATOR_NOT_SET}

Lib/test/test_embed.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,15 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
272272
maxDiff = 4096
273273
UTF8_MODE_ERRORS = ('surrogatepass' if MS_WINDOWS else 'surrogateescape')
274274

275-
# Mark config which should be get by get_default_config()
275+
# Marker to read the default configuration: get_default_config()
276276
GET_DEFAULT_CONFIG = object()
277+
278+
# Marker to ignore a configuration parameter
279+
IGNORE_CONFIG = object()
280+
277281
DEFAULT_PRE_CONFIG = {
278282
'allocator': PYMEM_ALLOCATOR_NOT_SET,
283+
'configure_locale': 1,
279284
'coerce_c_locale': 0,
280285
'coerce_c_locale_warn': 0,
281286
'utf8_mode': 0,
@@ -405,7 +410,7 @@ def main_xoptions(self, xoptions_list):
405410
xoptions[opt] = True
406411
return xoptions
407412

408-
def get_expected_config(self, expected, env, add_path=None):
413+
def get_expected_config(self, expected_preconfig, expected, env, add_path=None):
409414
expected = dict(self.DEFAULT_CORE_CONFIG, **expected)
410415

411416
code = textwrap.dedent('''
@@ -471,6 +476,14 @@ def get_expected_config(self, expected, env, add_path=None):
471476

472477
if add_path is not None:
473478
expected['module_search_paths'].append(add_path)
479+
480+
if not expected_preconfig['configure_locale']:
481+
# there is no easy way to get the locale encoding before
482+
# setlocale(LC_CTYPE, "") is called: don't test encodings
483+
for key in ('filesystem_encoding', 'filesystem_errors',
484+
'stdio_encoding', 'stdio_errors'):
485+
expected[key] = self.IGNORE_CONFIG
486+
474487
return expected
475488

476489
def check_pre_config(self, config, expected):
@@ -480,6 +493,10 @@ def check_pre_config(self, config, expected):
480493

481494
def check_core_config(self, config, expected):
482495
core_config = dict(config['core_config'])
496+
for key, value in list(expected.items()):
497+
if value is self.IGNORE_CONFIG:
498+
del core_config[key]
499+
del expected[key]
483500
self.assertEqual(core_config, expected)
484501

485502
def check_global_config(self, config):
@@ -517,7 +534,7 @@ def check_config(self, testname, expected_config, expected_preconfig,
517534
env['PYTHONUTF8'] = '0'
518535

519536
expected_preconfig = dict(self.DEFAULT_PRE_CONFIG, **expected_preconfig)
520-
expected_config = self.get_expected_config(expected_config, env, add_path)
537+
expected_config = self.get_expected_config(expected_preconfig, expected_config, env, add_path)
521538
for key in self.COPY_PRE_CONFIG:
522539
if key not in expected_preconfig:
523540
expected_preconfig[key] = expected_config[key]
@@ -692,7 +709,9 @@ def test_preinit_isolated2(self):
692709
self.check_config("preinit_isolated2", config, preconfig)
693710

694711
def test_init_isolated_config(self):
695-
preconfig = {}
712+
preconfig = {
713+
'configure_locale': 0,
714+
}
696715
config = {
697716
'isolated': 1,
698717
'use_environment': 0,
@@ -710,6 +729,13 @@ def test_init_python_config(self):
710729
}
711730
self.check_config("init_python_config", config, preconfig)
712731

732+
def test_init_dont_configure_locale(self):
733+
# _PyPreConfig.configure_locale=0
734+
preconfig = {
735+
'configure_locale': 0,
736+
}
737+
self.check_config("init_dont_configure_locale", {}, preconfig)
738+
713739
def test_init_read_set(self):
714740
preconfig = {}
715741
core_config = {

Programs/_testembed.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,33 @@ static int init_python_config(void)
788788
}
789789

790790

791+
static int init_dont_configure_locale(void)
792+
{
793+
_PyInitError err;
794+
795+
_PyPreConfig preconfig = _PyPreConfig_INIT;
796+
preconfig.configure_locale = 0;
797+
preconfig.coerce_c_locale = 1;
798+
preconfig.coerce_c_locale_warn = 1;
799+
800+
err = _Py_PreInitialize(&preconfig);
801+
if (_Py_INIT_FAILED(err)) {
802+
_Py_ExitInitError(err);
803+
}
804+
805+
_PyCoreConfig config = _PyCoreConfig_INIT;
806+
config.program_name = L"./_testembed";
807+
err = _Py_InitializeFromConfig(&config);
808+
if (_Py_INIT_FAILED(err)) {
809+
_Py_ExitInitError(err);
810+
}
811+
812+
dump_config();
813+
Py_Finalize();
814+
return 0;
815+
}
816+
817+
791818
static int init_dev_mode(void)
792819
{
793820
_PyCoreConfig config;
@@ -966,6 +993,7 @@ static struct TestCase TestCases[] = {
966993
{ "init_env", test_init_env },
967994
{ "init_env_dev_mode", test_init_env_dev_mode },
968995
{ "init_env_dev_mode_alloc", test_init_env_dev_mode_alloc },
996+
{ "init_dont_configure_locale", init_dont_configure_locale },
969997
{ "init_dev_mode", init_dev_mode },
970998
{ "init_isolated_flag", init_isolated_flag },
971999
{ "init_isolated_config", init_isolated_config },

Python/preconfig.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config)
286286
{
287287
_PyPreConfig_Init(config);
288288

289+
config->configure_locale = 0;
289290
config->isolated = 1;
290291
config->use_environment = 0;
291292
#ifdef MS_WINDOWS
@@ -312,6 +313,7 @@ _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2)
312313

313314
COPY_ATTR(isolated);
314315
COPY_ATTR(use_environment);
316+
COPY_ATTR(configure_locale);
315317
COPY_ATTR(dev_mode);
316318
COPY_ATTR(coerce_c_locale);
317319
COPY_ATTR(coerce_c_locale_warn);
@@ -360,6 +362,7 @@ _PyPreConfig_AsDict(const _PyPreConfig *config)
360362

361363
SET_ITEM_INT(isolated);
362364
SET_ITEM_INT(use_environment);
365+
SET_ITEM_INT(configure_locale);
363366
SET_ITEM_INT(coerce_c_locale);
364367
SET_ITEM_INT(coerce_c_locale_warn);
365368
SET_ITEM_INT(utf8_mode);
@@ -603,6 +606,12 @@ preconfig_init_utf8_mode(_PyPreConfig *config, const _PyPreCmdline *cmdline)
603606
static void
604607
preconfig_init_coerce_c_locale(_PyPreConfig *config)
605608
{
609+
if (!config->configure_locale) {
610+
config->coerce_c_locale = 0;
611+
config->coerce_c_locale_warn = 0;
612+
return;
613+
}
614+
606615
const char *env = _Py_GetEnv(config->use_environment, "PYTHONCOERCECLOCALE");
607616
if (env) {
608617
if (strcmp(env, "0") == 0) {
@@ -746,7 +755,9 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args)
746755
}
747756

748757
/* Set LC_CTYPE to the user preferred locale */
749-
_Py_SetLocaleFromEnv(LC_CTYPE);
758+
if (config->configure_locale) {
759+
_Py_SetLocaleFromEnv(LC_CTYPE);
760+
}
750761

751762
_PyPreCmdline cmdline = _PyPreCmdline_INIT;
752763
int init_utf8_mode = Py_UTF8Mode;
@@ -879,12 +890,14 @@ _PyPreConfig_Write(const _PyPreConfig *config)
879890

880891
_PyPreConfig_SetGlobalConfig(config);
881892

882-
if (config->coerce_c_locale) {
883-
_Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
884-
}
893+
if (config->configure_locale) {
894+
if (config->coerce_c_locale) {
895+
_Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
896+
}
885897

886-
/* Set LC_CTYPE to the user preferred locale */
887-
_Py_SetLocaleFromEnv(LC_CTYPE);
898+
/* Set LC_CTYPE to the user preferred locale */
899+
_Py_SetLocaleFromEnv(LC_CTYPE);
900+
}
888901

889902
/* Write the new pre-configuration into _PyRuntime */
890903
PyMemAllocatorEx old_alloc;

0 commit comments

Comments
 (0)