bpo-42260: Add _PyInterpreterState_SetConfig() (GH-23158)
* Inline _PyInterpreterState_SetConfig(): replace it with _PyConfig_Copy(). * Add _PyErr_SetFromPyStatus() * Add _PyInterpreterState_GetConfigCopy() * Add a new _PyInterpreterState_SetConfig() function. * Add an unit which gets, modifies, and sets the config.
This commit is contained in:
parent
100964e031
commit
048a35659a
|
@ -128,6 +128,8 @@ PyStatus
|
||||||
|
|
||||||
Initialization error with a message.
|
Initialization error with a message.
|
||||||
|
|
||||||
|
*err_msg* must not be ``NULL``.
|
||||||
|
|
||||||
.. c:function:: PyStatus PyStatus_NoMemory(void)
|
.. c:function:: PyStatus PyStatus_NoMemory(void)
|
||||||
|
|
||||||
Memory allocation failure (out of memory).
|
Memory allocation failure (out of memory).
|
||||||
|
|
|
@ -193,6 +193,36 @@ PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc(
|
||||||
|
|
||||||
PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *interp);
|
PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *interp);
|
||||||
|
|
||||||
|
/* Get a copy of the current interpreter configuration.
|
||||||
|
|
||||||
|
Return 0 on success. Raise an exception and return -1 on error.
|
||||||
|
|
||||||
|
The caller must initialize 'config', using PyConfig_InitPythonConfig()
|
||||||
|
for example.
|
||||||
|
|
||||||
|
Python must be preinitialized to call this method.
|
||||||
|
The caller must hold the GIL. */
|
||||||
|
PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy(
|
||||||
|
struct PyConfig *config);
|
||||||
|
|
||||||
|
/* Set the configuration of the current interpreter.
|
||||||
|
|
||||||
|
This function should be called during or just after the Python
|
||||||
|
initialization.
|
||||||
|
|
||||||
|
Update the sys module with the new configuration. If the sys module was
|
||||||
|
modified directly after the Python initialization, these changes are lost.
|
||||||
|
|
||||||
|
Some configuration like faulthandler or warnoptions can be updated in the
|
||||||
|
configuration, but don't reconfigure Python (don't enable/disable
|
||||||
|
faulthandler and don't reconfigure warnings filters).
|
||||||
|
|
||||||
|
Return 0 on success. Raise an exception and return -1 on error.
|
||||||
|
|
||||||
|
The configuration should come from _PyInterpreterState_GetConfigCopy(). */
|
||||||
|
PyAPI_FUNC(int) _PyInterpreterState_SetConfig(
|
||||||
|
const struct PyConfig *config);
|
||||||
|
|
||||||
// Get the configuration of the currrent interpreter.
|
// Get the configuration of the currrent interpreter.
|
||||||
// The caller must hold the GIL.
|
// The caller must hold the GIL.
|
||||||
PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
|
PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
|
||||||
|
|
|
@ -44,6 +44,8 @@ struct pyruntimestate;
|
||||||
#define _PyStatus_UPDATE_FUNC(err) \
|
#define _PyStatus_UPDATE_FUNC(err) \
|
||||||
do { err.func = _PyStatus_GET_FUNC(); } while (0)
|
do { err.func = _PyStatus_GET_FUNC(); } while (0)
|
||||||
|
|
||||||
|
PyObject* _PyErr_SetFromPyStatus(PyStatus status);
|
||||||
|
|
||||||
/* --- PyWideStringList ------------------------------------------------ */
|
/* --- PyWideStringList ------------------------------------------------ */
|
||||||
|
|
||||||
#define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL}
|
#define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL}
|
||||||
|
|
|
@ -263,13 +263,7 @@ struct _is {
|
||||||
struct ast_state ast;
|
struct ast_state ast;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used by _PyImport_Cleanup() */
|
|
||||||
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);
|
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);
|
||||||
|
|
||||||
extern PyStatus _PyInterpreterState_SetConfig(
|
|
||||||
PyInterpreterState *interp,
|
|
||||||
const PyConfig *config);
|
|
||||||
|
|
||||||
extern void _PyInterpreterState_Clear(PyThreadState *tstate);
|
extern void _PyInterpreterState_Clear(PyThreadState *tstate);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1394,6 +1394,15 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
||||||
self.check_all_configs("test_init_warnoptions", config, preconfig,
|
self.check_all_configs("test_init_warnoptions", config, preconfig,
|
||||||
api=API_PYTHON)
|
api=API_PYTHON)
|
||||||
|
|
||||||
|
def test_init_set_config(self):
|
||||||
|
config = {
|
||||||
|
'_init_main': 0,
|
||||||
|
'bytes_warning': 2,
|
||||||
|
'warnoptions': ['error::BytesWarning'],
|
||||||
|
}
|
||||||
|
self.check_all_configs("test_init_set_config", config,
|
||||||
|
api=API_ISOLATED)
|
||||||
|
|
||||||
def test_get_argc_argv(self):
|
def test_get_argc_argv(self):
|
||||||
self.run_embedded_interpreter("test_get_argc_argv")
|
self.run_embedded_interpreter("test_get_argc_argv")
|
||||||
# ignore output
|
# ignore output
|
||||||
|
|
|
@ -1526,6 +1526,55 @@ static int test_init_warnoptions(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int tune_config(void)
|
||||||
|
{
|
||||||
|
PyConfig config;
|
||||||
|
PyConfig_InitPythonConfig(&config);
|
||||||
|
if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
PyErr_Print();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.bytes_warning = 2;
|
||||||
|
|
||||||
|
if (_PyInterpreterState_SetConfig(&config) < 0) {
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int test_set_config(void)
|
||||||
|
{
|
||||||
|
// Initialize core
|
||||||
|
PyConfig config;
|
||||||
|
PyConfig_InitIsolatedConfig(&config);
|
||||||
|
config_set_string(&config, &config.program_name, PROGRAM_NAME);
|
||||||
|
config._init_main = 0;
|
||||||
|
config.bytes_warning = 0;
|
||||||
|
init_from_config_clear(&config);
|
||||||
|
|
||||||
|
// Tune the configuration using _PyInterpreterState_SetConfig()
|
||||||
|
if (tune_config() < 0) {
|
||||||
|
PyErr_Print();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish initialization: main part
|
||||||
|
PyStatus status = _Py_InitializeMain();
|
||||||
|
if (PyStatus_Exception(status)) {
|
||||||
|
Py_ExitStatusException(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_config();
|
||||||
|
Py_Finalize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void configure_init_main(PyConfig *config)
|
static void configure_init_main(PyConfig *config)
|
||||||
{
|
{
|
||||||
wchar_t* argv[] = {
|
wchar_t* argv[] = {
|
||||||
|
@ -1693,6 +1742,7 @@ static struct TestCase TestCases[] = {
|
||||||
{"test_init_setpath_config", test_init_setpath_config},
|
{"test_init_setpath_config", test_init_setpath_config},
|
||||||
{"test_init_setpythonhome", test_init_setpythonhome},
|
{"test_init_setpythonhome", test_init_setpythonhome},
|
||||||
{"test_init_warnoptions", test_init_warnoptions},
|
{"test_init_warnoptions", test_init_warnoptions},
|
||||||
|
{"test_init_set_config", test_set_config},
|
||||||
{"test_run_main", test_run_main},
|
{"test_run_main", test_run_main},
|
||||||
{"test_get_argc_argv", test_get_argc_argv},
|
{"test_get_argc_argv", test_get_argc_argv},
|
||||||
|
|
||||||
|
|
|
@ -242,8 +242,9 @@ PyStatus PyStatus_Ok(void)
|
||||||
|
|
||||||
PyStatus PyStatus_Error(const char *err_msg)
|
PyStatus PyStatus_Error(const char *err_msg)
|
||||||
{
|
{
|
||||||
|
assert(err_msg != NULL);
|
||||||
return (PyStatus){._type = _PyStatus_TYPE_ERROR,
|
return (PyStatus){._type = _PyStatus_TYPE_ERROR,
|
||||||
.err_msg = err_msg};
|
.err_msg = err_msg};
|
||||||
}
|
}
|
||||||
|
|
||||||
PyStatus PyStatus_NoMemory(void)
|
PyStatus PyStatus_NoMemory(void)
|
||||||
|
@ -262,6 +263,23 @@ int PyStatus_IsExit(PyStatus status)
|
||||||
int PyStatus_Exception(PyStatus status)
|
int PyStatus_Exception(PyStatus status)
|
||||||
{ return _PyStatus_EXCEPTION(status); }
|
{ return _PyStatus_EXCEPTION(status); }
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
_PyErr_SetFromPyStatus(PyStatus status)
|
||||||
|
{
|
||||||
|
if (!_PyStatus_IS_ERROR(status)) {
|
||||||
|
PyErr_Format(PyExc_SystemError,
|
||||||
|
"%s() expects an error PyStatus",
|
||||||
|
_PyStatus_GET_FUNC());
|
||||||
|
}
|
||||||
|
else if (status.func) {
|
||||||
|
PyErr_Format(PyExc_ValueError, "%s: %s", status.func, status.err_msg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Format(PyExc_ValueError, "%s", status.err_msg);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --- PyWideStringList ------------------------------------------------ */
|
/* --- PyWideStringList ------------------------------------------------ */
|
||||||
|
|
||||||
|
|
|
@ -428,6 +428,67 @@ _Py_SetLocaleFromEnv(int category)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
interpreter_set_config(const PyConfig *config)
|
||||||
|
{
|
||||||
|
PyThreadState *tstate = PyThreadState_Get();
|
||||||
|
|
||||||
|
PyStatus status = _PyConfig_Write(config, tstate->interp->runtime);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
_PyErr_SetFromPyStatus(status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _PyConfig_Copy(&tstate->interp->config, config);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
_PyErr_SetFromPyStatus(status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
config = &tstate->interp->config;
|
||||||
|
|
||||||
|
if (config->_install_importlib && _Py_IsMainInterpreter(tstate)) {
|
||||||
|
status = _PyConfig_WritePathConfig(config);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
_PyErr_SetFromPyStatus(status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the sys module for the new configuration
|
||||||
|
if (_PySys_UpdateConfig(tstate) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyInterpreterState_SetConfig(const PyConfig *src_config)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
PyConfig config;
|
||||||
|
PyConfig_InitPythonConfig(&config);
|
||||||
|
PyStatus status = _PyConfig_Copy(&config, src_config);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
_PyErr_SetFromPyStatus(status);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = PyConfig_Read(&config);
|
||||||
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
_PyErr_SetFromPyStatus(status);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = interpreter_set_config(&config);
|
||||||
|
|
||||||
|
done:
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Global initializations. Can be undone by Py_Finalize(). Don't
|
/* Global initializations. Can be undone by Py_Finalize(). Don't
|
||||||
call this twice without an intervening Py_Finalize() call.
|
call this twice without an intervening Py_Finalize() call.
|
||||||
|
|
||||||
|
@ -462,7 +523,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _PyInterpreterState_SetConfig(interp, config);
|
status = _PyConfig_Copy(&interp->config, config);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -550,7 +611,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
|
||||||
return _PyStatus_ERR("can't make main interpreter");
|
return _PyStatus_ERR("can't make main interpreter");
|
||||||
}
|
}
|
||||||
|
|
||||||
PyStatus status = _PyInterpreterState_SetConfig(interp, config);
|
PyStatus status = _PyConfig_Copy(&interp->config, config);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -917,7 +978,7 @@ pyinit_core(_PyRuntimeState *runtime,
|
||||||
}
|
}
|
||||||
|
|
||||||
PyConfig config;
|
PyConfig config;
|
||||||
_PyConfig_InitCompatConfig(&config);
|
PyConfig_InitPythonConfig(&config);
|
||||||
|
|
||||||
status = _PyConfig_Copy(&config, src_config);
|
status = _PyConfig_Copy(&config, src_config);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
|
@ -1835,7 +1896,8 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter)
|
||||||
config = _PyInterpreterState_GetConfig(main_interp);
|
config = _PyInterpreterState_GetConfig(main_interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _PyInterpreterState_SetConfig(interp, config);
|
|
||||||
|
status = _PyConfig_Copy(&interp->config, config);
|
||||||
if (_PyStatus_EXCEPTION(status)) {
|
if (_PyStatus_EXCEPTION(status)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -778,7 +778,7 @@ PyState_RemoveModule(struct PyModuleDef* def)
|
||||||
return PyList_SetItem(interp->modules_by_index, index, Py_None);
|
return PyList_SetItem(interp->modules_by_index, index, Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used by PyImport_Cleanup() */
|
// Used by finalize_modules()
|
||||||
void
|
void
|
||||||
_PyInterpreterState_ClearModules(PyInterpreterState *interp)
|
_PyInterpreterState_ClearModules(PyInterpreterState *interp)
|
||||||
{
|
{
|
||||||
|
@ -1920,11 +1920,17 @@ _PyInterpreterState_GetConfig(PyInterpreterState *interp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyStatus
|
int
|
||||||
_PyInterpreterState_SetConfig(PyInterpreterState *interp,
|
_PyInterpreterState_GetConfigCopy(PyConfig *config)
|
||||||
const PyConfig *config)
|
|
||||||
{
|
{
|
||||||
return _PyConfig_Copy(&interp->config, config);
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
|
||||||
|
PyStatus status = _PyConfig_Copy(config, &interp->config);
|
||||||
|
if (PyStatus_Exception(status)) {
|
||||||
|
_PyErr_SetFromPyStatus(status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue