From 41264f1cd4d6066b2797ff07cae465c1e06ff3b2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 Dec 2017 02:05:29 +0100 Subject: [PATCH] bpo-32030: Add _PyMainInterpreterConfig.executable (#4876) * Add new fields to _PyMainInterpreterConfig: * executable * prefix * base_prefix * exec_prefix * base_exec_prefix * _PySys_EndInit() now sets sys attributes from _PyMainInterpreterConfig --- Include/pylifecycle.h | 2 +- Include/pystate.h | 15 ++++++---- Modules/main.c | 69 +++++++++++++++++++++++++++++++------------ Python/pylifecycle.c | 32 ++------------------ Python/sysmodule.c | 43 +++++++++++++++++++-------- 5 files changed, 92 insertions(+), 69 deletions(-) diff --git a/Include/pylifecycle.h b/Include/pylifecycle.h index 39339da45af..dcb7fcb8495 100644 --- a/Include/pylifecycle.h +++ b/Include/pylifecycle.h @@ -135,7 +135,7 @@ PyAPI_FUNC(const char *) _Py_gitversion(void); #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void); PyAPI_FUNC(_PyInitError) _PySys_BeginInit(PyObject **sysmod); -PyAPI_FUNC(int) _PySys_EndInit(PyObject *sysdict); +PyAPI_FUNC(int) _PySys_EndInit(PyObject *sysdict, _PyMainInterpreterConfig *config); PyAPI_FUNC(_PyInitError) _PyImport_Init(PyInterpreterState *interp); PyAPI_FUNC(void) _PyExc_Init(PyObject * bltinmod); PyAPI_FUNC(_PyInitError) _PyImportHooks_Init(void); diff --git a/Include/pystate.h b/Include/pystate.h index e8cf4134a8c..a56c9b4ea6c 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -52,15 +52,18 @@ typedef struct { /* Placeholders while working on the new configuration API * * See PEP 432 for final anticipated contents - * - * For the moment, just handle the args to _Py_InitializeEx */ typedef struct { int install_signal_handlers; - PyObject *argv; /* sys.argv list, can be NULL */ - PyObject *module_search_path; /* sys.path list */ - PyObject *warnoptions; /* sys.warnoptions list, can be NULL */ - PyObject *xoptions; /* sys._xoptions dict, can be NULL */ + PyObject *argv; /* sys.argv list, can be NULL */ + PyObject *executable; /* sys.executable str */ + PyObject *prefix; /* sys.prefix str */ + PyObject *base_prefix; /* sys.base_prefix str, can be NULL */ + PyObject *exec_prefix; /* sys.exec_prefix str */ + PyObject *base_exec_prefix; /* sys.base_exec_prefix str, can be NULL */ + PyObject *warnoptions; /* sys.warnoptions list, can be NULL */ + PyObject *xoptions; /* sys._xoptions dict, can be NULL */ + PyObject *module_search_path; /* sys.path list */ } _PyMainInterpreterConfig; #define _PyMainInterpreterConfig_INIT \ diff --git a/Modules/main.c b/Modules/main.c index 8c4219c7ec3..339a0f5e681 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -2005,9 +2005,14 @@ void _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config) { Py_CLEAR(config->argv); - Py_CLEAR(config->module_search_path); + Py_CLEAR(config->executable); + Py_CLEAR(config->prefix); + Py_CLEAR(config->base_prefix); + Py_CLEAR(config->exec_prefix); + Py_CLEAR(config->base_exec_prefix); Py_CLEAR(config->warnoptions); Py_CLEAR(config->xoptions); + Py_CLEAR(config->module_search_path); } @@ -2052,9 +2057,14 @@ _PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config, } while (0) COPY_ATTR(argv); - COPY_ATTR(module_search_path); + COPY_ATTR(executable); + COPY_ATTR(prefix); + COPY_ATTR(base_prefix); + COPY_ATTR(exec_prefix); + COPY_ATTR(base_exec_prefix); COPY_ATTR(warnoptions); COPY_ATTR(xoptions); + COPY_ATTR(module_search_path); #undef COPY_ATTR return 0; } @@ -2099,26 +2109,14 @@ config_create_path_list(const wchar_t *path, wchar_t delim) } -static _PyInitError -config_init_module_search_path(_PyMainInterpreterConfig *config, _PyCoreConfig *core_config) +_PyInitError +_PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *config, _PyCoreConfig *core_config) { _PyInitError err = _PyPathConfig_Init(core_config); if (_Py_INIT_FAILED(err)) { return err; } - wchar_t *sys_path = Py_GetPath(); - config->module_search_path = config_create_path_list(sys_path, DELIM); - if (config->module_search_path == NULL) { - return _Py_INIT_NO_MEMORY(); - } - return _Py_INIT_OK(); -} - - -_PyInitError -_PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *config, _PyCoreConfig *core_config) -{ /* Signal handlers are installed by default */ if (config->install_signal_handlers < 0) { config->install_signal_handlers = 1; @@ -2126,12 +2124,45 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *config, _PyCoreConfig *c if (config->module_search_path == NULL && !core_config->_disable_importlib) + { - _PyInitError err = config_init_module_search_path(config, core_config); - if (_Py_INIT_FAILED(err)) { - return err; + wchar_t *sys_path = Py_GetPath(); + config->module_search_path = config_create_path_list(sys_path, DELIM); + if (config->module_search_path == NULL) { + return _Py_INIT_NO_MEMORY(); } } + + if (config->executable == NULL) { + config->executable = PyUnicode_FromWideChar(Py_GetProgramFullPath(), -1); + if (config->executable == NULL) { + return _Py_INIT_NO_MEMORY(); + } + } + + if (config->prefix == NULL) { + config->prefix = PyUnicode_FromWideChar(Py_GetPrefix(), -1); + if (config->prefix == NULL) { + return _Py_INIT_NO_MEMORY(); + } + } + + if (config->exec_prefix == NULL) { + config->exec_prefix = PyUnicode_FromWideChar(Py_GetExecPrefix(), -1); + if (config->exec_prefix == NULL) { + return _Py_INIT_NO_MEMORY(); + } + } + + if (config->base_prefix == NULL) { + Py_INCREF(config->prefix); + config->base_prefix = config->prefix; + } + + if (config->base_exec_prefix == NULL) { + Py_INCREF(config->exec_prefix); + config->base_exec_prefix = config->exec_prefix; + } return _Py_INIT_OK(); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 830f89d0d41..8c626075d5d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -830,28 +830,7 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) return _Py_INIT_ERR("can't initialize time"); } - /* Set sys attributes */ - assert(interp->config.module_search_path != NULL); - if (PySys_SetObject("path", interp->config.module_search_path) != 0) { - return _Py_INIT_ERR("can't assign sys.path"); - } - if (interp->config.argv != NULL) { - if (PySys_SetObject("argv", interp->config.argv) != 0) { - return _Py_INIT_ERR("can't assign sys.argv"); - } - } - if (interp->config.warnoptions != NULL) { - if (PySys_SetObject("warnoptions", interp->config.warnoptions)) { - return _Py_INIT_ERR("can't assign sys.warnoptions"); - } - } - if (interp->config.xoptions != NULL) { - if (PySys_SetObject("_xoptions", interp->config.xoptions)) { - return _Py_INIT_ERR("can't assign sys._xoptions"); - } - } - - if (_PySys_EndInit(interp->sysdict) < 0) { + if (_PySys_EndInit(interp->sysdict, &interp->config) < 0) { return _Py_INIT_ERR("can't finish initializing sys"); } @@ -1314,12 +1293,6 @@ new_interpreter(PyThreadState **tstate_p) return _Py_INIT_ERR("failed to copy main interpreter config"); } - err = _PyPathConfig_Init(&interp->core_config); - if (_Py_INIT_FAILED(err)) { - return err; - } - wchar_t *sys_path = Py_GetPath(); - /* XXX The following is lax in error checking */ PyObject *modules = PyDict_New(); if (modules == NULL) { @@ -1334,8 +1307,7 @@ new_interpreter(PyThreadState **tstate_p) goto handle_error; Py_INCREF(interp->sysdict); PyDict_SetItemString(interp->sysdict, "modules", modules); - PySys_SetPath(sys_path); - _PySys_EndInit(interp->sysdict); + _PySys_EndInit(interp->sysdict, &interp->config); } bimod = _PyImport_FindBuiltin("builtins", modules); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index b33a316331a..24098b9daf8 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2212,7 +2212,6 @@ err_occurred: } #undef SET_SYS_FROM_STRING -#undef SET_SYS_FROM_STRING_BORROW /* Updating the sys namespace, returning integer error codes */ #define SET_SYS_FROM_STRING_INT_RESULT(key, value) \ @@ -2228,10 +2227,35 @@ err_occurred: } while (0) int -_PySys_EndInit(PyObject *sysdict) +_PySys_EndInit(PyObject *sysdict, _PyMainInterpreterConfig *config) { int res; + /* _PyMainInterpreterConfig_Read() must set all these variables */ + assert(config->module_search_path != NULL); + assert(config->executable != NULL); + assert(config->prefix != NULL); + assert(config->base_prefix != NULL); + assert(config->exec_prefix != NULL); + assert(config->base_exec_prefix != NULL); + + SET_SYS_FROM_STRING_BORROW("path", config->module_search_path); + SET_SYS_FROM_STRING_BORROW("executable", config->executable); + SET_SYS_FROM_STRING_BORROW("prefix", config->prefix); + SET_SYS_FROM_STRING_BORROW("base_prefix", config->base_prefix); + SET_SYS_FROM_STRING_BORROW("exec_prefix", config->exec_prefix); + SET_SYS_FROM_STRING_BORROW("base_exec_prefix", config->base_exec_prefix); + + if (config->argv != NULL) { + SET_SYS_FROM_STRING_BORROW("argv", config->argv); + } + if (config->warnoptions != NULL) { + SET_SYS_FROM_STRING_BORROW("warnoptions", config->warnoptions); + } + if (config->xoptions != NULL) { + SET_SYS_FROM_STRING_BORROW("_xoptions", config->xoptions); + } + /* Set flags to their final values */ SET_SYS_FROM_STRING_INT_RESULT("flags", make_flags()); /* prevent user from creating new instances */ @@ -2247,17 +2271,6 @@ _PySys_EndInit(PyObject *sysdict) SET_SYS_FROM_STRING_INT_RESULT("dont_write_bytecode", PyBool_FromLong(Py_DontWriteBytecodeFlag)); - SET_SYS_FROM_STRING_INT_RESULT("executable", - PyUnicode_FromWideChar( - Py_GetProgramFullPath(), -1)); - SET_SYS_FROM_STRING_INT_RESULT("prefix", - PyUnicode_FromWideChar(Py_GetPrefix(), -1)); - SET_SYS_FROM_STRING_INT_RESULT("exec_prefix", - PyUnicode_FromWideChar(Py_GetExecPrefix(), -1)); - SET_SYS_FROM_STRING_INT_RESULT("base_prefix", - PyUnicode_FromWideChar(Py_GetPrefix(), -1)); - SET_SYS_FROM_STRING_INT_RESULT("base_exec_prefix", - PyUnicode_FromWideChar(Py_GetExecPrefix(), -1)); if (get_warnoptions() == NULL) return -1; @@ -2268,8 +2281,12 @@ _PySys_EndInit(PyObject *sysdict) if (PyErr_Occurred()) return -1; return 0; + +err_occurred: + return -1; } +#undef SET_SYS_FROM_STRING_BORROW #undef SET_SYS_FROM_STRING_INT_RESULT static PyObject *