Skip to content

Commit 177a41a

Browse files
authored
bpo-34725: Adds _Py_SetProgramFullPath so embedders may override sys.executable (GH-9860)
1 parent 689d555 commit 177a41a

File tree

6 files changed

+74
-33
lines changed

6 files changed

+74
-33
lines changed

Include/internal/pycore_pathconfig.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ typedef struct _PyPathConfig {
2626
/* Full path to the Python program */
2727
wchar_t *program_full_path;
2828
wchar_t *prefix;
29+
wchar_t *exec_prefix;
2930
#ifdef MS_WINDOWS
3031
wchar_t *dll_path;
31-
#else
32-
wchar_t *exec_prefix;
3332
#endif
3433
/* Set by Py_SetPath(), or computed by _PyPathConfig_Init() */
3534
wchar_t *module_search_path;

Include/pylifecycle.h

+11-7
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@
77
extern "C" {
88
#endif
99

10-
PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *);
11-
PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
12-
13-
PyAPI_FUNC(void) Py_SetPythonHome(const wchar_t *);
14-
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
15-
1610
#ifndef Py_LIMITED_API
1711
/* Only used by applications that embed the interpreter and need to
1812
* override the standard encoding determination mechanism
@@ -83,8 +77,18 @@ PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *);
8377
/* Bootstrap __main__ (defined in Modules/main.c) */
8478
PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
8579

86-
/* In getpath.c */
80+
/* In pathconfig.c */
81+
PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *);
82+
PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
83+
84+
PyAPI_FUNC(void) Py_SetPythonHome(const wchar_t *);
85+
PyAPI_FUNC(wchar_t *) Py_GetPythonHome(void);
86+
87+
#ifndef Py_LIMITED_API
88+
PyAPI_FUNC(void) _Py_SetProgramFullPath(const wchar_t *);
89+
#endif
8790
PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void);
91+
8892
PyAPI_FUNC(wchar_t *) Py_GetPrefix(void);
8993
PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
9094
PyAPI_FUNC(wchar_t *) Py_GetPath(void);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Adds _Py_SetProgramFullPath so embedders may override sys.executable

PC/getpathp.c

+4
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,10 @@ calculate_path_impl(const _PyCoreConfig *core_config,
982982
if (config->prefix == NULL) {
983983
return _Py_INIT_NO_MEMORY();
984984
}
985+
config->exec_prefix = _PyMem_RawWcsdup(prefix);
986+
if (config->exec_prefix == NULL) {
987+
return _Py_INIT_NO_MEMORY();
988+
}
985989

986990
return _Py_INIT_OK();
987991
}

Python/coreconfig.c

+24
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,23 @@ config_init_program_name(_PyCoreConfig *config)
662662
return _Py_INIT_OK();
663663
}
664664

665+
static _PyInitError
666+
config_init_executable(_PyCoreConfig *config)
667+
{
668+
assert(config->executable == NULL);
669+
670+
/* If Py_SetProgramFullPath() was called, use its value */
671+
const wchar_t *program_full_path = _Py_path_config.program_full_path;
672+
if (program_full_path != NULL) {
673+
config->executable = _PyMem_RawWcsdup(program_full_path);
674+
if (config->executable == NULL) {
675+
return _Py_INIT_NO_MEMORY();
676+
}
677+
return _Py_INIT_OK();
678+
}
679+
680+
return _Py_INIT_OK();
681+
}
665682

666683
static const wchar_t*
667684
config_get_xoption(const _PyCoreConfig *config, wchar_t *name)
@@ -1370,6 +1387,13 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
13701387
}
13711388
}
13721389

1390+
if (config->executable == NULL) {
1391+
err = config_init_executable(config);
1392+
if (_Py_INIT_FAILED(err)) {
1393+
return err;
1394+
}
1395+
}
1396+
13731397
if (config->utf8_mode < 0 || config->coerce_c_locale < 0) {
13741398
config_init_locale(config);
13751399
}

Python/pathconfig.c

+33-24
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ _PyPathConfig_Clear(_PyPathConfig *config)
4949

