From 54b43bb3bb88339b63182b3515cda3efa530ed62 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 16 May 2019 18:30:15 +0200 Subject: [PATCH] bpo-36763: Add _PyCoreConfig.configure_c_stdio (GH-13363) Add tests for configure_c_stdio and pathconfig_warnings parameters. --- Include/cpython/coreconfig.h | 9 +++++++++ Lib/test/test_embed.py | 4 ++++ Programs/_testembed.c | 7 +++++++ Python/coreconfig.c | 20 +++++++++++++++++--- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h index c2c55668406..b531118ea3c 100644 --- a/Include/cpython/coreconfig.h +++ b/Include/cpython/coreconfig.h @@ -312,6 +312,14 @@ typedef struct { !Py_NoUserSiteDirectory. */ int user_site_directory; + /* If non-zero, configure C standard steams (stdio, stdout, + stderr): + + - Set O_BINARY mode on Windows. + - If buffered_stdio is equal to zero, make streams unbuffered. + Otherwise, enable streams buffering if interactive is non-zero. */ + int configure_c_stdio; + /* If equal to 0, enable unbuffered mode: force the stdout and stderr streams to be unbuffered. @@ -439,6 +447,7 @@ typedef struct { .verbose = -1, \ .quiet = -1, \ .user_site_directory = -1, \ + .configure_c_stdio = 1, \ .buffered_stdio = -1, \ ._install_importlib = 1, \ .check_hash_pycs_mode = NULL, \ diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index c3c1a3e3bac..b1872ace8a6 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -331,6 +331,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'verbose': 0, 'quiet': 0, 'user_site_directory': 1, + 'configure_c_stdio': 1, 'buffered_stdio': 1, 'stdio_encoding': GET_DEFAULT_CONFIG, @@ -558,6 +559,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'filesystem_encoding': 'utf-8', 'filesystem_errors': self.UTF8_MODE_ERRORS, 'user_site_directory': 0, + 'pathconfig_warnings': 0, } self.check_config("init_global_config", config, preconfig) @@ -597,11 +599,13 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'write_bytecode': 0, 'verbose': 1, 'quiet': 1, + 'configure_c_stdio': 0, 'buffered_stdio': 0, 'user_site_directory': 0, 'faulthandler': 1, 'check_hash_pycs_mode': 'always', + 'pathconfig_warnings': 0, } self.check_config("init_from_config", config, preconfig) diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 4ee2cd1b407..87d159fe721 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -360,6 +360,8 @@ static int test_init_global_config(void) putenv("PYTHONUNBUFFERED="); Py_UnbufferedStdioFlag = 1; + Py_FrozenFlag = 1; + /* FIXME: test Py_LegacyWindowsFSEncodingFlag */ /* FIXME: test Py_LegacyWindowsStdioFlag */ @@ -481,6 +483,8 @@ static int test_init_from_config(void) Py_QuietFlag = 0; config.quiet = 1; + config.configure_c_stdio = 0; + putenv("PYTHONUNBUFFERED="); Py_UnbufferedStdioFlag = 0; config.buffered_stdio = 0; @@ -501,6 +505,9 @@ static int test_init_from_config(void) config.check_hash_pycs_mode = L"always"; + Py_FrozenFlag = 0; + config.pathconfig_warnings = 0; + err = _Py_InitializeFromConfig(&config); if (_Py_INIT_FAILED(err)) { _Py_ExitInitError(err); diff --git a/Python/coreconfig.c b/Python/coreconfig.c index 8a5e5d509cb..e51bf9424a3 100644 --- a/Python/coreconfig.c +++ b/Python/coreconfig.c @@ -654,6 +654,7 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) COPY_ATTR(verbose); COPY_ATTR(quiet); COPY_ATTR(user_site_directory); + COPY_ATTR(configure_c_stdio); COPY_ATTR(buffered_stdio); COPY_WSTR_ATTR(filesystem_encoding); COPY_WSTR_ATTR(filesystem_errors); @@ -755,6 +756,7 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config) SET_ITEM_INT(verbose); SET_ITEM_INT(quiet); SET_ITEM_INT(user_site_directory); + SET_ITEM_INT(configure_c_stdio); SET_ITEM_INT(buffered_stdio); SET_ITEM_WSTR(stdio_encoding); SET_ITEM_WSTR(stdio_errors); @@ -1582,7 +1584,6 @@ config_read(_PyCoreConfig *config, _PyPreCmdline *cmdline) return _Py_INIT_NO_MEMORY(); } } - return _Py_INIT_OK(); } @@ -1632,7 +1633,10 @@ void _PyCoreConfig_Write(const _PyCoreConfig *config, _PyRuntimeState *runtime) { _PyCoreConfig_SetGlobalConfig(config); - config_init_stdio(config); + + if (config->configure_c_stdio) { + config_init_stdio(config); + } /* Write the new pre-configuration into _PyRuntime */ _PyPreConfig *preconfig = &runtime->preconfig; @@ -2067,6 +2071,9 @@ config_read_cmdline(_PyCoreConfig *config, _PyPreCmdline *precmdline) if (config->parse_argv < 0) { config->parse_argv = 1; } + if (config->configure_c_stdio < 0) { + config->configure_c_stdio = 1; + } if (config->parse_argv) { int opt_index; @@ -2171,7 +2178,9 @@ _PyCoreConfig_SetWideArgv(_PyCoreConfig *config, int argc, wchar_t **argv) * Command line arguments * Environment variables - * Py_xxx global configuration variables */ + * Py_xxx global configuration variables + + The only side effects are to modify config and to call _Py_SetArgcArgv(). */ _PyInitError _PyCoreConfig_Read(_PyCoreConfig *config) { @@ -2227,14 +2236,19 @@ _PyCoreConfig_Read(_PyCoreConfig *config) assert(config->quiet >= 0); assert(config->user_site_directory >= 0); assert(config->parse_argv >= 0); + assert(config->configure_c_stdio >= 0); assert(config->buffered_stdio >= 0); assert(config->program_name != NULL); assert(config->program != NULL); assert(_PyWstrList_CheckConsistency(&config->argv)); + /* sys.argv must be non-empty: empty argv is replaced with [''] */ + assert(config->argv.length >= 1); assert(_PyWstrList_CheckConsistency(&config->xoptions)); assert(_PyWstrList_CheckConsistency(&config->warnoptions)); assert(_PyWstrList_CheckConsistency(&config->module_search_paths)); if (config->_install_importlib) { + assert(config->use_module_search_paths != 0); + /* don't check config->module_search_paths */ assert(config->executable != NULL); assert(config->prefix != NULL); assert(config->base_prefix != NULL);