Skip to content

Commit 1f15111

Browse files
authored
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
1 parent e32e79f commit 1f15111

File tree

8 files changed

+135
-42
lines changed

8 files changed

+135
-42
lines changed

‎Include/pylifecycle.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
1212

1313
PyAPI_FUNC(void) Py_SetPythonHome(wchar_t *);
1414
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
15+
#ifdef Py_BUILD_CORE
16+
PyAPI_FUNC(wchar_t *) _Py_GetPythonHomeWithConfig(
17+
const _PyMainInterpreterConfig *config);
18+
#endif
1519

1620
#ifndef Py_LIMITED_API
1721
/* Only used by applications that embed the interpreter and need to
@@ -94,7 +98,8 @@ PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
9498
PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
9599
PyAPI_FUNC(wchar_t *) Py_GetPath(void);
96100
#ifdef Py_BUILD_CORE
97-
PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig(_PyMainInterpreterConfig *config);
101+
PyAPI_FUNC(wchar_t *) _Py_GetPathWithConfig(
102+
const _PyMainInterpreterConfig *config);
98103
#endif
99104
PyAPI_FUNC(void) Py_SetPath(const wchar_t *);
100105
#ifdef MS_WINDOWS

‎Include/pystate.h‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,15 @@ typedef struct {
6161
typedef struct {
6262
int install_signal_handlers;
6363
wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
64+
wchar_t *pythonhome; /* PYTHONHOME environment variable,
65+
see also Py_SetPythonHome(). */
6466
} _PyMainInterpreterConfig;
6567

6668
#define _PyMainInterpreterConfig_INIT \
6769
(_PyMainInterpreterConfig){\
6870
.install_signal_handlers = -1, \
69-
.module_search_path_env = NULL}
71+
.module_search_path_env = NULL, \
72+
.pythonhome = NULL}
7073