5050
CLEAR(config->prefix);
5151
CLEAR(config->program_full_path);
52+
CLEAR(config->exec_prefix);
5253
#ifdef MS_WINDOWS
5354
CLEAR(config->dll_path);
54-
#else
55-
CLEAR(config->exec_prefix);
5655
#endif
5756
CLEAR(config->module_search_path);
5857
CLEAR(config->home);
@@ -74,8 +73,8 @@ _PyPathConfig_Calculate(_PyPathConfig *path_config,
7473
PyMemAllocatorEx old_alloc;
7574
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
7675

77-
/* Calculate program_full_path, prefix, exec_prefix (Unix)
78-
or dll_path (Windows), and module_search_path */
76+
/* Calculate program_full_path, prefix, exec_prefix,
77+
dll_path (Windows), and module_search_path */
7978
err = _PyPathConfig_Calculate_impl(&new_config, core_config);
8079
if (_Py_INIT_FAILED(err)) {
8180
goto err;
@@ -126,10 +125,9 @@ _PyPathConfig_SetGlobal(const _PyPathConfig *config)
126125

127126
COPY_ATTR(program_full_path);
128127
COPY_ATTR(prefix);
128+
COPY_ATTR(exec_prefix);
129129
#ifdef MS_WINDOWS
130130
COPY_ATTR(dll_path);
131-
#else
132-
COPY_ATTR(exec_prefix);
133131
#endif
134132
COPY_ATTR(module_search_path);
135133
COPY_ATTR(program_name);
@@ -208,12 +206,11 @@ _PyCoreConfig_SetPathConfig(const _PyCoreConfig *core_config)
208206
if (copy_wstr(&path_config.prefix, core_config->prefix) < 0) {
209207
goto no_memory;
210208
}
211-
#ifdef MS_WINDOWS
212-
if (copy_wstr(&path_config.dll_path, core_config->dll_path) < 0) {
209+
if (copy_wstr(&path_config.exec_prefix, core_config->exec_prefix) < 0) {
213210
goto no_memory;
214211
}
215-
#else
216-
if (copy_wstr(&path_config.exec_prefix, core_config->exec_prefix) < 0) {
212+
#ifdef MS_WINDOWS
213+
if (copy_wstr(&path_config.dll_path, core_config->dll_path) < 0) {
217214
goto no_memory;
218215
}
219216
#endif
@@ -317,12 +314,8 @@ _PyCoreConfig_CalculatePathConfig(_PyCoreConfig *config)
317314
}
318315

319316
if (config->exec_prefix == NULL) {
320-
#ifdef MS_WINDOWS
321-
wchar_t *exec_prefix = path_config.prefix;
322-
#else
323-
wchar_t *exec_prefix = path_config.exec_prefix;
324-
#endif
325-
if (copy_wstr(&config->exec_prefix, exec_prefix) < 0) {
317+
if (copy_wstr(&config->exec_prefix,
318+
path_config.exec_prefix) < 0) {
326319
goto no_memory;
327320
}
328321
}
@@ -379,7 +372,8 @@ _PyCoreConfig_InitPathConfig(_PyCoreConfig *config)
379372
}
380373

381374
if (config->base_exec_prefix == NULL) {
382-
if (copy_wstr(&config->base_exec_prefix, config->exec_prefix) < 0) {
375+
if (copy_wstr(&config->base_exec_prefix,
376+
config->exec_prefix) < 0) {
383377
return _Py_INIT_NO_MEMORY();
384378
}
385379
}
@@ -435,12 +429,11 @@ Py_SetPath(const wchar_t *path)
435429
int alloc_error = (new_config.program_full_path == NULL);
436430
new_config.prefix = _PyMem_RawWcsdup(L"");
437431
alloc_error |= (new_config.prefix == NULL);
432+
new_config.exec_prefix = _PyMem_RawWcsdup(L"");
433+
alloc_error |= (new_config.exec_prefix == NULL);
438434
#ifdef MS_WINDOWS
439435
new_config.dll_path = _PyMem_RawWcsdup(L"");
440436
alloc_error |= (new_config.dll_path == NULL);
441-
#else
442-
new_config.exec_prefix = _PyMem_RawWcsdup(L"");
443-
alloc_error |= (new_config.exec_prefix == NULL);
444437
#endif
445438
new_config.module_search_path = _PyMem_RawWcsdup(path);
446439
alloc_error |= (new_config.module_search_path == NULL);
@@ -503,6 +496,26 @@ Py_SetProgramName(const wchar_t *program_name)
503496
}
504497
}
505498

499+
void
500+
_Py_SetProgramFullPath(const wchar_t *program_full_path)
501+
{
502+
if (program_full_path == NULL || program_full_path[0] == L'\0') {
503+
return;
504+
}
505+
506+
PyMemAllocatorEx old_alloc;
507+
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
508+
509+
PyMem_RawFree(_Py_path_config.program_full_path);
510+
_Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path);
511+
512+
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
513+
514+
if (_Py_path_config.program_full_path == NULL) {
515+
Py_FatalError("_Py_SetProgramFullPath() failed: out of memory");
516+
}
517+
}
518+
506519

507520
wchar_t *
508521
Py_GetPath(void)
@@ -523,12 +536,8 @@ Py_GetPrefix(void)
523536
wchar_t *
524537
Py_GetExecPrefix(void)
525538
{
526-
#ifdef MS_WINDOWS
527-
return Py_GetPrefix();
528-
#else
529539
pathconfig_global_init();
530540
return _Py_path_config.exec_prefix;
531-
#endif
532541
}
533542

534543

0 commit comments

Comments
 (0)