Skip to content

Commit 022be02

Browse files
authored
bpo-36763: Add _PyPreConfig._config_init (GH-13481)
* _PyPreConfig_GetGlobalConfig() and _PyCoreConfig_GetGlobalConfig() now do nothing if the configuration was not initialized with _PyPreConfig_InitCompatConfig() and _PyCoreConfig_InitCompatConfig() * Remove utf8_mode=-2 special case: use utf8_mode=-1 instead. * Fix _PyPreConfig_InitPythonConfig(): * isolated = 0 instead of -1 * use_environment = 1 instead of -1 * Rename _PyConfig_INIT to _PyConfig_INIT_COMPAT * Rename _PyPreConfig_Init() to _PyPreConfig_InitCompatConfig() * Rename _PyCoreConfig_Init() to _PyCoreConfig_InitCompatConfig() * PyInterpreterState_New() now uses _PyCoreConfig_InitPythonConfig() as default configuration, but it's very quickly overriden anyway. * _freeze_importlib.c uses _PyCoreConfig_SetString() to set program_name. * Cleanup preconfig_init_utf8_mode(): cmdline is always non-NULL.
1 parent e4d300e commit 022be02

File tree

11 files changed

+200
-108
lines changed

11 files changed

+200
-108
lines changed

Include/cpython/coreconfig.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,18 @@ typedef struct {
4040

4141
#define _Py_CONFIG_VERSION 1
4242

43+
typedef enum {
44+
/* Py_Initialize() API: backward compatibility with Python 3.6 and 3.7 */
45+
_PyConfig_INIT_COMPAT = 1,
46+
_PyConfig_INIT_PYTHON = 2,
47+
_PyConfig_INIT_ISOLATED = 3
48+
} _PyConfigInitEnum;
49+
50+
4351
typedef struct {
4452
int _config_version; /* Internal configuration version,
4553
used for ABI compatibility */
54+
int _config_init; /* _PyConfigInitEnum value */
4655

4756
/* Parse _Py_PreInitializeFromArgs() arguments?
4857
See _PyCoreConfig.parse_argv */
@@ -107,10 +116,7 @@ typedef struct {
107116
Set to 0 by "-X utf8=0" and PYTHONUTF8=0.
108117
109118
If equals to -1, it is set to 1 if the LC_CTYPE locale is "C" or
110-
"POSIX", otherwise it is set to 0.
111-
112-
If equals to -2, inherit Py_UTF8Mode value value (which is equal to 0
113-
by default). */
119+
"POSIX", otherwise it is set to 0. Inherit Py_UTF8Mode value value. */
114120
int utf8_mode;
115121

116122
int dev_mode; /* Development mode. PYTHONDEVMODE, -X dev */
@@ -126,16 +132,10 @@ PyAPI_FUNC(void) _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config);
126132

127133
/* --- _PyCoreConfig ---------------------------------------------- */
128134

129-
typedef enum {
130-
_PyCoreConfig_INIT = 0,
131-
_PyCoreConfig_INIT_PYTHON = 1,
132-
_PyCoreConfig_INIT_ISOLATED = 2
133-
} _PyCoreConfigInitEnum;
134-
135135
typedef struct {
136136
int _config_version; /* Internal configuration version,
137137
used for ABI compatibility */
138-
int _config_init; /* _PyCoreConfigInitEnum value */
138+
int _config_init; /* _PyConfigInitEnum value */
139139

140140
int isolated; /* Isolated mode? see _PyPreConfig.isolated */
141141
int use_environment; /* Use environment variables? see _PyPreConfig.use_environment */

Include/internal/pycore_coreconfig.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline,
120120

121121
/* --- _PyPreConfig ----------------------------------------------- */
122122

123-
PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config);
123+
PyAPI_FUNC(void) _PyPreConfig_InitCompatConfig(_PyPreConfig *config);
124124
PyAPI_FUNC(void) _PyPreConfig_InitFromCoreConfig(
125125
_PyPreConfig *config,
126126
const _PyCoreConfig *coreconfig);
@@ -139,7 +139,7 @@ PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config);
139139

140140
/* --- _PyCoreConfig ---------------------------------------------- */
141141

142-
PyAPI_FUNC(void) _PyCoreConfig_Init(_PyCoreConfig *config);
142+
PyAPI_FUNC(void) _PyCoreConfig_InitCompatConfig(_PyCoreConfig *config);
143143
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Copy(
144144
_PyCoreConfig *config,
145145
const _PyCoreConfig *config2);

Lib/test/test_embed.py

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,17 @@
1313

1414

1515
MS_WINDOWS = (os.name == 'nt')
16+
1617
PYMEM_ALLOCATOR_NOT_SET = 0
1718
PYMEM_ALLOCATOR_DEBUG = 2
1819
PYMEM_ALLOCATOR_MALLOC = 3
1920

20-
CONFIG_INIT = 0
21-
CONFIG_INIT_PYTHON = 1
22-
CONFIG_INIT_ISOLATED = 2
21+
# _PyCoreConfig_InitCompatConfig()
22+
API_COMPAT = 1
23+
# _PyCoreConfig_InitPythonConfig()
24+
API_PYTHON = 2
25+
# _PyCoreConfig_InitIsolatedConfig()
26+
API_ISOLATED = 3
2327

2428

2529
class EmbeddingTestsMixin:
@@ -282,7 +286,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
282286
# Marker to ignore a configuration parameter
283287
IGNORE_CONFIG = object()
284288

285-
DEFAULT_PRE_CONFIG = {
289+
PRE_CONFIG_COMPAT = {
286290
'allocator': PYMEM_ALLOCATOR_NOT_SET,
287291
'parse_argv': 0,
288292
'configure_locale': 1,
@@ -291,15 +295,15 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
291295
'utf8_mode': 0,
292296
}
293297
if MS_WINDOWS:
294-
DEFAULT_PRE_CONFIG.update({
298+
PRE_CONFIG_COMPAT.update({
295299
'legacy_windows_fs_encoding': 0,
296300
})
297-
PYTHON_PRE_CONFIG = dict(DEFAULT_PRE_CONFIG,
301+
PRE_CONFIG_PYTHON = dict(PRE_CONFIG_COMPAT,
298302
parse_argv=1,
299303
coerce_c_locale=GET_DEFAULT_CONFIG,
300304
utf8_mode=GET_DEFAULT_CONFIG,
301305
)
302-
ISOLATED_PRE_CONFIG = dict(DEFAULT_PRE_CONFIG,
306+
PRE_CONFIG_ISOLATED = dict(PRE_CONFIG_COMPAT,
303307
configure_locale=0,
304308
isolated=1,
305309
use_environment=0,
@@ -314,8 +318,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
314318
'use_environment',
315319
]
316320

317-
DEFAULT_CORE_CONFIG = {
318-
'_config_init': CONFIG_INIT,
321+
CORE_CONFIG_COMPAT = {
322+
'_config_init': API_COMPAT,
319323
'isolated': 0,
320324
'use_environment': 1,
321325
'dev_mode': 0,
@@ -379,15 +383,15 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
379383
'_init_main': 1,
380384
}
381385
if MS_WINDOWS:
382-
DEFAULT_CORE_CONFIG.update({
386+
CORE_CONFIG_COMPAT.update({
383387
'legacy_windows_stdio': 0,
384388
})
385389

386-
PYTHON_CORE_CONFIG = dict(DEFAULT_CORE_CONFIG,
390+
CORE_CONFIG_PYTHON = dict(CORE_CONFIG_COMPAT,
387391
configure_c_stdio=1,
388392
parse_argv=1,
389393
)
390-
ISOLATED_CORE_CONFIG = dict(DEFAULT_CORE_CONFIG,
394+
CORE_CONFIG_ISOLATED = dict(CORE_CONFIG_COMPAT,
391395
isolated=1,
392396
use_environment=0,
393397
user_site_directory=0,
@@ -399,7 +403,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
399403
pathconfig_warnings=0,
400404
)
401405
if MS_WINDOWS:
402-
ISOLATED_CORE_CONFIG['legacy_windows_stdio'] = 0
406+
CORE_CONFIG_ISOLATED['legacy_windows_stdio'] = 0
403407

404408
# global config
405409
DEFAULT_GLOBAL_CONFIG = {
@@ -492,7 +496,7 @@ def get_expected_config(self, expected_preconfig, expected, env, api,
492496
if value is self.GET_DEFAULT_CONFIG:
493497
expected_preconfig[key] = pre_config[key]
494498

495-
if not expected_preconfig['configure_locale'] or api == CONFIG_INIT:
499+
if not expected_preconfig['configure_locale'] or api == API_COMPAT:
496500
# there is no easy way to get the locale encoding before
497501
# setlocale(LC_CTYPE, "") is called: don't test encodings
498502
for key in ('filesystem_encoding', 'filesystem_errors',
@@ -579,32 +583,33 @@ def check_global_config(self, config):
579583

580584
self.assertEqual(config['global_config'], expected)
581585

582-
def check_config(self, testname, expected_config=None, expected_preconfig=None,
583-
add_path=None, stderr=None, api=CONFIG_INIT):
586+
def check_config(self, testname, expected_config=None,
587+
expected_preconfig=None, add_path=None, stderr=None,
588+
*, api):
584589
env = dict(os.environ)
585590
# Remove PYTHON* environment variables to get deterministic environment
586591
for key in list(env):
587592
if key.startswith('PYTHON'):
588593
del env[key]
589594

590-
if api == CONFIG_INIT_ISOLATED:
591-
default_preconfig = self.ISOLATED_PRE_CONFIG
592-
elif api == CONFIG_INIT_PYTHON:
593-
default_preconfig = self.PYTHON_PRE_CONFIG
595+
if api == API_ISOLATED:
596+
default_preconfig = self.PRE_CONFIG_ISOLATED
597+
elif api == API_PYTHON:
598+
default_preconfig = self.PRE_CONFIG_PYTHON
594599
else:
595-
default_preconfig = self.DEFAULT_PRE_CONFIG
600+
default_preconfig = self.PRE_CONFIG_COMPAT
596601
if expected_preconfig is None:
597602
expected_preconfig = {}
598603
expected_preconfig = dict(default_preconfig, **expected_preconfig)
599604
if expected_config is None:
600605
expected_config = {}
601606

602-
if api == CONFIG_INIT_PYTHON:
603-
default_config = self.PYTHON_CORE_CONFIG
604-
elif api == CONFIG_INIT_ISOLATED:
605-
default_config = self.ISOLATED_CORE_CONFIG
607+
if api == API_PYTHON:
608+
default_config = self.CORE_CONFIG_PYTHON
609+
elif api == API_ISOLATED:
610+
default_config = self.CORE_CONFIG_ISOLATED
606611
else:
607-
default_config = self.DEFAULT_CORE_CONFIG
612+
default_config = self.CORE_CONFIG_COMPAT
608613
expected_config = dict(default_config, **expected_config)
609614
expected_config['_config_init'] = api
610615

@@ -627,7 +632,13 @@ def check_config(self, testname, expected_config=None, expected_preconfig=None,
627632
self.check_global_config(config)
628633

629634
def test_init_default_config(self):
630-
self.check_config("init_default_config", {}, {})
635+
self.check_config("init_initialize_config", api=API_COMPAT)
636+
637+
def test_preinit_compat_config(self):
638+
self.check_config("preinit_compat_config", api=API_COMPAT)
639+
640+
def test_init_compat_config(self):
641+
self.check_config("init_compat_config", api=API_COMPAT)
631642

632643
def test_init_global_config(self):
633644
preconfig = {
@@ -649,7 +660,8 @@ def test_init_global_config(self):
649660
'user_site_directory': 0,
650661
'pathconfig_warnings': 0,
651662
}
652-
self.check_config("init_global_config", config, preconfig)
663+
self.check_config("init_global_config", config, preconfig,
664+
api=API_COMPAT)
653665

654666
def test_init_from_config(self):
655667
preconfig = {
@@ -693,11 +705,13 @@ def test_init_from_config(self):
693705
'check_hash_pycs_mode': 'always',
694706
'pathconfig_warnings': 0,
695707
}
696-
self.check_config("init_from_config", config, preconfig)
708+
self.check_config("init_from_config", config, preconfig,
709+
api=API_COMPAT)
697710

698711
def test_init_env(self):
699712
preconfig = {
700713
'allocator': PYMEM_ALLOCATOR_MALLOC,
714+
'utf8_mode': 1,
701715
}
702716
config = {
703717
'use_hash_seed': 1,
@@ -718,21 +732,24 @@ def test_init_env(self):
718732
'faulthandler': 1,
719733
'warnoptions': ['EnvVar'],
720734
}
721-
self.check_config("init_env", config, preconfig)
735+
self.check_config("init_env", config, preconfig,
736+
api=API_COMPAT)
722737

723738
def test_init_env_dev_mode(self):
724739
preconfig = dict(allocator=PYMEM_ALLOCATOR_DEBUG)
725740
config = dict(dev_mode=1,
726741
faulthandler=1,
727742
warnoptions=['default'])
728-
self.check_config("init_env_dev_mode", config, preconfig)
743+
self.check_config("init_env_dev_mode", config, preconfig,
744+
api=API_COMPAT)
729745

730746
def test_init_env_dev_mode_alloc(self):
731747
preconfig = dict(allocator=PYMEM_ALLOCATOR_MALLOC)
732748
config = dict(dev_mode=1,
733749
faulthandler=1,
734750
warnoptions=['default'])
735-
self.check_config("init_env_dev_mode_alloc", config, preconfig)
751+
self.check_config("init_env_dev_mode_alloc", config, preconfig,
752+
api=API_COMPAT)
736753

737754
def test_init_dev_mode(self):
738755
preconfig = {
@@ -744,7 +761,7 @@ def test_init_dev_mode(self):
744761
'warnoptions': ['default'],
745762
}
746763
self.check_config("init_dev_mode", config, preconfig,
747-
api=CONFIG_INIT_PYTHON)
764+
api=API_PYTHON)
748765

749766
def test_preinit_parse_argv(self):
750767
# Pre-initialize implicitly using argv: make sure that -X dev
@@ -761,7 +778,7 @@ def test_preinit_parse_argv(self):
761778
'xoptions': ['dev'],
762779
}
763780
self.check_config("preinit_parse_argv", config, preconfig,
764-
api=CONFIG_INIT_PYTHON)
781+
api=API_PYTHON)
765782

766783
def test_preinit_dont_parse_argv(self):
767784
# -X dev must be ignored by isolated preconfiguration
@@ -774,15 +791,15 @@ def test_preinit_dont_parse_argv(self):
774791
'isolated': 0,
775792
}
776793
self.check_config("preinit_dont_parse_argv", config, preconfig,
777-
api=CONFIG_INIT_ISOLATED)
794+
api=API_ISOLATED)
778795

779796
def test_init_isolated_flag(self):
780797
config = {
781798
'isolated': 1,
782799
'use_environment': 0,
783800
'user_site_directory': 0,
784801
}
785-
self.check_config("init_isolated_flag", config, api=CONFIG_INIT_PYTHON)
802+
self.check_config("init_isolated_flag", config, api=API_PYTHON)
786803

787804
def test_preinit_isolated1(self):
788805
# _PyPreConfig.isolated=1, _PyCoreConfig.isolated not set
@@ -791,7 +808,7 @@ def test_preinit_isolated1(self):
791808
'use_environment': 0,
792809
'user_site_directory': 0,
793810
}
794-
self.check_config("preinit_isolated1", config)
811+
self.check_config("preinit_isolated1", config, api=API_COMPAT)
795812

796813
def test_preinit_isolated2(self):
797814
# _PyPreConfig.isolated=0, _PyCoreConfig.isolated=1
@@ -800,16 +817,16 @@ def test_preinit_isolated2(self):
800817
'use_environment': 0,
801818
'user_site_directory': 0,
802819
}
803-
self.check_config("preinit_isolated2", config)
820+
self.check_config("preinit_isolated2", config, api=API_COMPAT)
804821

805822
def test_preinit_isolated_config(self):
806-
self.check_config("preinit_isolated_config", api=CONFIG_INIT_ISOLATED)
823+
self.check_config("preinit_isolated_config", api=API_ISOLATED)
807824

808825
def test_init_isolated_config(self):
809-
self.check_config("init_isolated_config", api=CONFIG_INIT_ISOLATED)
826+
self.check_config("init_isolated_config", api=API_ISOLATED)
810827

811828
def test_init_python_config(self):
812-
self.check_config("init_python_config", api=CONFIG_INIT_PYTHON)
829+
self.check_config("init_python_config", api=API_PYTHON)
813830

814831
def test_init_dont_configure_locale(self):
815832
# _PyPreConfig.configure_locale=0
@@ -818,15 +835,15 @@ def test_init_dont_configure_locale(self):
818835
'coerce_c_locale': 0,
819836
}
820837
self.check_config("init_dont_configure_locale", {}, preconfig,
821-
api=CONFIG_INIT_PYTHON)
838+
api=API_PYTHON)
822839

823840
def test_init_read_set(self):
824841
core_config = {
825842
'program_name': './init_read_set',
826843
'executable': 'my_executable',
827844
}
828845
self.check_config("init_read_set", core_config,
829-
api=CONFIG_INIT_PYTHON,
846+
api=API_PYTHON,
830847
add_path="init_read_set_path")
831848

832849
def test_init_run_main(self):
@@ -838,8 +855,7 @@ def test_init_run_main(self):
838855
'run_command': code + '\n',
839856
'parse_argv': 1,
840857
}
841-
self.check_config("init_run_main", core_config,
842-
api=CONFIG_INIT_PYTHON)
858+
self.check_config("init_run_main", core_config, api=API_PYTHON)
843859

844860
def test_init_main(self):
845861
code = ('import _testinternalcapi, json; '
@@ -852,7 +868,7 @@ def test_init_main(self):
852868
'_init_main': 0,
853869
}
854870
self.check_config("init_main", core_config,
855-
api=CONFIG_INIT_PYTHON,
871+
api=API_PYTHON,
856872
stderr="Run Python code before _Py_InitializeMain")
857873

858874
def test_init_parse_argv(self):
@@ -863,8 +879,7 @@ def test_init_parse_argv(self):
863879
'run_command': 'pass\n',
864880
'use_environment': 0,
865881
}
866-
self.check_config("init_parse_argv", core_config,
867-
api=CONFIG_INIT_PYTHON)
882+
self.check_config("init_parse_argv", core_config, api=API_PYTHON)
868883

869884
def test_init_dont_parse_argv(self):
870885
pre_config = {
@@ -876,7 +891,7 @@ def test_init_dont_parse_argv(self):
876891
'program_name': './argv0',
877892
}
878893
self.check_config("init_dont_parse_argv", core_config, pre_config,
879-
api=CONFIG_INIT_PYTHON)
894+
api=API_PYTHON)
880895

881896

882897
if __name__ == "__main__":

0 commit comments

Comments
 (0)