Skip to content

Commit 582a0c1

Browse files
committed
gh-107954: Add PyInitConfig C API
Add PyInitConfig functions: * PyInitConfig_Python_New() * PyInitConfig_Isolated_New() * PyInitConfig_Free(config) * PyInitConfig_SetInt(config, key, value) * PyInitConfig_SetStr(config, key, value) * PyInitConfig_SetWStr(config, key, value) * PyInitConfig_SetStrList(config, key, length, items) * PyInitConfig_SetWStrList(config, key, length, items) * PyInitConfig_Exception(config) * PyInitConfig_GetError(config, &err_msg) * PyInitConfig_GetExitCode(config, &exitcode) Add also functions using it: * Py_InitializeFromInitConfig(config) * Py_ExitWithInitConfig(config) Add these functions to the limited C API. Changes: * Add Doc/c-api/config.rst. * Add Include/initconfig.h header. * Add Modules/_testcapi/config.c * Add Lib/test/test_capi/test_config.py.
1 parent fe9991b commit 582a0c1

20 files changed

+865
-59
lines changed

Doc/c-api/config.rst

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
.. highlight:: c
2+
3+
.. _config-c-api:
4+
5+
********************
6+
Python Configuration
7+
********************
8+
9+
.. versionadded:: 3.13
10+
11+
API part of the limited C API version 3.13 to configure the Python
12+
initialization and get the Python runtime configuration.
13+
14+
See also :ref:`Python Initialization Configuration <init-config>`.
15+
16+
17+
Initialize Python
18+
=================
19+
20+
Configuration to customize Python initialization. Configuration option names
21+
are names of a :c:type:`PyConfig` members.
22+
23+
.. c:struct:: PyInitConfig
24+
25+
Opaque structure to configure the Python initialization.
26+
27+
28+
.. c:function:: PyInitConfig* PyInitConfig_Python_New(void)
29+
30+
Create a new initialization configuration using :ref:`Python Configuration
31+
<init-python-config>` default values.
32+
33+
It must be freed by :c:func:`PyInitConfig_Free`.
34+
35+
Return ``NULL`` on memory allocation failure.
36+
37+
38+
.. c:function:: PyInitConfig* PyInitConfig_Isolated_New(void)
39+
40+
Similar to :c:func:`PyInitConfig_Python_New`, but use :ref:`Isolated
41+
Configuration <init-isolated-conf>` default values.
42+
43+
44+
.. c:function:: void PyInitConfig_Free(PyInitConfig *config)
45+
46+
Free memory of an initialization configuration.
47+
48+
49+
.. c:function:: int PyInitConfig_SetInt(PyInitConfig *config, const char *name, int64_t value)
50+
51+
Set an integer configuration option.
52+
53+
* Return ``0`` on success.
54+
* Set an error in *config* and return ``-1`` on error.
55+
56+
57+
.. c:function:: int PyInitConfig_SetStr(PyInitConfig *config, const char *name, const char *value)
58+
59+
Set a string configuration option from a null-terminated bytes string.
60+
61+
The bytes string is decoded by :c:func:`Py_DecodeLocale`. If Python is not
62+
yet preinitialized, this function preinitializes it to ensure that encodings
63+
are properly configured.
64+
65+
* Return ``0`` on success.
66+
* Set an error in *config* and return ``-1`` on error.
67+
68+
69+
.. c:function:: int PyInitConfig_SetWStr(PyInitConfig *config, const char *name, const wchar_t *value)
70+
71+
Set a string configuration option from a null-terminated wide string.
72+
73+
If Python is not yet preinitialized, this function preinitializes it.
74+
75+
* Return ``0`` on success.
76+
* Set an error in *config* and return ``-1`` on error.
77+
78+
79+
.. c:function:: int PyInitConfig_SetStrList(PyInitConfig *config, const char *name, size_t length, char * const *items)
80+
81+
Set a string list configuration option from an array of null-terminated
82+
bytes strings.
83+
84+
The bytes string is decoded by :c:func:`Py_DecodeLocale`. If Python is not
85+
yet preinitialized, this function preinitializes it to ensure that encodings
86+
are properly configured.
87+
88+
* Return ``0`` on success.
89+
* Set an error in *config* and return ``-1`` on error.
90+
91+
92+
.. c:function:: int PyInitConfig_SetWStrList(PyInitConfig *config, const char *name, size_t length, wchar_t * const *items)
93+
94+
Set a string list configuration option from a null-terminated wide strings.
95+
96+
If Python is not yet preinitialized, this function preinitializes it.
97+
98+
* Return ``0`` on success.
99+
* Set an error in *config* and return ``-1`` on error.
100+
101+
102+
.. c:function:: int Py_InitializeFromInitConfig(PyInitConfig *config)
103+
104+
Initialize Python from the initialization configuration.
105+
106+
* Return ``0`` on success.
107+
* Return ``-1`` if an error was set or if an exit code was set.
108+
109+
110+
Error handling
111+
==============
112+
113+
.. c:function:: int PyInitConfig_Exception(PyInitConfig* config)
114+
115+
Check if an exception is set in *config*:
116+
117+
* Return non-zero if an error was set or if an exit code was set.
118+
* Return zero otherwise.
119+
120+
121+
.. c:function:: int PyInitConfig_GetError(PyInitConfig* config, const char **err_msg)
122+
123+
Get the *config* error message.
124+
125+
* Set *\*err_msg* and return ``1`` if an error is set.
126+
* Set *\*err_msg* to ``NULL`` and return ``0`` otherwise.
127+
128+
129+
.. c:function:: int PyInitConfig_GetExitCode(PyInitConfig* config, int *exitcode)
130+
131+
Get the *config* exit code.
132+
133+
* Set *\*exitcode* and return ``1`` if an exit code is set.
134+
* Return ``0`` otherwise.
135+
136+
137+
.. c:function:: void Py_ExitWithInitConfig(PyInitConfig *config)
138+
139+
Exit Python and free memory of a initialization configuration.
140+
141+
If an error message is set, display the error message.
142+
143+
If an exit code is set, use it to exit the process.
144+
145+
The function does not return.
146+
147+
148+
Example
149+
-------
150+
151+
Code::
152+
153+
void init_python(void)
154+
{
155+
PyInitConfig *config = PyInitConfig_Python_New();
156+
if (config == NULL) {
157+
printf("Init allocation error\n");
158+
return;
159+
}
160+
161+
if (PyInitConfig_SetInt(config, "dev_mode", 1) < 0) {
162+
goto error;
163+
}
164+
165+
// Set a list of wide strings (argv)
166+
wchar_t *argv[] = {L"my_program"", L"-c", L"pass"};
167+
if (PyInitConfig_SetWStrList(config, "argv",
168+
Py_ARRAY_LENGTH(argv), argv) < 0) {
169+
goto error;
170+
}
171+
172+
// Set a wide string (program_name)
173+
if (PyInitConfig_SetWStr(config, "program_name", L"my_program") < 0) {
174+
goto error;
175+
}
176+
177+
// Set a list of bytes strings (xoptions)
178+
char* xoptions[] = {"faulthandler"};
179+
if (PyInitConfig_SetStrList(config, "xoptions",
180+
Py_ARRAY_LENGTH(xoptions), xoptions) < 0) {
181+
goto error;
182+
}
183+
184+
if (Py_InitializeFromInitConfig(config) < 0) {
185+
Py_ExitWithInitConfig(config);
186+
}
187+
PyInitConfig_Free(config);
188+
}

Doc/c-api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ document the API functions in detail.
2222
concrete.rst
2323
init.rst
2424
init_config.rst
25+
config.rst
2526
memory.rst
2627
objimpl.rst
2728
apiabiversion.rst

Doc/c-api/init.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
Initialization, Finalization, and Threads
88
*****************************************
99

10-
See also :ref:`Python Initialization Configuration <init-config>`.
10+
See also the :ref:`Python Initialization Configuration <init-config>`
11+
and the :ref:`Python Configuration <config-c-api>`
1112

1213
.. _pre-init-safe:
1314

Doc/c-api/init_config.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ There are two kinds of configuration:
2727
The :c:func:`Py_RunMain` function can be used to write a customized Python
2828
program.
2929

30-
See also :ref:`Initialization, Finalization, and Threads <initialization>`.
30+
See also :ref:`Initialization, Finalization, and Threads <initialization>`
31+
and the :ref:`Python Configuration <config-c-api>`.
3132

3233
.. seealso::
3334
:pep:`587` "Python Initialization Configuration".

Doc/data/stable_abi.dat

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/whatsnew/3.13.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,24 @@ New Features
12741274
* Add :c:func:`Py_HashPointer` function to hash a pointer.
12751275
(Contributed by Victor Stinner in :gh:`111545`.)
12761276

1277+
* Add functions to the limited C API to configure the Python initialization:
1278+
1279+
* :c:func:`PyInitConfig_Python_New`
1280+
* :c:func:`PyInitConfig_Isolated_New`
1281+
* :c:func:`PyInitConfig_Free`
1282+
* :c:func:`PyInitConfig_SetInt`
1283+
* :c:func:`PyInitConfig_SetStr`
1284+
* :c:func:`PyInitConfig_SetWStr`
1285+
* :c:func:`PyInitConfig_SetStrList`
1286+
* :c:func:`PyInitConfig_SetWStrList`
1287+
* :c:func:`PyInitConfig_Exception`
1288+
* :c:func:`PyInitConfig_GetError`
1289+
* :c:func:`PyInitConfig_GetExitCode`
1290+
* :c:func:`Py_InitializeFromInitConfig`
1291+
* :c:func:`Py_ExitWithInitConfig`
1292+
1293+
(Contributed by Victor Stinner in :gh:`107954`.)
1294+
12771295

12781296
Porting to Python 3.13
12791297
----------------------

Include/Python.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
#include "sliceobject.h"
8989
#include "cpython/cellobject.h"
9090
#include "iterobject.h"
91-
#include "cpython/initconfig.h"
91+
#include "initconfig.h"
9292
#include "pystate.h"
9393
#include "cpython/genobject.h"
9494
#include "descrobject.h"

Include/cpython/initconfig.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
#ifndef Py_PYCORECONFIG_H
2-
#define Py_PYCORECONFIG_H
3-
#ifndef Py_LIMITED_API
4-
#ifdef __cplusplus
5-
extern "C" {
1+
#ifndef Py_CPYTHON_INITCONFIG_H
2+
# error "this header file must not be included directly"
63
#endif
74

85
/* --- PyStatus ----------------------------------------------- */
@@ -263,9 +260,3 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
263260
264261
See also PyConfig.orig_argv. */
265262
PyAPI_FUNC(void) Py_GetArgcArgv(int *argc, wchar_t ***argv);
266-
267-
#ifdef __cplusplus
268-
}
269-
#endif
270-
#endif /* !Py_LIMITED_API */
271-
#endif /* !Py_PYCORECONFIG_H */

0 commit comments

Comments
 (0)