7174
typedef struct _is {
7275

‎Include/warnings.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ extern "C" {
77
#ifndef Py_LIMITED_API
88
PyAPI_FUNC(PyObject*) _PyWarnings_Init(void);
99
#endif
10+
#ifdef Py_BUILD_CORE
11+
PyAPI_FUNC(PyObject*) _PyWarnings_InitWithConfig(const _PyCoreConfig *config);
12+
#endif
1013

1114
PyAPI_FUNC(int) PyErr_WarnEx(
1215
PyObject *category,

‎Modules/getpath.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,13 @@ search_for_exec_prefix(wchar_t *argv0_path, wchar_t *home,
456456
}
457457

458458
static void
459-
calculate_path(_PyMainInterpreterConfig *config)
459+
calculate_path(const _PyMainInterpreterConfig *config)
460460
{
461461
extern wchar_t *Py_GetProgramName(void);
462462

463463
static const wchar_t delimiter[2] = {DELIM, '\0'};
464464
static const wchar_t separator[2] = {SEP, '\0'};
465-
wchar_t *home = Py_GetPythonHome();
465+
wchar_t *home = _Py_GetPythonHomeWithConfig(config);
466466
char *_path = getenv("PATH");
467467
wchar_t *path_buffer = NULL;
468468
wchar_t *path = NULL;
@@ -858,7 +858,7 @@ Py_SetPath(const wchar_t *path)
858858
}
859859

860860
wchar_t *
861-
_Py_GetPathWithConfig(_PyMainInterpreterConfig *config)
861+
_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config)
862862
{
863863
if (!module_search_path) {
864864
calculate_path(config);

‎Modules/main.c‎

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,6 @@ typedef struct {
400400
_PyInitError err;
401401
/* PYTHONWARNINGS env var */
402402
_Py_OptList env_warning_options;
403-
/* PYTHONPATH env var */
404403
int argc;
405404
wchar_t **argv;
406405
} _PyMain;
@@ -1368,47 +1367,98 @@ pymain_set_flags_from_env(_PyMain *pymain)
13681367

13691368

13701369
static int
1371-
pymain_init_pythonpath(_PyMain *pymain)
1370+
pymain_get_env_var_dup(_PyMain *pymain, wchar_t **dest,
1371+
wchar_t *wname, char *name)
13721372
{
13731373
if (Py_IgnoreEnvironmentFlag) {
1374+
*dest = NULL;
13741375
return 0;
13751376
}
13761377

13771378
#ifdef MS_WINDOWS
1378-
wchar_t *path = _wgetenv(L"PYTHONPATH");
1379-
if (!path || path[0] == '\0') {
1379+
wchar_t *var = _wgetenv(wname);
1380+
if (!var || var[0] == '\0') {
1381+
*dest = NULL;
13801382
return 0;
13811383
}
13821384

1383-
wchar_t *path2 = pymain_wstrdup(pymain, path);
1384-
if (path2 == NULL) {
1385+
wchar_t *copy = pymain_wstrdup(pymain, var);
1386+
if (copy == NULL) {
13851387
return -1;
13861388
}
13871389

1388-
pymain->config.module_search_path_env = path2;
1390+
*dest = copy;
13891391
#else
1390-
char *path = pymain_get_env_var("PYTHONPATH");
1391-
if (!path) {
1392+
char *var = getenv(name);
1393+
if (!var || var[0] == '\0') {
1394+
*dest = NULL;
13921395
return 0;
13931396
}
13941397

13951398
size_t len;
1396-
wchar_t *wpath = Py_DecodeLocale(path, &len);
1397-
if (!wpath) {
1399+
wchar_t *wvar = Py_DecodeLocale(var, &len);
1400+
if (!wvar) {
13981401
if (len == (size_t)-2) {
1399-
pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME");
1402+
/* don't set pymain->err */
1403+
return -2;
14001404
}
14011405
else {
14021406
pymain->err = INIT_NO_MEMORY();
1407+
return -1;
14031408
}
1404-
return -1;
14051409
}
1406-
pymain->config.module_search_path_env = wpath;
1410+
*dest = wvar;
14071411
#endif
14081412
return 0;
14091413
}
14101414

14111415

1416+
static int
1417+
pymain_init_pythonpath(_PyMain *pymain)
1418+
{
1419+
wchar_t *path;
1420+
int res = pymain_get_env_var_dup(pymain, &path,
1421+
L"PYTHONPATH", "PYTHONPATH");
1422+
if (res < 0) {
1423+
if (res == -2) {
1424+
pymain->err = _Py_INIT_ERR("failed to decode PYTHONPATH");
1425+
}
1426+
return -1;
1427+
}
1428+
pymain->config.module_search_path_env = path;
1429+
return 0;
1430+
}
1431+
1432+
1433+
static int
1434+
pymain_init_pythonhome(_PyMain *pymain)
1435+
{
1436+
wchar_t *home;
1437+
1438+
home = Py_GetPythonHome();
1439+
if (home) {
1440+
/* Py_SetPythonHome() has been called before Py_Main(),
1441+
use its value */
1442+
pymain->config.pythonhome = pymain_wstrdup(pymain, home);
1443+
if (pymain->config.pythonhome == NULL) {
1444+
return -1;
1445+
}
1446+
return 0;
1447+
}
1448+
1449+
int res = pymain_get_env_var_dup(pymain, &home,
1450+
L"PYTHONHOME", "PYTHONHOME");
1451+
if (res < 0) {
1452+
if (res == -2) {
1453+
pymain->err = _Py_INIT_ERR("failed to decode PYTHONHOME");
1454+
}
1455+
return -1;
1456+
}
1457+
pymain->config.pythonhome = home;
1458+
return 0;
1459+
}
1460+
1461+
14121462
static int
14131463
pymain_parse_envvars(_PyMain *pymain)
14141464
{
@@ -1433,6 +1483,9 @@ pymain_parse_envvars(_PyMain *pymain)
14331483
if (pymain_init_pythonpath(pymain) < 0) {
14341484
return -1;
14351485
}
1486+
if (pymain_init_pythonhome(pymain) < 0) {
1487+
return -1;
1488+
}
14361489

14371490
/* -X options */
14381491
if (pymain_get_xoption(pymain, L"showrefcount")) {

‎PC/getpathp.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,12 +624,12 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
624624

625625

626626
static void
627-
calculate_path(_PyMainInterpreterConfig *config)
627+
calculate_path(const _PyMainInterpreterConfig *config)
628628
{
629629
wchar_t argv0_path[MAXPATHLEN+1];
630630
wchar_t *buf;
631631
size_t bufsz;
632-
wchar_t *pythonhome = Py_GetPythonHome();
632+
wchar_t *pythonhome = _Py_GetPythonHomeWithConfig(config);
633633
wchar_t *envpath = NULL;
634634

635635
int skiphome, skipdefault;
@@ -899,7 +899,7 @@ Py_SetPath(const wchar_t *path)
899899
}
900900

901901
wchar_t *
902-
_Py_GetPathWithConfig(_PyMainInterpreterConfig *config)
902+
_Py_GetPathWithConfig(const _PyMainInterpreterConfig *config)
903903
{
904904
if (!module_search_path) {
905905
calculate_path(config);

‎Python/_warnings.c‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,10 +1185,9 @@ create_filter(PyObject *category, const char *action)
11851185
}
11861186

11871187
static PyObject *
1188-
init_filters(void)
1188+
init_filters(const _PyCoreConfig *config)
11891189
{
1190-
PyInterpreterState *interp = PyThreadState_GET()->interp;
1191-
int dev_mode = interp->core_config.dev_mode;
1190+
int dev_mode = config->dev_mode;
11921191

11931192
Py_ssize_t count = 2;
11941193
if (dev_mode) {
@@ -1264,8 +1263,8 @@ static struct PyModuleDef warningsmodule = {
12641263
};
12651264

12661265

1267-
PyMODINIT_FUNC
1268-
_PyWarnings_Init(void)
1266+
PyObject*
1267+
_PyWarnings_InitWithConfig(const _PyCoreConfig *config)
12691268
{
12701269
PyObject *m;
12711270

@@ -1274,7 +1273,7 @@ _PyWarnings_Init(void)
12741273
return NULL;
12751274

12761275
if (_PyRuntime.warnings.filters == NULL) {
1277-
_PyRuntime.warnings.filters = init_filters();
1276+
_PyRuntime.warnings.filters = init_filters(config);
12781277
if (_PyRuntime.warnings.filters == NULL)
12791278
return NULL;
12801279
}
@@ -1305,3 +1304,12 @@ _PyWarnings_Init(void)
13051304
_PyRuntime.warnings.filters_version = 0;
13061305
return m;
13071306
}
1307+
1308+
1309+
PyMODINIT_FUNC
1310+
_PyWarnings_Init(void)
1311+
{
1312+
PyInterpreterState *interp = PyThreadState_GET()->interp;
1313+
const _PyCoreConfig *config = &interp->core_config;
1314+
return _PyWarnings_InitWithConfig(config);
1315+
}

‎Python/pylifecycle.c‎

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,9 @@ _Py_InitializeCore(const _PyCoreConfig *config)
767767
}
768768

769769
/* Initialize _warnings. */
770-
_PyWarnings_Init();
770+
if (_PyWarnings_InitWithConfig(&interp->core_config) == NULL) {
771+
return _Py_INIT_ERR("can't initialize warnings");
772+
}
771773

772774
/* This call sets up builtin and frozen import support */
773775
if (!interp->core_config._disable_importlib) {
@@ -880,7 +882,7 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
880882
return err;
881883
}
882884

883-
if (config->install_signal_handlers) {
885+
if (interp->config.install_signal_handlers) {
884886
err = initsigs(); /* Signal handling stuff, including initintr() */
885887
if (_Py_INIT_FAILED(err)) {
886888
return err;
@@ -1468,7 +1470,6 @@ Py_GetProgramName(void)
14681470
}
14691471

14701472
static wchar_t *default_home = NULL;
1471-
static wchar_t env_home[MAXPATHLEN+1];
14721473

14731474
void
14741475
Py_SetPythonHome(wchar_t *home)
@@ -1477,20 +1478,40 @@ Py_SetPythonHome(wchar_t *home)
14771478
}
14781479

14791480
wchar_t *
1480-
Py_GetPythonHome(void)
1481+
_Py_GetPythonHomeWithConfig(const _PyMainInterpreterConfig *config)
14811482
{
1482-
wchar_t *home = default_home;
1483-
if (home == NULL && !Py_IgnoreEnvironmentFlag) {
1484-
char* chome = Py_GETENV("PYTHONHOME");
1485-
if (chome) {
1486-
size_t size = Py_ARRAY_LENGTH(env_home);
1487-
size_t r = mbstowcs(env_home, chome, size);
1488-
if (r != (size_t)-1 && r < size)
1489-
home = env_home;
1490-
}
1483+
/* Use a static buffer to avoid heap memory allocation failure.
1484+
Py_GetPythonHome() doesn't allow to report error, and the caller
1485+
doesn't release memory. */
1486+
static wchar_t buffer[MAXPATHLEN+1];
1487+
1488+
if (default_home) {
1489+
return default_home;
1490+
}
14911491

1492+
if (config) {
1493+
return config->pythonhome;
14921494
}
1493-
return home;
1495+
1496+
char *home = Py_GETENV("PYTHONHOME");
1497+
if (!home) {
1498+
return NULL;
1499+
}
1500+
1501+
size_t size = Py_ARRAY_LENGTH(buffer);
1502+
size_t r = mbstowcs(buffer, home, size);
1503+
if (r == (size_t)-1 || r >= size) {
1504+
/* conversion failed or the static buffer is too small */
1505+
return NULL;
1506+
}
1507+
1508+
return buffer;
1509+
}
1510+
1511+
wchar_t *
1512+
Py_GetPythonHome(void)
1513+
{
1514+
return _Py_GetPythonHomeWithConfig(NULL);
14941515
}
14951516

14961517
/* Add the __main__ module */

0 commit comments

Comments
 (0)