From cab5d0741ee6adf2ae9ff5aaafe06b75b4b5bca3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 17 May 2019 19:01:14 +0200 Subject: [PATCH] bpo-36763: Add _PyCoreConfig_InitPythonConfig() (GH-13388) Add new functions to get the Python interpreter behavior: * _PyPreConfig_InitPythonConfig() * _PyCoreConfig_InitPythonConfig() Add new functions to get an isolated configuration: * _PyPreConfig_InitIsolatedConfig() * _PyCoreConfig_InitIsolatedConfig() Replace _PyPreConfig_INIT and _PyCoreConfig_INIT with new functions _PyPreConfig_Init() and _PyCoreConfig_Init(). _PyCoreConfig: set configure_c_stdio and parse_argv to 0 by default to behave as Python 3.6 in the default configuration. _PyCoreConfig_Read() no longer sets coerce_c_locale_warn to 1 if it's equal to 0. coerce_c_locale_warn must now be set to -1 (ex: using _PyCoreConfig_InitPythonConfig()) to enable C locale coercion warning. Add unit tests for _PyCoreConfig_InitPythonConfig() and _PyCoreConfig_InitIsolatedConfig(). Changes: * Rename _PyCoreConfig_GetCoreConfig() to _PyPreConfig_GetCoreConfig() * Fix core_read_precmdline(): handle parse_argv=0 * Fix _Py_PreInitializeFromCoreConfig(): pass coreconfig.argv to _Py_PreInitializeFromPyArgv(), except if parse_argv=0 --- Include/cpython/coreconfig.h | 32 ++++-- Include/internal/pycore_coreconfig.h | 7 +- Lib/test/test_embed.py | 46 ++++++-- Modules/main.c | 19 ++-- Programs/_freeze_importlib.c | 3 +- Programs/_testembed.c | 151 ++++++++++++++++++++++----- Python/coreconfig.c | 79 ++++++++++++-- Python/frozenmain.c | 3 +- Python/pathconfig.c | 3 +- Python/preconfig.c | 78 ++++++++++---- Python/pylifecycle.c | 28 +++-- Python/pystate.c | 4 +- 12 files changed, 362 insertions(+), 91 deletions(-) diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h index dca41341dfe..7d561ceb3ee 100644 --- a/Include/cpython/coreconfig.h +++ b/Include/cpython/coreconfig.h @@ -86,12 +86,18 @@ typedef struct { If it is equal to 1, LC_CTYPE locale is read to decide it it should be coerced or not (ex: PYTHONCOERCECLOCALE=1). Internally, it is set to 2 - if the LC_CTYPE locale must be coerced. */ + if the LC_CTYPE locale must be coerced. + + Disable by default (set to 0). Set it to -1 to let Python decides if it + should be enabled or not. */ int coerce_c_locale; /* Emit a warning if the LC_CTYPE locale is coerced? - Disabled by default. Set to 1 by PYTHONCOERCECLOCALE=warn. */ + Set to 1 by PYTHONCOERCECLOCALE=warn. + + Disable by default (set to 0). Set it to -1 to let Python decides if it + should be enabled or not. */ int coerce_c_locale_warn; #ifdef MS_WINDOWS @@ -116,7 +122,10 @@ typedef struct { Set to 0 by "-X utf8=0" and PYTHONUTF8=0. If equals to -1, it is set to 1 if the LC_CTYPE locale is "C" or - "POSIX", otherwise inherit Py_UTF8Mode value. */ + "POSIX", otherwise it is set to 0. + + If equals to -2, inherit Py_UTF8Mode value value (which is equal to 0 + by default). */ int utf8_mode; int dev_mode; /* Development mode. PYTHONDEVMODE, -X dev */ @@ -138,9 +147,14 @@ typedef struct { ._config_version = _Py_CONFIG_VERSION, \ .isolated = -1, \ .use_environment = -1, \ + .utf8_mode = -2, \ .dev_mode = -1, \ .allocator = PYMEM_ALLOCATOR_NOT_SET} +PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config); +PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config); +PyAPI_FUNC(void) _PyPreConfig_InitIsolateConfig(_PyPreConfig *config); + /* --- _PyCoreConfig ---------------------------------------------- */ @@ -213,8 +227,8 @@ typedef struct { /* Command line arguments (sys.argv). - By default, Python command line arguments are parsed and then stripped - from argv. Set parse_argv to 0 to avoid that. + Set parse_argv to 1 to parse argv as Python command line arguments + and then strip Python arguments from argv. If argv is empty, an empty string is added to ensure that sys.argv always exists and is never empty. */ @@ -442,7 +456,7 @@ typedef struct { .faulthandler = -1, \ .tracemalloc = -1, \ .use_module_search_paths = 0, \ - .parse_argv = 1, \ + .parse_argv = 0, \ .site_import = -1, \ .bytes_warning = -1, \ .inspect = -1, \ @@ -453,7 +467,7 @@ typedef struct { .verbose = -1, \ .quiet = -1, \ .user_site_directory = -1, \ - .configure_c_stdio = 1, \ + .configure_c_stdio = 0, \ .buffered_stdio = -1, \ ._install_importlib = 1, \ .check_hash_pycs_mode = NULL, \ @@ -461,6 +475,10 @@ typedef struct { ._init_main = 1} /* Note: _PyCoreConfig_INIT sets other fields to 0/NULL */ +PyAPI_FUNC(void) _PyCoreConfig_Init(_PyCoreConfig *config); +PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config); +PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolateConfig(_PyCoreConfig *config); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h index ccb7948ef4d..e9c6d9fee81 100644 --- a/Include/internal/pycore_coreconfig.h +++ b/Include/internal/pycore_coreconfig.h @@ -88,10 +88,13 @@ PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline, /* --- _PyPreConfig ----------------------------------------------- */ +PyAPI_FUNC(void) _PyPreConfig_Init(_PyPreConfig *config); +PyAPI_FUNC(void) _PyPreConfig_InitPythonConfig(_PyPreConfig *config); +PyAPI_FUNC(void) _PyPreConfig_InitIsolatedConfig(_PyPreConfig *config); PyAPI_FUNC(int) _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2); PyAPI_FUNC(PyObject*) _PyPreConfig_AsDict(const _PyPreConfig *config); -PyAPI_FUNC(void) _PyCoreConfig_GetCoreConfig(_PyPreConfig *config, +PyAPI_FUNC(void) _PyPreConfig_GetCoreConfig(_PyPreConfig *config, const _PyCoreConfig *core_config); PyAPI_FUNC(_PyInitError) _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args); @@ -101,6 +104,8 @@ PyAPI_FUNC(_PyInitError) _PyPreConfig_Write(const _PyPreConfig *config); /* --- _PyCoreConfig ---------------------------------------------- */ PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *); +PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitPythonConfig(_PyCoreConfig *config); +PyAPI_FUNC(_PyInitError) _PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config); PyAPI_FUNC(_PyInitError) _PyCoreConfig_Copy( _PyCoreConfig *config, const _PyCoreConfig *config2); diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 92cc405859c..50badd8e585 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -307,7 +307,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'pycache_prefix': None, 'program_name': GET_DEFAULT_CONFIG, - 'parse_argv': 1, + 'parse_argv': 0, 'argv': [""], 'xoptions': [], @@ -333,7 +333,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'verbose': 0, 'quiet': 0, 'user_site_directory': 1, - 'configure_c_stdio': 1, + 'configure_c_stdio': 0, 'buffered_stdio': 1, 'stdio_encoding': GET_DEFAULT_CONFIG, @@ -588,6 +588,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'pycache_prefix': 'conf_pycache_prefix', 'program_name': './conf_program_name', 'argv': ['-c', 'arg2'], + 'parse_argv': 1, 'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'], 'warnoptions': ['error::ResourceWarning', 'default::BytesWarning'], 'run_command': 'pass\n', @@ -600,7 +601,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'write_bytecode': 0, 'verbose': 1, 'quiet': 1, - 'configure_c_stdio': 0, + 'configure_c_stdio': 1, 'buffered_stdio': 0, 'user_site_directory': 0, 'faulthandler': 1, @@ -661,14 +662,14 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): } self.check_config("init_dev_mode", config, preconfig) - def test_init_isolated(self): + def test_init_isolated_flag(self): preconfig = {} config = { 'isolated': 1, 'use_environment': 0, 'user_site_directory': 0, } - self.check_config("init_isolated", config, preconfig) + self.check_config("init_isolated_flag", config, preconfig) def test_preinit_isolated1(self): # _PyPreConfig.isolated=1, _PyCoreConfig.isolated not set @@ -690,6 +691,25 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): } self.check_config("preinit_isolated2", config, preconfig) + def test_init_isolated_config(self): + preconfig = {} + config = { + 'isolated': 1, + 'use_environment': 0, + 'user_site_directory': 0, + 'install_signal_handlers': 0, + 'pathconfig_warnings': 0, + } + self.check_config("init_isolated_config", config, preconfig) + + def test_init_python_config(self): + preconfig = {} + config = { + 'configure_c_stdio': 1, + 'parse_argv': 1, + } + self.check_config("init_python_config", config, preconfig) + def test_init_read_set(self): preconfig = {} core_config = { @@ -707,6 +727,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'argv': ['-c', 'arg2'], 'program_name': './python3', 'run_command': code + '\n', + 'parse_argv': 1, } self.check_config("init_run_main", core_config, preconfig) @@ -718,15 +739,26 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'argv': ['-c', 'arg2'], 'program_name': './python3', 'run_command': code + '\n', + 'parse_argv': 1, '_init_main': 0, } self.check_config("init_main", core_config, preconfig, stderr="Run Python code before _Py_InitializeMain") + def test_init_parse_argv(self): + core_config = { + 'argv': ['-c', 'arg1', '-v', 'arg3'], + 'program_name': './argv0', + 'parse_argv': 1, + 'run_command': 'pass\n', + 'use_environment': 0, + } + self.check_config("init_parse_argv", core_config, {}) + def test_init_dont_parse_argv(self): core_config = { - 'argv': ['-v', '-c', 'arg1', '-W', 'arg2'], - 'parse_argv': 0, + 'argv': ['./argv0', '-E', '-c', 'pass', 'arg1', '-v', 'arg3'], + 'program_name': './argv0', } self.check_config("init_dont_parse_argv", core_config, {}) diff --git a/Modules/main.c b/Modules/main.c index bb103c28a3e..72546a21cac 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -52,23 +52,28 @@ pymain_init(const _PyArgv *args) fedisableexcept(FE_OVERFLOW); #endif - _PyPreConfig preconfig = _PyPreConfig_INIT; - /* Set to -1 to enable them depending on the LC_CTYPE locale and the - environment variables (PYTHONUTF8 and PYTHONCOERCECLOCALE) */ - preconfig.coerce_c_locale = -1; - preconfig.utf8_mode = -1; + _PyPreConfig preconfig; + _PyPreConfig_InitPythonConfig(&preconfig); err = _Py_PreInitializeFromPyArgv(&preconfig, args); if (_Py_INIT_FAILED(err)) { return err; } + _PyCoreConfig config; + err = _PyCoreConfig_InitPythonConfig(&config); + if (_Py_INIT_FAILED(err)) { + return err; + } + /* pass NULL as the config: config is read from command line arguments, environment variables, configuration files */ if (args->use_bytes_argv) { - return _Py_InitializeFromArgs(NULL, args->argc, args->bytes_argv); + return _Py_InitializeFromArgs(&config, + args->argc, args->bytes_argv); } else { - return _Py_InitializeFromWideArgs(NULL, args->argc, args->wchar_argv); + return _Py_InitializeFromWideArgs(&config, + args->argc, args->wchar_argv); } } diff --git a/Programs/_freeze_importlib.c b/Programs/_freeze_importlib.c index 8cbbe17cfaf..bc29297a6b9 100644 --- a/Programs/_freeze_importlib.c +++ b/Programs/_freeze_importlib.c @@ -76,7 +76,8 @@ main(int argc, char *argv[]) } text[text_size] = '\0'; - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); config.use_environment = 0; config.user_site_directory = 0; config.site_import = 0; diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 3327c8ce663..e6896966f53 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -291,7 +291,9 @@ static int test_initialize_twice(void) static int test_initialize_pymain(void) { wchar_t *argv[] = {L"PYTHON", L"-c", - L"import sys; print(f'Py_Main() after Py_Initialize: sys.argv={sys.argv}')", + (L"import sys; " + L"print(f'Py_Main() after Py_Initialize: " + L"sys.argv={sys.argv}')"), L"arg2"}; _testembed_Py_Initialize(); @@ -376,7 +378,8 @@ static int test_init_from_config(void) { _PyInitError err; - _PyPreConfig preconfig = _PyPreConfig_INIT; + _PyPreConfig preconfig; + _PyPreConfig_Init(&preconfig); putenv("PYTHONMALLOC=malloc_debug"); preconfig.allocator = PYMEM_ALLOCATOR_MALLOC; @@ -391,7 +394,8 @@ static int test_init_from_config(void) } /* Test _Py_InitializeFromConfig() */ - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); config.install_signal_handlers = 0; /* FIXME: test use_environment */ @@ -400,7 +404,7 @@ static int test_init_from_config(void) config.use_hash_seed = 1; config.hash_seed = 123; - /* dev_mode=1 is tested in test_init_dev_mode() */ + /* dev_mode=1 is tested in init_dev_mode() */ putenv("PYTHONFAULTHANDLER="); config.faulthandler = 1; @@ -432,6 +436,7 @@ static int test_init_from_config(void) }; config.argv.length = Py_ARRAY_LENGTH(argv); config.argv.items = argv; + config.parse_argv = 1; static wchar_t* xoptions[3] = { L"core_xoption1=3", @@ -481,7 +486,7 @@ static int test_init_from_config(void) Py_QuietFlag = 0; config.quiet = 1; - config.configure_c_stdio = 0; + config.configure_c_stdio = 1; putenv("PYTHONUNBUFFERED="); Py_UnbufferedStdioFlag = 0; @@ -516,25 +521,26 @@ static int test_init_from_config(void) } -static int test_init_dont_parse_argv(void) +static int test_init_parse_argv(int parse_argv) { _PyInitError err; - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); static wchar_t* argv[] = { - L"-v", + L"./argv0", + L"-E", L"-c", + L"pass", L"arg1", - L"-W", - L"arg2", + L"-v", + L"arg3", }; - config.program_name = L"./_testembed"; - config.argv.length = Py_ARRAY_LENGTH(argv); config.argv.items = argv; - config.parse_argv = 0; + config.parse_argv = parse_argv; err = _Py_InitializeFromConfig(&config); if (_Py_INIT_FAILED(err)) { @@ -546,6 +552,18 @@ static int test_init_dont_parse_argv(void) } +static int init_parse_argv(void) +{ + return test_init_parse_argv(1); +} + + +static int init_dont_parse_argv(void) +{ + return test_init_parse_argv(0); +} + + static void test_init_env_putenvs(void) { putenv("PYTHONHASHSEED=42"); @@ -619,12 +637,13 @@ static int test_init_env_dev_mode_alloc(void) } -static int test_init_isolated(void) +static int init_isolated_flag(void) { _PyInitError err; /* Test _PyCoreConfig.isolated=1 */ - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); Py_IsolatedFlag = 0; config.isolated = 1; @@ -648,7 +667,8 @@ static int test_preinit_isolated1(void) { _PyInitError err; - _PyPreConfig preconfig = _PyPreConfig_INIT; + _PyPreConfig preconfig; + _PyPreConfig_Init(&preconfig); preconfig.isolated = 1; err = _Py_PreInitialize(&preconfig); @@ -656,7 +676,8 @@ static int test_preinit_isolated1(void) _Py_ExitInitError(err); } - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); config.program_name = L"./_testembed"; test_init_env_dev_mode_putenvs(); @@ -675,7 +696,8 @@ static int test_preinit_isolated2(void) { _PyInitError err; - _PyPreConfig preconfig = _PyPreConfig_INIT; + _PyPreConfig preconfig; + _PyPreConfig_Init(&preconfig); preconfig.isolated = 0; err = _Py_PreInitialize(&preconfig); @@ -684,7 +706,8 @@ static int test_preinit_isolated2(void) } /* Test _PyCoreConfig.isolated=1 */ - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); Py_IsolatedFlag = 0; config.isolated = 1; @@ -703,9 +726,72 @@ static int test_preinit_isolated2(void) } -static int test_init_dev_mode(void) +static int init_isolated_config(void) { - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyInitError err; + + _PyPreConfig preconfig; + _PyPreConfig_InitIsolatedConfig(&preconfig); + + err = _Py_PreInitialize(&preconfig); + if (_Py_INIT_FAILED(err)) { + _Py_ExitInitError(err); + } + + _PyPreConfig *rt_preconfig = &_PyRuntime.preconfig; + assert(rt_preconfig->isolated == 1); + assert(rt_preconfig->use_environment == 0); + + _PyCoreConfig config; + err = _PyCoreConfig_InitIsolatedConfig(&config); + if (_Py_INIT_FAILED(err)) { + _Py_ExitInitError(err); + } + config.program_name = L"./_testembed"; + + err = _Py_InitializeFromConfig(&config); + if (_Py_INIT_FAILED(err)) { + _Py_ExitInitError(err); + } + dump_config(); + Py_Finalize(); + return 0; +} + + +static int init_python_config(void) +{ + _PyInitError err; + + _PyPreConfig preconfig; + _PyPreConfig_InitPythonConfig(&preconfig); + + err = _Py_PreInitialize(&preconfig); + if (_Py_INIT_FAILED(err)) { + _Py_ExitInitError(err); + } + + _PyCoreConfig config; + err = _PyCoreConfig_InitPythonConfig(&config); + if (_Py_INIT_FAILED(err)) { + _Py_ExitInitError(err); + } + config.program_name = L"./_testembed"; + + err = _Py_InitializeFromConfig(&config); + if (_Py_INIT_FAILED(err)) { + _Py_ExitInitError(err); + } + dump_config(); + Py_Finalize(); + return 0; +} + + +static int init_dev_mode(void) +{ + _PyCoreConfig config; + _PyCoreConfig_Init(&config); putenv("PYTHONFAULTHANDLER="); putenv("PYTHONMALLOC="); config.dev_mode = 1; @@ -723,7 +809,8 @@ static int test_init_dev_mode(void) static int test_init_read_set(void) { _PyInitError err; - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); err = _PyCoreConfig_DecodeLocale(&config.program_name, "./init_read_set"); if (_Py_INIT_FAILED(err)) { @@ -772,13 +859,15 @@ static void configure_init_main(_PyCoreConfig *config) { config->argv.length = Py_ARRAY_LENGTH(init_main_argv); config->argv.items = init_main_argv; + config->parse_argv = 1; config->program_name = L"./python3"; } static int test_init_run_main(void) { - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); configure_init_main(&config); _PyInitError err = _Py_InitializeFromConfig(&config); @@ -792,7 +881,8 @@ static int test_init_run_main(void) static int test_init_main(void) { - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); configure_init_main(&config); config._init_main = 0; @@ -821,7 +911,8 @@ static int test_init_main(void) static int test_run_main(void) { - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); wchar_t *argv[] = {L"python3", L"-c", (L"import sys; " @@ -829,6 +920,7 @@ static int test_run_main(void) L"arg2"}; config.argv.length = Py_ARRAY_LENGTH(argv); config.argv.items = argv; + config.parse_argv = 1; config.program_name = L"./python3"; _PyInitError err = _Py_InitializeFromConfig(&config); @@ -869,12 +961,15 @@ static struct TestCase TestCases[] = { { "init_default_config", test_init_default_config }, { "init_global_config", test_init_global_config }, { "init_from_config", test_init_from_config }, - { "init_dont_parse_argv", test_init_dont_parse_argv }, + { "init_parse_argv", init_parse_argv }, + { "init_dont_parse_argv", init_dont_parse_argv }, { "init_env", test_init_env }, { "init_env_dev_mode", test_init_env_dev_mode }, { "init_env_dev_mode_alloc", test_init_env_dev_mode_alloc }, - { "init_dev_mode", test_init_dev_mode }, - { "init_isolated", test_init_isolated }, + { "init_dev_mode", init_dev_mode }, + { "init_isolated_flag", init_isolated_flag }, + { "init_isolated_config", init_isolated_config }, + { "init_python_config", init_python_config }, { "preinit_isolated1", test_preinit_isolated1 }, { "preinit_isolated2", test_preinit_isolated2 }, { "init_read_set", test_init_read_set }, diff --git a/Python/coreconfig.c b/Python/coreconfig.c index 634891ed214..2e8f4cf6f10 100644 --- a/Python/coreconfig.c +++ b/Python/coreconfig.c @@ -109,7 +109,7 @@ static const char usage_6[] = /* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change stdin and stdout error handler to "surrogateescape". It is equal to -1 by default: unknown, will be set by Py_Main() */ -int Py_UTF8Mode = -1; +int Py_UTF8Mode = 0; int Py_DebugFlag = 0; /* Needed by parser.c */ int Py_VerboseFlag = 0; /* Needed by import.c */ int Py_QuietFlag = 0; /* Needed by sysmodule.c */ @@ -520,6 +520,61 @@ _PyCoreConfig_Clear(_PyCoreConfig *config) } +void +_PyCoreConfig_Init(_PyCoreConfig *config) +{ + *config = _PyCoreConfig_INIT; +} + + +_PyInitError +_PyCoreConfig_InitPythonConfig(_PyCoreConfig *config) +{ + _PyCoreConfig_Init(config); + + config->configure_c_stdio = 1; + config->parse_argv = 1; + + return _Py_INIT_OK(); +} + + +_PyInitError +_PyCoreConfig_InitIsolatedConfig(_PyCoreConfig *config) +{ + _PyCoreConfig_Init(config); + + /* set to 1 */ + config->isolated = 1; + config->site_import = 1; + config->write_bytecode = 1; + config->buffered_stdio = 1; + + /* set to 0 */ + config->use_environment = 0; + config->dev_mode = 0; + config->install_signal_handlers = 0; + config->use_hash_seed = 0; + config->faulthandler = 0; + config->tracemalloc = 0; + config->bytes_warning = 0; + config->inspect = 0; + config->interactive = 0; + config->optimization_level = 0; + config->parser_debug = 0; + config->verbose = 0; + config->quiet = 0; + config->user_site_directory = 0; + config->configure_c_stdio = 0; + config->pathconfig_warnings = 0; +#ifdef MS_WINDOWS + config->legacy_windows_stdio = 0; +#endif + + return _Py_INIT_OK(); +} + + /* Copy str into *config_str (duplicate the string) */ _PyInitError _PyCoreConfig_SetString(wchar_t **config_str, const wchar_t *str) @@ -2014,17 +2069,20 @@ core_read_precmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline) { _PyInitError err; - if (_PyWstrList_Copy(&precmdline->argv, &config->argv) < 0) { - return _Py_INIT_NO_MEMORY(); + if (config->parse_argv) { + if (_PyWstrList_Copy(&precmdline->argv, &config->argv) < 0) { + return _Py_INIT_NO_MEMORY(); + } } - _PyPreConfig preconfig = _PyPreConfig_INIT; + _PyPreConfig preconfig; + _PyPreConfig_Init(&preconfig); if (_PyPreConfig_Copy(&preconfig, &_PyRuntime.preconfig) < 0) { err = _Py_INIT_NO_MEMORY(); return err; } - _PyCoreConfig_GetCoreConfig(&preconfig, config); + _PyPreConfig_GetCoreConfig(&preconfig, config); err = _PyPreCmdline_Read(precmdline, &preconfig); if (_Py_INIT_FAILED(err)) { @@ -2155,6 +2213,7 @@ _PyInitError _PyCoreConfig_Read(_PyCoreConfig *config) { _PyInitError err; + _PyWstrList orig_argv = _PyWstrList_INIT; err = _Py_PreInitializeFromCoreConfig(config, NULL); if (_Py_INIT_FAILED(err)) { @@ -2163,6 +2222,10 @@ _PyCoreConfig_Read(_PyCoreConfig *config) _PyCoreConfig_GetGlobalConfig(config); + if (_PyWstrList_Copy(&orig_argv, &config->argv) < 0) { + return _Py_INIT_NO_MEMORY(); + } + _PyPreCmdline precmdline = _PyPreCmdline_INIT; err = core_read_precmdline(config, &precmdline); if (_Py_INIT_FAILED(err)) { @@ -2185,10 +2248,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config) goto done; } - /* precmdline.argv is a copy of config.argv which is modified - by config_read_cmdline() */ - const _PyWstrList *argv = &precmdline.argv; - if (_Py_SetArgcArgv(argv->length, argv->items) < 0) { + if (_Py_SetArgcArgv(orig_argv.length, orig_argv.items) < 0) { err = _Py_INIT_NO_MEMORY(); goto done; } @@ -2249,6 +2309,7 @@ _PyCoreConfig_Read(_PyCoreConfig *config) err = _Py_INIT_OK(); done: + _PyWstrList_Clear(&orig_argv); _PyPreCmdline_Clear(&precmdline); return err; } diff --git a/Python/frozenmain.c b/Python/frozenmain.c index f2499ef84cd..0175e42596b 100644 --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -39,7 +39,8 @@ Py_FrozenMain(int argc, char **argv) } } - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); config.pathconfig_warnings = 0; /* Suppress errors from getpath.c */ if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') diff --git a/Python/pathconfig.c b/Python/pathconfig.c index 2fcb8160580..c8c69ebad6a 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -392,7 +392,8 @@ pathconfig_global_init(void) } _PyInitError err; - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); err = _PyCoreConfig_Read(&config); if (_Py_INIT_FAILED(err)) { diff --git a/Python/preconfig.c b/Python/preconfig.c index 2bbf8e6fb7f..7814ee08a63 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -260,6 +260,42 @@ _PyPreCmdline_Read(_PyPreCmdline *cmdline, /* --- _PyPreConfig ----------------------------------------------- */ +void +_PyPreConfig_Init(_PyPreConfig *config) +{ + *config = _PyPreConfig_INIT; +} + + +void +_PyPreConfig_InitPythonConfig(_PyPreConfig *config) +{ + _PyPreConfig_Init(config); + + /* Set to -1 to enable C locale coercion (PEP 538) and UTF-8 Mode (PEP 540) + depending on the LC_CTYPE locale, PYTHONUTF8 and PYTHONCOERCECLOCALE + environment variables. */ + config->coerce_c_locale = -1; + config->coerce_c_locale_warn = -1; + config->utf8_mode = -1; +} + + +void +_PyPreConfig_InitIsolatedConfig(_PyPreConfig *config) +{ + _PyPreConfig_Init(config); + + config->isolated = 1; + config->use_environment = 0; +#ifdef MS_WINDOWS + config->legacy_windows_fs_encoding = 0; +#endif + config->utf8_mode = 0; + config->dev_mode = 0; +} + + int _PyPreConfig_Copy(_PyPreConfig *config, const _PyPreConfig *config2) { @@ -346,7 +382,7 @@ fail: void -_PyCoreConfig_GetCoreConfig(_PyPreConfig *config, +_PyPreConfig_GetCoreConfig(_PyPreConfig *config, const _PyCoreConfig *core_config) { #define COPY_ATTR(ATTR) \ @@ -366,11 +402,11 @@ static void _PyPreConfig_GetGlobalConfig(_PyPreConfig *config) { #define COPY_FLAG(ATTR, VALUE) \ - if (config->ATTR == -1) { \ + if (config->ATTR < 0) { \ config->ATTR = VALUE; \ } #define COPY_NOT_FLAG(ATTR, VALUE) \ - if (config->ATTR == -1) { \ + if (config->ATTR < 0) { \ config->ATTR = !(VALUE); \ } @@ -379,8 +415,8 @@ _PyPreConfig_GetGlobalConfig(_PyPreConfig *config) #ifdef MS_WINDOWS COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); #endif - if (Py_UTF8Mode > 0) { - config->utf8_mode = 1; + if (config->utf8_mode == -2) { + config->utf8_mode = Py_UTF8Mode; } #undef COPY_FLAG @@ -392,11 +428,11 @@ static void _PyPreConfig_SetGlobalConfig(const _PyPreConfig *config) { #define COPY_FLAG(ATTR, VAR) \ - if (config->ATTR != -1) { \ + if (config->ATTR >= 0) { \ VAR = config->ATTR; \ } #define COPY_NOT_FLAG(ATTR, VAR) \ - if (config->ATTR != -1) { \ + if (config->ATTR >= 0) { \ VAR = !config->ATTR; \ } @@ -575,7 +611,9 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config) } } else if (strcmp(env, "warn") == 0) { - config->coerce_c_locale_warn = 1; + if (config->coerce_c_locale_warn < 0) { + config->coerce_c_locale_warn = 1; + } } else { if (config->coerce_c_locale < 0) { @@ -587,19 +625,19 @@ preconfig_init_coerce_c_locale(_PyPreConfig *config) /* Test if coerce_c_locale equals to -1 or equals to 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 || config->coerce_c_locale == 2) { - return; + if (config->coerce_c_locale < 0 || config->coerce_c_locale == 1) { + /* The C locale enables the C locale coercion (PEP 538) */ + if (_Py_LegacyLocaleDetected()) { + config->coerce_c_locale = 2; + } + else { + config->coerce_c_locale = 0; + } } - /* The C locale enables the C locale coercion (PEP 538) */ - if (_Py_LegacyLocaleDetected()) { - config->coerce_c_locale = 2; + if (config->coerce_c_locale_warn < 0) { + config->coerce_c_locale_warn = 0; } - else { - config->coerce_c_locale = 0; - } - - assert(config->coerce_c_locale >= 0); } @@ -659,6 +697,7 @@ preconfig_read(_PyPreConfig *config, _PyPreCmdline *cmdline) } assert(config->coerce_c_locale >= 0); + assert(config->coerce_c_locale_warn >= 0); #ifdef MS_WINDOWS assert(config->legacy_windows_fs_encoding >= 0); #endif @@ -700,7 +739,8 @@ _PyPreConfig_Read(_PyPreConfig *config, const _PyArgv *args) } /* Save the config to be able to restore it if encodings change */ - _PyPreConfig save_config = _PyPreConfig_INIT; + _PyPreConfig save_config; + _PyPreConfig_Init(&save_config); if (_PyPreConfig_Copy(&save_config, config) < 0) { return _Py_INIT_NO_MEMORY(); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index eecb439a11d..231706d2ab6 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -701,7 +701,8 @@ _Py_PreInitializeFromPyArgv(const _PyPreConfig *src_config, const _PyArgv *args) return _Py_INIT_OK(); } - _PyPreConfig config = _PyPreConfig_INIT; + _PyPreConfig config; + _PyPreConfig_Init(&config); if (src_config) { if (_PyPreConfig_Copy(&config, src_config) < 0) { @@ -752,13 +753,22 @@ _PyInitError _Py_PreInitializeFromCoreConfig(const _PyCoreConfig *coreconfig, const _PyArgv *args) { - _PyPreConfig config = _PyPreConfig_INIT; + _PyPreConfig config; + _PyPreConfig_Init(&config); if (coreconfig != NULL) { - _PyCoreConfig_GetCoreConfig(&config, coreconfig); + _PyPreConfig_GetCoreConfig(&config, coreconfig); + } + + if (args == NULL && coreconfig != NULL && coreconfig->parse_argv) { + _PyArgv config_args = { + .use_bytes_argv = 0, + .argc = coreconfig->argv.length, + .wchar_argv = coreconfig->argv.items}; + return _Py_PreInitializeFromPyArgv(&config, &config_args); + } + else { + return _Py_PreInitializeFromPyArgv(&config, args); } - return _Py_PreInitializeFromPyArgv(&config, args); - /* No need to clear config: - _PyCoreConfig_GetCoreConfig() doesn't allocate memory */ } @@ -829,7 +839,8 @@ _Py_InitializeCore(_PyRuntimeState *runtime, return err; } - _PyCoreConfig local_config = _PyCoreConfig_INIT; + _PyCoreConfig local_config; + _PyCoreConfig_Init(&local_config); err = pyinit_coreconfig(runtime, &local_config, src_config, args, interp_p); _PyCoreConfig_Clear(&local_config); return err; @@ -1051,7 +1062,8 @@ Py_InitializeEx(int install_sigs) return; } - _PyCoreConfig config = _PyCoreConfig_INIT; + _PyCoreConfig config; + _PyCoreConfig_Init(&config); config.install_signal_handlers = install_sigs; err = _Py_InitializeFromConfig(&config); diff --git a/Python/pystate.c b/Python/pystate.c index 8c906ce87ad..2f80aa253b5 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -49,7 +49,7 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime) _PyGC_Initialize(&runtime->gc); _PyEval_Initialize(&runtime->ceval); - runtime->preconfig = _PyPreConfig_INIT; + _PyPreConfig_Init(&runtime->preconfig); runtime->gilstate.check_enabled = 1; @@ -189,7 +189,7 @@ PyInterpreterState_New(void) memset(interp, 0, sizeof(*interp)); interp->id_refcount = -1; interp->check_interval = 100; - interp->core_config = _PyCoreConfig_INIT; + _PyCoreConfig_Init(&interp->core_config); interp->eval_frame = _PyEval_EvalFrameDefault; #ifdef HAVE_DLOPEN #if HAVE_DECL_RTLD_NOW