diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h index b531118ea3c..1ba2663c966 100644 --- a/Include/cpython/coreconfig.h +++ b/Include/cpython/coreconfig.h @@ -218,11 +218,15 @@ typedef struct { always exists and is never empty. */ _PyWstrList argv; - /* Program: argv[0] or "". - Used to display Python usage if parsing command line arguments fails. - Used to initialize the default value of program_name */ - wchar_t *program; - wchar_t *program_name; /* Program name, see also Py_GetProgramName() */ + /* Program name: + + - If Py_SetProgramName() was called, use its value. + - On macOS, use PYTHONEXECUTABLE environment variable if set. + - If WITH_NEXT_FRAMEWORK macro is defined, use __PYVENV_LAUNCHER__ + environment variable is set. + - Use argv[0] if available and non-empty. + - Use "python" on Windows, or "python3 on other platforms. */ + wchar_t *program_name; _PyWstrList xoptions; /* Command line -X options */ _PyWstrList warnoptions; /* Warnings options */ diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index b1872ace8a6..4012a389d75 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -306,7 +306,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'program_name': GET_DEFAULT_CONFIG, 'parse_argv': 1, 'argv': [""], - 'program': '', 'xoptions': [], 'warnoptions': [], @@ -586,7 +585,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'pycache_prefix': 'conf_pycache_prefix', 'program_name': './conf_program_name', 'argv': ['-c', 'arg2'], - 'program': 'conf_program', 'xoptions': ['core_xoption1=3', 'core_xoption2=', 'core_xoption3'], 'warnoptions': ['error::ResourceWarning', 'default::BytesWarning'], 'run_command': 'pass\n', @@ -704,7 +702,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'print(json.dumps(_testinternalcapi.get_configs()))') core_config = { 'argv': ['-c', 'arg2'], - 'program': 'python3', 'program_name': './python3', 'run_command': code + '\n', } @@ -716,7 +713,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'print(json.dumps(_testinternalcapi.get_configs()))') core_config = { 'argv': ['-c', 'arg2'], - 'program': 'python3', 'program_name': './python3', 'run_command': code + '\n', '_init_main': 0, @@ -728,7 +724,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): core_config = { 'argv': ['-v', '-c', 'arg1', '-W', 'arg2'], 'parse_argv': 0, - 'program': 'program', } self.check_config("init_dont_parse_argv", core_config, {}) diff --git a/Modules/main.c b/Modules/main.c index b47ac70d62c..bb103c28a3e 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -283,7 +283,7 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf) else cfilename = ""; fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n", - config->program, cfilename, err, strerror(err)); + config->program_name, cfilename, err, strerror(err)); PyMem_RawFree(cfilename_buffer); return 2; } @@ -303,7 +303,7 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf) if (_Py_fstat_noraise(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) { fprintf(stderr, "%ls: '%ls' is a directory, cannot continue\n", - config->program, filename); + config->program_name, filename); fclose(fp); return 1; } diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 87d159fe721..b1b7c6e0ffc 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -433,8 +433,6 @@ static int test_init_from_config(void) config.argv.length = Py_ARRAY_LENGTH(argv); config.argv.items = argv; - config.program = L"conf_program"; - static wchar_t* xoptions[3] = { L"core_xoption1=3", L"core_xoption2=", @@ -532,7 +530,6 @@ static int test_init_dont_parse_argv(void) L"arg2", }; - config.program = L"program"; config.program_name = L"./_testembed"; config.argv.length = Py_ARRAY_LENGTH(argv); diff --git a/Python/coreconfig.c b/Python/coreconfig.c index ce778a640d3..c20ae2151c9 100644 --- a/Python/coreconfig.c +++ b/Python/coreconfig.c @@ -492,7 +492,6 @@ _PyCoreConfig_Clear(_PyCoreConfig *config) CLEAR(config->module_search_path_env); CLEAR(config->home); CLEAR(config->program_name); - CLEAR(config->program); _PyWstrList_Clear(&config->argv); _PyWstrList_Clear(&config->warnoptions); @@ -626,7 +625,6 @@ _PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2) COPY_WSTR_ATTR(module_search_path_env); COPY_WSTR_ATTR(home); COPY_WSTR_ATTR(program_name); - COPY_WSTR_ATTR(program); COPY_ATTR(parse_argv); COPY_WSTRLIST(argv); @@ -732,7 +730,6 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config) SET_ITEM_WSTR(program_name); SET_ITEM_INT(parse_argv); SET_ITEM_WSTRLIST(argv); - SET_ITEM_WSTR(program); SET_ITEM_WSTRLIST(xoptions); SET_ITEM_WSTRLIST(warnoptions); SET_ITEM_WSTR(module_search_path_env); @@ -918,7 +915,6 @@ static _PyInitError config_init_program_name(_PyCoreConfig *config) { _PyInitError err; - assert(config->program_name == NULL); /* If Py_SetProgramName() was called, use its value */ const wchar_t *program_name = _Py_path_config.program_name; @@ -967,16 +963,17 @@ config_init_program_name(_PyCoreConfig *config) #endif /* WITH_NEXT_FRAMEWORK */ #endif /* __APPLE__ */ - /* Use argv[0] by default, if available */ - if (config->program != NULL) { - err = _PyCoreConfig_SetString(&config->program_name, config->program); - if (_Py_INIT_FAILED(err)) { - return err; + /* Use argv[0] if available and non-empty */ + const _PyWstrList *argv = &config->argv; + if (argv->length >= 1 && argv->items[0][0] != L'\0') { + config->program_name = _PyMem_RawWcsdup(argv->items[0]); + if (config->program_name == NULL) { + return _Py_INIT_NO_MEMORY(); } return _Py_INIT_OK(); } - /* Last fall back: hardcoded string */ + /* Last fall back: hardcoded name */ #ifdef MS_WINDOWS const wchar_t *default_program_name = L"python"; #else @@ -1518,13 +1515,6 @@ config_read(_PyCoreConfig *config) } } - if (config->program_name == NULL) { - err = config_init_program_name(config); - if (_Py_INIT_FAILED(err)) { - return err; - } - } - if (config->executable == NULL) { err = config_init_executable(config); if (_Py_INIT_FAILED(err)) { @@ -1678,6 +1668,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions, _PyInitError err; const _PyWstrList *argv = &config->argv; int print_version = 0; + const wchar_t* program = config->program_name; _PyOS_ResetGetOpt(); do { @@ -1734,7 +1725,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions, } else { fprintf(stderr, "--check-hash-based-pycs must be one of " "'default', 'always', or 'never'\n"); - config_usage(1, config->program); + config_usage(1, program); return _Py_INIT_EXIT(2); } break; @@ -1794,7 +1785,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions, case 'h': case '?': - config_usage(0, config->program); + config_usage(0, program); return _Py_INIT_EXIT(0); case 'V': @@ -1819,7 +1810,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyWstrList *warnoptions, default: /* unknown argument: parsing failed */ - config_usage(1, config->program); + config_usage(1, program); return _Py_INIT_EXIT(2); } } while (1); @@ -1892,26 +1883,6 @@ config_init_env_warnoptions(const _PyCoreConfig *config, _PyWstrList *warnoption } -static _PyInitError -config_init_program(_PyCoreConfig *config) -{ - const _PyWstrList *argv = &config->argv; - wchar_t *program; - if (argv->length >= 1) { - program = argv->items[0]; - } - else { - program = L""; - } - config->program = _PyMem_RawWcsdup(program); - if (config->program == NULL) { - return _Py_INIT_NO_MEMORY(); - } - - return _Py_INIT_OK(); -} - - static int config_add_warnoption(_PyCoreConfig *config, const wchar_t *option) { @@ -2084,10 +2055,10 @@ config_read_cmdline(_PyCoreConfig *config) config->parse_argv = 1; } - if (config->program == NULL) { - err = config_init_program(config); + if (config->program_name == NULL) { + err = config_init_program_name(config); if (_Py_INIT_FAILED(err)) { - goto done; + return err; } } @@ -2218,6 +2189,8 @@ _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) { err = _Py_INIT_NO_MEMORY(); @@ -2246,7 +2219,6 @@ _PyCoreConfig_Read(_PyCoreConfig *config) 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);