Skip to content

Commit da27341

Browse files
authored
bpo-32030: Add _PyCoreConfig_Copy() (#4874)
Each interpreter now has its core_config and main_config copy: * Add _PyCoreConfig_Copy() and _PyMainInterpreterConfig_Copy() * Move _PyCoreConfig_Read(), _PyCoreConfig_Clear() and _PyMainInterpreterConfig_Clear() from Python/pylifecycle.c to Modules/main.c * Fix _Py_InitializeEx_Private(): call _PyCoreConfig_ReadEnv() before _Py_InitializeCore()
1 parent 358e5e1 commit da27341

File tree

4 files changed

+197
-84
lines changed

4 files changed

+197
-84
lines changed

Include/pylifecycle.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,15 @@ PyAPI_FUNC(int) _Py_IsCoreInitialized(void);
5757
PyAPI_FUNC(_PyInitError) _PyCoreConfig_ReadEnv(_PyCoreConfig *);
5858
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *);
5959
PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
60+
PyAPI_FUNC(int) _PyCoreConfig_Copy(
61+
_PyCoreConfig *config,
62+
const _PyCoreConfig *config2);
6063

6164
PyAPI_FUNC(_PyInitError) _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *, _PyCoreConfig *);
6265
PyAPI_FUNC(void) _PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *);
66+
PyAPI_FUNC(int) _PyMainInterpreterConfig_Copy(
67+
_PyMainInterpreterConfig *config,
68+
const _PyMainInterpreterConfig *config2);
6369

6470
PyAPI_FUNC(_PyInitError) _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *);
6571
#endif

Modules/main.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,6 +1914,154 @@ pymain_parse_cmdline_envvars(_PyMain *pymain)
19141914
}
19151915

19161916

1917+
/* Read configuration settings from standard locations
1918+
*
1919+
* This function doesn't make any changes to the interpreter state - it
1920+
* merely populates any missing configuration settings. This allows an
1921+
* embedding application to completely override a config option by
1922+
* setting it before calling this function, or else modify the default
1923+
* setting before passing the fully populated config to Py_EndInitialization.
1924+
*
1925+
* More advanced selective initialization tricks are possible by calling
1926+
* this function multiple times with various preconfigured settings.
1927+
*/
1928+
1929+
_PyInitError
1930+
_PyCoreConfig_Read(_PyCoreConfig *config)
1931+
{
1932+
if (config->program_name == NULL) {
1933+
#ifdef MS_WINDOWS
1934+
const wchar_t *program_name = L"python";
1935+
#else
1936+
const wchar_t *program_name = L"python3";
1937+
#endif
1938+
config->program_name = _PyMem_RawWcsdup(program_name);
1939+
if (config->program_name == NULL) {
1940+
return _Py_INIT_NO_MEMORY();
1941+
}
1942+
}
1943+
1944+
return _Py_INIT_OK();
1945+
}
1946+
1947+
1948+
void
1949+
_PyCoreConfig_Clear(_PyCoreConfig *config)
1950+
{
1951+
#define CLEAR(ATTR) \
1952+
do { \
1953+
PyMem_RawFree(ATTR); \
1954+
ATTR = NULL; \
1955+
} while (0)
1956+
1957+
CLEAR(config->module_search_path_env);
1958+
CLEAR(config->home);
1959+
CLEAR(config->program_name);
1960+
#undef CLEAR
1961+
}
1962+
1963+
1964+
int
1965+
_PyCoreConfig_Copy(_PyCoreConfig *config, const _PyCoreConfig *config2)
1966+
{
1967+
_PyCoreConfig_Clear(config);
1968+
1969+
#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
1970+
COPY_ATTR(ignore_environment);
1971+
COPY_ATTR(use_hash_seed);
1972+
COPY_ATTR(hash_seed);
1973+
COPY_ATTR(_disable_importlib);
1974+
COPY_ATTR(allocator);
1975+
COPY_ATTR(dev_mode);
1976+
COPY_ATTR(faulthandler);
1977+
COPY_ATTR(tracemalloc);
1978+
COPY_ATTR(import_time);
1979+
COPY_ATTR(show_ref_count);
1980+
COPY_ATTR(show_alloc_count);
1981+
COPY_ATTR(dump_refs);
1982+
COPY_ATTR(malloc_stats);
1983+
COPY_ATTR(utf8_mode);
1984+
#undef COPY_ATTR
1985+
1986+
#define COPY_STR_ATTR(ATTR) \
1987+
do { \
1988+
if (config2->ATTR != NULL) { \
1989+
config->ATTR = _PyMem_RawWcsdup(config2->ATTR); \
1990+
if (config->ATTR == NULL) { \
1991+
return -1; \
1992+
} \
1993+
} \
1994+
} while (0)
1995+
1996+
COPY_STR_ATTR(module_search_path_env);
1997+
COPY_STR_ATTR(home);
1998+
COPY_STR_ATTR(program_name);
1999+
#undef COPY_STR_ATTR
2000+
return 0;
2001+
}
2002+
2003+
2004+
void
2005+
_PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config)
2006+
{
2007+
Py_CLEAR(config->argv);
2008+
Py_CLEAR(config->module_search_path);
2009+
Py_CLEAR(config->warnoptions);
2010+
Py_CLEAR(config->xoptions);
2011+
}
2012+
2013+
2014+
static PyObject*
2015+
config_copy_attr(PyObject *obj)
2016+
{
2017+
if (PyUnicode_Check(obj)) {
2018+
Py_INCREF(obj);
2019+
return obj;
2020+
}
2021+
else if (PyList_Check(obj)) {
2022+
return PyList_GetSlice(obj, 0, Py_SIZE(obj));
2023+
}
2024+
else if (PyDict_Check(obj)) {
2025+
/* The dict type is used for xoptions. Make the assumption that keys
2026+
and values are immutables */
2027+
return PyDict_Copy(obj);
2028+
}
2029+
else {
2030+
PyErr_Format(PyExc_TypeError,
2031+
"cannot copy config attribute of type %.200s",
2032+
Py_TYPE(obj)->tp_name);
2033+
return NULL;
2034+
}
2035+
}
2036+
2037+
2038+
int
2039+
_PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config,
2040+
const _PyMainInterpreterConfig *config2)
2041+
{
2042+
_PyMainInterpreterConfig_Clear(config);
2043+
2044+
#define COPY_ATTR(ATTR) \
2045+
do { \
2046+
if (config2->ATTR != NULL) { \
2047+
config->ATTR = config_copy_attr(config2->ATTR); \
2048+
if (config->ATTR == NULL) { \
2049+
return -1; \
2050+
} \
2051+
} \
2052+
} while (0)
2053+
2054+
COPY_ATTR(argv);
2055+
COPY_ATTR(module_search_path);
2056+
COPY_ATTR(warnoptions);
2057+
COPY_ATTR(xoptions);
2058+
#undef COPY_ATTR
2059+
return 0;
2060+
}
2061+
2062+
2063+
2064+
19172065
static PyObject *
19182066
config_create_path_list(const wchar_t *path, wchar_t delim)
19192067
{

0 commit comments

Comments
 (0)