Commit 1f15111a authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

bpo-32030: Add _PyMainInterpreterConfig.pythonhome (#4513)

* Py_Main() now reads the PYTHONHOME environment variable
* Add _Py_GetPythonHomeWithConfig() private function
* Add _PyWarnings_InitWithConfig()
* init_filters() doesn't get the current core configuration from the
  current interpreter or Python thread anymore. Pass explicitly the
  configuration to _PyWarnings_InitWithConfig().
* _Py_InitializeCore() now fails on _PyWarnings_InitWithConfig()
  failure.
* Pass configuration as constant
parent e32e79f7
...@@ -12,6 +12,10 @@ PyAPI_FUNC(wchar_t *) Py_GetProgramName(void); ...@@ -12,6 +12,10 @@ PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *); PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *);
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void); PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
#ifdef Py_BUILD_CORE
PyAPI_FUNC(wchar_t *) _Py_GetPythonHomeWithConfig(
const _PyMainInterpreterConfig *config);
#endif
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
/* Only used by applications that embed the interpreter and need to /* Only used by applications that embed the interpreter and need to
...@@ -94,7 +98,8 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void); ...@@ -94,7 +98,8 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void); PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
PyAPI_FUNC(wchar_t *) Py_GetPath(void); PyAPI_FUNC(wchar_t *) Py_GetPath(void);
#ifdef Py_BUILD_CORE #ifdef Py_BUILD_CORE
PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig(_PyMainInterpreterConfig *config); PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig(
const _PyMainInterpreterConfig *config);
#endif #endif
PyAPI_FUNC(void) Py_SetPath(const wchar_t *); PyAPI_FUNC(void) Py_SetPath(const wchar_t *);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
......
...@@ -61,12 +61,15 @@ typedef struct { ...@@ -61,12 +61,15 @@ typedef struct {
typedef struct { typedef struct {
int install_signal_handlers; int install_signal_handlers;
wchar_t *module_search_path_env; /* PYTHONPATH environment variable */ wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
wchar_t *pythonhome; /* PYTHONHOME environment variable,
see also Py_SetPythonHome(). */
} _PyMainInterpreterConfig; } _PyMainInterpreterConfig;
#define _PyMainInterpreterConfig_INIT \ #define _PyMainInterpreterConfig_INIT \
(_PyMainInterpreterConfig){\ (_PyMainInterpreterConfig){\
.install_signal_handlers = -1, \ .install_signal_handlers = -1, \
.module_search_path_env = NULL} .module_search_path_env = NULL, \
.pythonhome = NULL}
typedef struct _is { typedef struct _is {
......
...@@ -7,6 +7,9 @@ extern "C" { ...@@ -7,6 +7,9 @@ extern "C" {
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject*) _PyWarnings_Init(void); PyAPI_FUNC(PyObject*) _PyWarnings_Init(void);
#endif #endif
#ifdef Py_BUILD_CORE
PyAPI_FUNC(PyObject*) _PyWarnings_InitWithConfig(const _PyCoreConfig *config);
#endif
PyAPI_FUNC(int) PyErr_WarnEx( PyAPI_FUNC(int) PyErr_WarnEx(
PyObject *category, PyObject *category,
......
...@@ -456,13 +456,13 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home, ...@@ -456,13 +456,13 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
} }
static void static void
calculate_path(_PyMainInterpreterConfig *config) calculate_path(const _PyMainInterpreterConfig *config)
{ {
extern wchar_t *Py_GetProgramName(void); extern wchar_t *Py_GetProgramName(void);
static const wchar_t delimiter[2] = {DELIM, '\0'}; static const wchar_t delimiter[2] = {DELIM, '\0'};
static const wchar_t separator[2] = {SEP, '\0'}; static const wchar_t separator[2] = {SEP, '\0'};
wchar_t *home = Py_GetPythonHome(); wchar_t *home = _Py_GetPythonHomeWithConfig(config);
char *_path = getenv("PATH"); char *_path = getenv("PATH");
wchar_t *path_buffer = NULL; wchar_t *path_buffer = NULL;
wchar_t *path = NULL; wchar_t *path = NULL;
...@@ -858,7 +858,7 @@ Py_SetPath(const wchar_t *path) ...@@ -858,7 +858,7 @@ Py_SetPath(const wchar_t *path)
} }
wchar_t * wchar_t *
_Py_GetPathWithConfig(_PyMainInterpreterConfig *config) _Py_GetPathWithConfig(const _PyMainInterpreterConfig *config)
{ {
if (!module_search_path) { if (!module_search_path) {
calculate_path(config); calculate_path(config);
......
...@@ -400,7 +400,6 @@ typedef struct { ...@@ -400,7 +400,6 @@ typedef struct {
_PyInitError err; _PyInitError err;
/* PYTHONWARNINGS env var */ /* PYTHONWARNINGS env var */
_Py_OptList env_warning_options; _Py_OptList env_warning_options;
/* PYTHONPATH env var */
int argc; int argc;
wchar_t **argv; wchar_t **argv;
} _PyMain; } _PyMain;
...@@ -1368,47 +1367,98 @@ pymain_set_flags_from_env(_PyMain *pymain) ...@@ -1368,47 +1367,98 @@ pymain_set_flags_from_env(_PyMain *pymain)
static int static int
pymain_init_pythonpath(_PyMain *pymain) pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest,
wchar_t *wname, char *name)
{ {
if (Py_IgnoreEnvironmentFlag) { if (Py_IgnoreEnvironmentFlag) {
*dest = NULL;
return 0; return 0;
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
wchar_t *path = _wgetenv(L"PYTHONPATH"); wchar_t *var = _wgetenv(wname);
if (!path || path[0] == '\0') { if (!var || var[0] == '\0') {
*dest = NULL;
return 0; return 0;
} }
wchar_t *path2 = pymain_wstrdup(pymain, path); wchar_t *copy = pymain_wstrdup(pymain, var);
if (path2 == NULL) { if (copy == NULL) {
return -1; return -1;
} }
pymain->config.module_search_path_env = path2; *dest = copy;
#else #else
char *path = pymain_get_env_var("PYTHONPATH"); char *var = getenv(name);
if (!path) { if (!var || var[0] == '\0') {
*dest = NULL;
return 0; return 0;
} }
size_t len; size_t len;
wchar_t *wpath = Py_DecodeLocale(path, &len); wchar_t *wvar = Py_DecodeLocale(var, &len);
if (!wpath) { if (!wvar) {
if (len == (size_t)-2) { if (len == (size_t)-2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME"); /* don't set pymain->err */
return -2;
} }
else { else {
pymain->err = INIT_NO_MEMORY(); pymain->err = INIT_NO_MEMORY();
return -1;
} }
return -1;
} }
pymain->config.module_search_path_env = wpath; *dest = wvar;
#endif #endif
return 0; return 0;
} }
static int
pymain_init_pythonpath(_PyMain *pymain)
{
wchar_t *path;
int res = pymain_get_env_var_dup(pymain, &path,
L"PYTHONPATH", "PYTHONPATH");
if (res < 0) {
if (res == -2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONPATH");
}
return -1;
}
pymain->config.module_search_path_env = path;
return 0;
}
static int
pymain_init_pythonhome(_PyMain *pymain)
{
wchar_t *home;
home = Py_GetPythonHome();
if (home) {
/* Py_SetPythonHome() has been called before Py_Main(),
use its value */
pymain->config.pythonhome = pymain_wstrdup(pymain, home);
if (pymain->config.pythonhome == NULL) {
return -1;
}
return 0;
}
int res = pymain_get_env_var_dup(pymain, &home,
L"PYTHONHOME", "PYTHONHOME");
if (res < 0) {
if (res == -2) {
pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME");
}
return -1;
}
pymain->config.pythonhome = home;
return 0;
}
static int static int
pymain_parse_envvars(_PyMain *pymain) pymain_parse_envvars(_PyMain *pymain)
{ {
...@@ -1433,6 +1483,9 @@ pymain_parse_envvars(_PyMain *pymain) ...@@ -1433,6 +1483,9 @@ pymain_parse_envvars(_PyMain *pymain)
if (pymain_init_pythonpath(pymain) < 0) { if (pymain_init_pythonpath(pymain) < 0) {
return -1; return -1;
} }
if (pymain_init_pythonhome(pymain) < 0) {
return -1;
}
/* -X options */ /* -X options */
if (pymain_get_xoption(pymain, L"showrefcount")) { if (pymain_get_xoption(pymain, L"showrefcount")) {
......
...@@ -624,12 +624,12 @@ error: ...@@ -624,12 +624,12 @@ error:
static void static void
calculate_path(_PyMainInterpreterConfig *config) calculate_path(const _PyMainInterpreterConfig *config)
{ {
wchar_t argv0_path[MAXPATHLEN+1]; wchar_t argv0_path[MAXPATHLEN+1];
wchar_t *buf; wchar_t *buf;
size_t bufsz; size_t bufsz;
wchar_t *pythonhome = Py_GetPythonHome(); wchar_t *pythonhome = _Py_GetPythonHomeWithConfig(config);
wchar_t *envpath = NULL; wchar_t *envpath = NULL;
int skiphome, skipdefault; int skiphome, skipdefault;
...@@ -899,7 +899,7 @@ Py_SetPath(const wchar_t *path) ...@@ -899,7 +899,7 @@ Py_SetPath(const wchar_t *path)
} }
wchar_t * wchar_t *
_Py_GetPathWithConfig(_PyMainInterpreterConfig *config) _Py_GetPathWithConfig(const _PyMainInterpreterConfig *config)
{ {
if (!module_search_path) { if (!module_search_path) {
calculate_path(config); calculate_path(config);
......
...@@ -1185,10 +1185,9 @@ create_filter(PyObject *category, const char *action) ...@@ -1185,10 +1185,9 @@ create_filter(PyObject *category, const char *action)
} }
static PyObject * static PyObject *
init_filters(void) init_filters(const _PyCoreConfig *config)
{ {
PyInterpreterState *interp = PyThreadState_GET()->interp; int dev_mode = config->dev_mode;
int dev_mode = interp->core_config.dev_mode;
Py_ssize_t count = 2; Py_ssize_t count = 2;
if (dev_mode) { if (dev_mode) {
...@@ -1264,8 +1263,8 @@ static struct PyModuleDef warningsmodule = { ...@@ -1264,8 +1263,8 @@ static struct PyModuleDef warningsmodule = {
}; };
PyMODINIT_FUNC PyObject*
_PyWarnings_Init(void) _PyWarnings_InitWithConfig(const _PyCoreConfig *config)
{ {
PyObject *m; PyObject *m;
...@@ -1274,7 +1273,7 @@ _PyWarnings_Init(void) ...@@ -1274,7 +1273,7 @@ _PyWarnings_Init(void)
return NULL; return NULL;
if (_PyRuntime.warnings.filters == NULL) { if (_PyRuntime.warnings.filters == NULL) {
_PyRuntime.warnings.filters = init_filters(); _PyRuntime.warnings.filters = init_filters(config);
if (_PyRuntime.warnings.filters == NULL) if (_PyRuntime.warnings.filters == NULL)
return NULL; return NULL;
} }
...@@ -1305,3 +1304,12 @@ _PyWarnings_Init(void) ...@@ -1305,3 +1304,12 @@ _PyWarnings_Init(void)
_PyRuntime.warnings.filters_version = 0; _PyRuntime.warnings.filters_version = 0;
return m; return m;
} }
PyMODINIT_FUNC
_PyWarnings_Init(void)
{
PyInterpreterState *interp = PyThreadState_GET()->interp;
const _PyCoreConfig *config = &interp->core_config;
return _PyWarnings_InitWithConfig(config);
}
...@@ -767,7 +767,9 @@ _Py_InitializeCore(const _PyCoreConfig *config) ...@@ -767,7 +767,9 @@ _Py_InitializeCore(const _PyCoreConfig *config)
} }
/* Initialize _warnings. */ /* Initialize _warnings. */
_PyWarnings_Init(); if (_PyWarnings_InitWithConfig(&interp->core_config) == NULL) {
return _Py_INIT_ERR("can't initialize warnings");
}
/* This call sets up builtin and frozen import support */ /* This call sets up builtin and frozen import support */
if (!interp->core_config._disable_importlib) { if (!interp->core_config._disable_importlib) {
...@@ -880,7 +882,7 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config) ...@@ -880,7 +882,7 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
return err; return err;
} }
if (config->install_signal_handlers) { if (interp->config.install_signal_handlers) {
err = initsigs(); /* Signal handling stuff, including initintr() */ err = initsigs(); /* Signal handling stuff, including initintr() */
if (_Py_INIT_FAILED(err)) { if (_Py_INIT_FAILED(err)) {
return err; return err;
...@@ -1468,7 +1470,6 @@ Py_GetProgramName(void) ...@@ -1468,7 +1470,6 @@ Py_GetProgramName(void)
} }
static wchar_t *default_home = NULL; static wchar_t *default_home = NULL;
static wchar_t env_home[MAXPATHLEN+1];
void void
Py_SetPythonHome(wchar_t *home) Py_SetPythonHome(wchar_t *home)
...@@ -1477,20 +1478,40 @@ Py_SetPythonHome(wchar_t *home) ...@@ -1477,20 +1478,40 @@ Py_SetPythonHome(wchar_t *home)
} }
wchar_t * wchar_t *
Py_GetPythonHome(void) _Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config)
{ {
wchar_t *home = default_home; /* Use a static buffer to avoid heap memory allocation failure.
if (home == NULL && !Py_IgnoreEnvironmentFlag) { Py_GetPythonHome() doesn't allow to report error, and the caller
char* chome = Py_GETENV("PYTHONHOME"); doesn't release memory. */
if (chome) { static wchar_t buffer[MAXPATHLEN+1];
size_t size = Py_ARRAY_LENGTH(env_home);
size_t r = mbstowcs(env_home, chome, size); if (default_home) {
if (r != (size_t)-1 && r < size) return default_home;
home = env_home; }
}
if (config) {
return config->pythonhome;
} }
return home;
char *home = Py_GETENV("PYTHONHOME");
if (!home) {
return NULL;
}
size_t size = Py_ARRAY_LENGTH(buffer);
size_t r = mbstowcs(buffer, home, size);
if (r == (size_t)-1 || r >= size) {
/* conversion failed or the static buffer is too small */
return NULL;
}
return buffer;
}
wchar_t *
Py_GetPythonHome(void)
{
return _Py_GetPythonHomeWithConfig(NULL);
} }
/* Add the __main__ module */ /* Add the __main__ module */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment