Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 048a356

Browse filesBrowse files
authored
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.
1 parent 100964e commit 048a356
Copy full SHA for 048a356

File tree

Expand file treeCollapse file tree

9 files changed

+189
-16
lines changed
Filter options
Expand file treeCollapse file tree

9 files changed

+189
-16
lines changed

‎Doc/c-api/init_config.rst

Copy file name to clipboardExpand all lines: Doc/c-api/init_config.rst
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ PyStatus
128128
129129
Initialization error with a message.
130130
131+
*err_msg* must not be ``NULL``.
132+
131133
.. c:function:: PyStatus PyStatus_NoMemory(void)
132134
133135
Memory allocation failure (out of memory).

‎Include/cpython/pystate.h

Copy file name to clipboardExpand all lines: Include/cpython/pystate.h
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,36 @@ PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc(
193193

194194
PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *interp);
195195

196+
/* Get a copy of the current interpreter configuration.
197+
198+
Return 0 on success. Raise an exception and return -1 on error.
199+
200+
The caller must initialize 'config', using PyConfig_InitPythonConfig()
201+
for example.
202+
203+
Python must be preinitialized to call this method.
204+
The caller must hold the GIL. */
205+
PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy(
206+
struct PyConfig *config);
207+
208+
/* Set the configuration of the current interpreter.
209+
210+
This function should be called during or just after the Python
211+
initialization.
212+
213+
Update the sys module with the new configuration. If the sys module was
214+
modified directly after the Python initialization, these changes are lost.
215+
216+
Some configuration like faulthandler or warnoptions can be updated in the
217+
configuration, but don't reconfigure Python (don't enable/disable
218+
faulthandler and don't reconfigure warnings filters).
219+
220+
Return 0 on success. Raise an exception and return -1 on error.
221+
222+
The configuration should come from _PyInterpreterState_GetConfigCopy(). */
223+
PyAPI_FUNC(int) _PyInterpreterState_SetConfig(
224+
const struct PyConfig *config);
225+
196226
// Get the configuration of the currrent interpreter.
197227
// The caller must hold the GIL.
198228
PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);

‎Include/internal/pycore_initconfig.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_initconfig.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct pyruntimestate;
4444
#define _PyStatus_UPDATE_FUNC(err) \
4545
do { err.func = _PyStatus_GET_FUNC(); } while (0)
4646

47+
PyObject* _PyErr_SetFromPyStatus(PyStatus status);
48+
4749
/* --- PyWideStringList ------------------------------------------------ */
4850

4951
#define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL}

‎Include/internal/pycore_interp.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_interp.h
-6Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,7 @@ struct _is {
263263
struct ast_state ast;
264264
};
265265

266-
/* Used by _PyImport_Cleanup() */
267266
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);
268-
269-
extern PyStatus _PyInterpreterState_SetConfig(
270-
PyInterpreterState *interp,
271-
const PyConfig *config);
272-
273267
extern void _PyInterpreterState_Clear(PyThreadState *tstate);
274268

275269

‎Lib/test/test_embed.py

Copy file name to clipboardExpand all lines: Lib/test/test_embed.py
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,15 @@ def test_init_warnoptions(self):
13941394
self.check_all_configs("test_init_warnoptions", config, preconfig,
13951395
api=API_PYTHON)
13961396

1397+
def test_init_set_config(self):
1398+
config = {
1399+
'_init_main': 0,
1400+
'bytes_warning': 2,
1401+
'warnoptions': ['error::BytesWarning'],
1402+
}
1403+
self.check_all_configs("test_init_set_config", config,
1404+
api=API_ISOLATED)
1405+
13971406
def test_get_argc_argv(self):
13981407
self.run_embedded_interpreter("test_get_argc_argv")
13991408
# ignore output

‎Programs/_testembed.c

Copy file name to clipboardExpand all lines: Programs/_testembed.c
+50Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,55 @@ static int test_init_warnoptions(void)
15261526
}
15271527

15281528

1529+
static int tune_config(void)
1530+
{
1531+
PyConfig config;
1532+
PyConfig_InitPythonConfig(&config);
1533+
if (_PyInterpreterState_GetConfigCopy(&config) < 0) {
1534+
PyConfig_Clear(&config);
1535+
PyErr_Print();
1536+
return -1;
1537+
}
1538+
1539+
config.bytes_warning = 2;
1540+
1541+
if (_PyInterpreterState_SetConfig(&config) < 0) {
1542+
PyConfig_Clear(&config);
1543+
return -1;
1544+
}
1545+
PyConfig_Clear(&config);
1546+
return 0;
1547+
}
1548+
1549+
1550+
static int test_set_config(void)
1551+
{
1552+
// Initialize core
1553+
PyConfig config;
1554+
PyConfig_InitIsolatedConfig(&config);
1555+
config_set_string(&config, &config.program_name, PROGRAM_NAME);
1556+
config._init_main = 0;
1557+
config.bytes_warning = 0;
1558+
init_from_config_clear(&config);
1559+
1560+
// Tune the configuration using _PyInterpreterState_SetConfig()
1561+
if (tune_config() < 0) {
1562+
PyErr_Print();
1563+
return 1;
1564+
}
1565+
1566+
// Finish initialization: main part
1567+
PyStatus status = _Py_InitializeMain();
1568+
if (PyStatus_Exception(status)) {
1569+
Py_ExitStatusException(status);
1570+
}
1571+
1572+
dump_config();
1573+
Py_Finalize();
1574+
return 0;
1575+
}
1576+
1577+
15291578
static void configure_init_main(PyConfig *config)
15301579
{
15311580
wchar_t* argv[] = {
@@ -1693,6 +1742,7 @@ static struct TestCase TestCases[] = {
16931742
{"test_init_setpath_config", test_init_setpath_config},
16941743
{"test_init_setpythonhome", test_init_setpythonhome},
16951744
{"test_init_warnoptions", test_init_warnoptions},
1745+
{"test_init_set_config", test_set_config},
16961746
{"test_run_main", test_run_main},
16971747
{"test_get_argc_argv", test_get_argc_argv},
16981748

‎Python/initconfig.c

Copy file name to clipboardExpand all lines: Python/initconfig.c
+19-1Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,9 @@ PyStatus PyStatus_Ok(void)
242242

243243
PyStatus PyStatus_Error(const char *err_msg)
244244
{
245+
assert(err_msg != NULL);
245246
return (PyStatus){._type = _PyStatus_TYPE_ERROR,
246-
.err_msg = err_msg};
247+
.err_msg = err_msg};
247248
}
248249

249250
PyStatus PyStatus_NoMemory(void)
@@ -262,6 +263,23 @@ int PyStatus_IsExit(PyStatus status)
262263
int PyStatus_Exception(PyStatus status)
263264
{ return _PyStatus_EXCEPTION(status); }
264265

266+
PyObject*
267+
_PyErr_SetFromPyStatus(PyStatus status)
268+
{
269+
if (!_PyStatus_IS_ERROR(status)) {
270+
PyErr_Format(PyExc_SystemError,
271+
"%s() expects an error PyStatus",
272+
_PyStatus_GET_FUNC());
273+
}
274+
else if (status.func) {
275+
PyErr_Format(PyExc_ValueError, "%s: %s", status.func, status.err_msg);
276+
}
277+
else {
278+
PyErr_Format(PyExc_ValueError, "%s", status.err_msg);
279+
}
280+
return NULL;
281+
}
282+
265283

266284
/* --- PyWideStringList ------------------------------------------------ */
267285

‎Python/pylifecycle.c

Copy file name to clipboardExpand all lines: Python/pylifecycle.c
+66-4Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,67 @@ _Py_SetLocaleFromEnv(int category)
428428
}
429429

430430

431+
static int
432+
interpreter_set_config(const PyConfig *config)
433+
{
434+
PyThreadState *tstate = PyThreadState_Get();
435+
436+
PyStatus status = _PyConfig_Write(config, tstate->interp->runtime);
437+
if (_PyStatus_EXCEPTION(status)) {
438+
_PyErr_SetFromPyStatus(status);
439+
return -1;
440+
}
441+
442+
status = _PyConfig_Copy(&tstate->interp->config, config);
443+
if (_PyStatus_EXCEPTION(status)) {
444+
_PyErr_SetFromPyStatus(status);
445+
return -1;
446+
}
447+
config = &tstate->interp->config;
448+
449+
if (config->_install_importlib && _Py_IsMainInterpreter(tstate)) {
450+
status = _PyConfig_WritePathConfig(config);
451+
if (_PyStatus_EXCEPTION(status)) {
452+
_PyErr_SetFromPyStatus(status);
453+
return -1;
454+
}
455+
}
456+
457+
// Update the sys module for the new configuration
458+
if (_PySys_UpdateConfig(tstate) < 0) {
459+
return -1;
460+
}
461+
return 0;
462+
}
463+
464+
465+
int
466+
_PyInterpreterState_SetConfig(const PyConfig *src_config)
467+
{
468+
int res = -1;
469+
470+
PyConfig config;
471+
PyConfig_InitPythonConfig(&config);
472+
PyStatus status = _PyConfig_Copy(&config, src_config);
473+
if (_PyStatus_EXCEPTION(status)) {
474+
_PyErr_SetFromPyStatus(status);
475+
goto done;
476+
}
477+
478+
status = PyConfig_Read(&config);
479+
if (_PyStatus_EXCEPTION(status)) {
480+
_PyErr_SetFromPyStatus(status);
481+
goto done;
482+
}
483+
484+
res = interpreter_set_config(&config);
485+
486+
done:
487+
PyConfig_Clear(&config);
488+
return res;
489+
}
490+
491+
431492
/* Global initializations. Can be undone by Py_Finalize(). Don't
432493
call this twice without an intervening Py_Finalize() call.
433494
@@ -462,7 +523,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime,
462523
return status;
463524
}
464525

465-
status = _PyInterpreterState_SetConfig(interp, config);
526+
status = _PyConfig_Copy(&interp->config, config);
466527
if (_PyStatus_EXCEPTION(status)) {
467528
return status;
468529
}
@@ -550,7 +611,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
550611
return _PyStatus_ERR("can't make main interpreter");
551612
}
552613

553-
PyStatus status = _PyInterpreterState_SetConfig(interp, config);
614+
PyStatus status = _PyConfig_Copy(&interp->config, config);
554615
if (_PyStatus_EXCEPTION(status)) {
555616
return status;
556617
}
@@ -917,7 +978,7 @@ pyinit_core(_PyRuntimeState *runtime,
917978
}
918979

919980
PyConfig config;
920-
_PyConfig_InitCompatConfig(&config);
981+
PyConfig_InitPythonConfig(&config);
921982

922983
status = _PyConfig_Copy(&config, src_config);
923984
if (_PyStatus_EXCEPTION(status)) {
@@ -1835,7 +1896,8 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter)
18351896
config = _PyInterpreterState_GetConfig(main_interp);
18361897
}
18371898

1838-
status = _PyInterpreterState_SetConfig(interp, config);
1899+
1900+
status = _PyConfig_Copy(&interp->config, config);
18391901
if (_PyStatus_EXCEPTION(status)) {
18401902
goto error;
18411903
}

‎Python/pystate.c

Copy file name to clipboardExpand all lines: Python/pystate.c
+11-5Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ PyState_RemoveModule(struct PyModuleDef* def)
778778
return PyList_SetItem(interp->modules_by_index, index, Py_None);
779779
}
780780

781-
/* Used by PyImport_Cleanup() */
781+
// Used by finalize_modules()
782782
void
783783
_PyInterpreterState_ClearModules(PyInterpreterState *interp)
784784
{
@@ -1920,11 +1920,17 @@ _PyInterpreterState_GetConfig(PyInterpreterState *interp)
19201920
}
19211921

19221922

1923-
PyStatus
1924-
_PyInterpreterState_SetConfig(PyInterpreterState *interp,
1925-
const PyConfig *config)
1923+
int
1924+
_PyInterpreterState_GetConfigCopy(PyConfig *config)
19261925
{
1927-
return _PyConfig_Copy(&interp->config, config);
1926+
PyInterpreterState *interp = PyInterpreterState_Get();
1927+
1928+
PyStatus status = _PyConfig_Copy(config, &interp->config);
1929+
if (PyStatus_Exception(status)) {
1930+
_PyErr_SetFromPyStatus(status);
1931+
return -1;
1932+
}
1933+
return 0;
19281934
}
19291935

19301936

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.