Skip to content

Commit

Permalink
pythongh-107954: Add PyInitConfig C API
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
vstinner committed May 23, 2024
1 parent a192547 commit 2022d23
Show file tree
Hide file tree
Showing 17 changed files with 802 additions and 51 deletions.
188 changes: 188 additions & 0 deletions Doc/c-api/config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
.. highlight:: c

.. _config-c-api:

********************
Python Configuration
********************

.. versionadded:: 3.13

API part of the limited C API version 3.13 to configure the Python
initialization and get the Python runtime configuration.

See also :ref:`Python Initialization Configuration <init-config>`.


Initialize Python
=================

Configuration to customize Python initialization. Configuration option names
are names of a :c:type:`PyConfig` members.

.. c:struct:: PyInitConfig
Opaque structure to configure the Python initialization.


.. c:function:: PyInitConfig* PyInitConfig_Python_New(void)
Create a new initialization configuration using :ref:`Python Configuration
<init-python-config>` default values.
It must be freed by :c:func:`PyInitConfig_Free`.
Return ``NULL`` on memory allocation failure.
.. c:function:: PyInitConfig* PyInitConfig_Isolated_New(void)
Similar to :c:func:`PyInitConfig_Python_New`, but use :ref:`Isolated
Configuration <init-isolated-conf>` default values.
.. c:function:: void PyInitConfig_Free(PyInitConfig *config)
Free memory of an initialization configuration.
.. c:function:: int PyInitConfig_SetInt(PyInitConfig *config, const char *name, int64_t value)
Set an integer configuration option.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
.. c:function:: int PyInitConfig_SetStr(PyInitConfig *config, const char *name, const char *value)
Set a string configuration option from a null-terminated bytes string.
The bytes string is decoded by :c:func:`Py_DecodeLocale`. If Python is not
yet preinitialized, this function preinitializes it to ensure that encodings
are properly configured.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
.. c:function:: int PyInitConfig_SetWStr(PyInitConfig *config, const char *name, const wchar_t *value)
Set a string configuration option from a null-terminated wide string.
If Python is not yet preinitialized, this function preinitializes it.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
.. c:function:: int PyInitConfig_SetStrList(PyInitConfig *config, const char *name, size_t length, char * const *items)
Set a string list configuration option from an array of null-terminated
bytes strings.
The bytes string is decoded by :c:func:`Py_DecodeLocale`. If Python is not
yet preinitialized, this function preinitializes it to ensure that encodings
are properly configured.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
.. c:function:: int PyInitConfig_SetWStrList(PyInitConfig *config, const char *name, size_t length, wchar_t * const *items)
Set a string list configuration option from a null-terminated wide strings.
If Python is not yet preinitialized, this function preinitializes it.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
.. c:function:: int Py_InitializeFromInitConfig(PyInitConfig *config)
Initialize Python from the initialization configuration.
* Return ``0`` on success.
* Return ``-1`` if an error was set or if an exit code was set.
Error handling
==============
.. c:function:: int PyInitConfig_Exception(PyInitConfig* config)
Check if an exception is set in *config*:
* Return non-zero if an error was set or if an exit code was set.
* Return zero otherwise.
.. c:function:: int PyInitConfig_GetError(PyInitConfig* config, const char **err_msg)
Get the *config* error message.
* Set *\*err_msg* and return ``1`` if an error is set.
* Set *\*err_msg* to ``NULL`` and return ``0`` otherwise.
.. c:function:: int PyInitConfig_GetExitCode(PyInitConfig* config, int *exitcode)
Get the *config* exit code.
* Set *\*exitcode* and return ``1`` if an exit code is set.
* Return ``0`` otherwise.
.. c:function:: void Py_ExitWithInitConfig(PyInitConfig *config)
Exit Python and free memory of a initialization configuration.
If an error message is set, display the error message.
If an exit code is set, use it to exit the process.
The function does not return.
Example
-------
Code::
void init_python(void)
{
PyInitConfig *config = PyInitConfig_Python_New();
if (config == NULL) {
printf("Init allocation error\n");
return;
}
if (PyInitConfig_SetInt(config, "dev_mode", 1) < 0) {
goto error;
}
// Set a list of wide strings (argv)
wchar_t *argv[] = {L"my_program"", L"-c", L"pass"};
if (PyInitConfig_SetWStrList(config, "argv",
Py_ARRAY_LENGTH(argv), argv) < 0) {
goto error;
}
// Set a wide string (program_name)
if (PyInitConfig_SetWStr(config, "program_name", L"my_program") < 0) {
goto error;
}
// Set a list of bytes strings (xoptions)
char* xoptions[] = {"faulthandler"};
if (PyInitConfig_SetStrList(config, "xoptions",
Py_ARRAY_LENGTH(xoptions), xoptions) < 0) {
goto error;
}
if (Py_InitializeFromInitConfig(config) < 0) {
Py_ExitWithInitConfig(config);
}
PyInitConfig_Free(config);
}
1 change: 1 addition & 0 deletions Doc/c-api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ document the API functions in detail.
concrete.rst
init.rst
init_config.rst
config.rst
memory.rst
objimpl.rst
apiabiversion.rst
Expand Down
3 changes: 2 additions & 1 deletion Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
Initialization, Finalization, and Threads
*****************************************

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

.. _pre-init-safe:

Expand Down
3 changes: 2 additions & 1 deletion Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ There are two kinds of configuration:
The :c:func:`Py_RunMain` function can be used to write a customized Python
program.

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

.. seealso::
:pep:`587` "Python Initialization Configuration".
Expand Down
13 changes: 13 additions & 0 deletions Doc/data/stable_abi.dat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,21 @@ New Features
destruction the same way the :mod:`tracemalloc` module does. (Contributed
by Pablo Galindo in :gh:`93502`.)

* Add functions to the limited C API to configure the Python initialization:

* :c:func:`PyInitConfig_Python_New`
* :c:func:`PyInitConfig_Isolated_New`
* :c:func:`PyInitConfig_Free`
* :c:func:`PyInitConfig_SetInt`
* :c:func:`PyInitConfig_SetStr`
* :c:func:`PyInitConfig_SetStrList`
* :c:func:`PyInitConfig_Exception`
* :c:func:`PyInitConfig_GetError`
* :c:func:`PyInitConfig_GetExitCode`
* :c:func:`Py_InitializeFromInitConfig`
* :c:func:`Py_ExitWithInitConfig`

(Contributed by Victor Stinner in :gh:`107954`.)

Build Changes
=============
Expand Down
2 changes: 1 addition & 1 deletion Include/Python.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
#include "sliceobject.h"
#include "cpython/cellobject.h"
#include "iterobject.h"
#include "cpython/initconfig.h"
#include "initconfig.h"
#include "pystate.h"
#include "cpython/genobject.h"
#include "descrobject.h"
Expand Down
81 changes: 71 additions & 10 deletions Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#ifndef Py_PYCORECONFIG_H
#define Py_PYCORECONFIG_H
#ifndef Py_LIMITED_API
#ifdef __cplusplus
extern "C" {
#ifndef Py_CPYTHON_INITCONFIG_H
# error "this header file must not be included directly"
#endif

/* --- PyStatus ----------------------------------------------- */
Expand Down Expand Up @@ -267,8 +264,72 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
See also PyConfig.orig_argv. */
PyAPI_FUNC(void) Py_GetArgcArgv(int *argc, wchar_t ***argv);

#ifdef __cplusplus
}
#endif
#endif /* !Py_LIMITED_API */
#endif /* !Py_PYCORECONFIG_H */

// --- PyInitConfig ---------------------------------------------------------

typedef struct PyInitConfig PyInitConfig;

// Create a new initialization configuration.
// It must be freed by PyInitConfig_Free().
// Return NULL on memory allocation failure.
//
// PyInitConfig_Python_New() has a Python configuration by default.
// PyInitConfig_Isolated_New() has an Isolated configuration by default.
PyAPI_FUNC(PyInitConfig*) PyInitConfig_Python_New(void);
PyAPI_FUNC(PyInitConfig*) PyInitConfig_Isolated_New(void);

// Free memory of a initialization configuration.
PyAPI_FUNC(void) PyInitConfig_Free(PyInitConfig *config);

// Set an integer configuration option.
// Return 0 on success, or return -1 on error.
PyAPI_FUNC(int) PyInitConfig_SetInt(
PyInitConfig *config,
const char *name,
int64_t value);

// Set a string configuration option from a bytes string.
//
// The bytes string is decoded by Py_DecodeLocale(). Preinitialize Python if
// needed to ensure that encodings are properly configured.
//
// Return 0 on success, or return -1 on error.
PyAPI_FUNC(int) PyInitConfig_SetStr(
PyInitConfig *config,
const char *name,
const char *value);

// Set a string list configuration option from bytes strings.
//
// The bytes strings are decoded by Py_DecodeLocale(). Preinitialize Python if
// needed to ensure that encodings are properly configured.
//
// Return 0 on success, or return -1 on error.
PyAPI_FUNC(int) PyInitConfig_SetStrList(
PyInitConfig *config,
const char *name,
size_t length,
char * const *items);

// Initialize Python from the initialization configuration.
// Return 0 on success.
// Return -1 if Python wants to exit and on error
PyAPI_FUNC(int) Py_InitializeFromInitConfig(PyInitConfig *config);

// Return non-zero if an error was set or if an exit code was set.
// Return zero otherwise.
PyAPI_FUNC(int) PyInitConfig_Exception(PyInitConfig* config);

// Get the error message.
// Set *err_msg and return 1 if an error is set.
// Set *err_msg to NULL and return 0 otherwise.
PyAPI_FUNC(int) PyInitConfig_GetError(PyInitConfig* config, const char **err_msg);

// Get the exit code.
// Set '*exitcode' and return 1 if an exit code is set.
// Return 0 otherwise.
PyAPI_FUNC(int) PyInitConfig_GetExitCode(PyInitConfig* config, int *exitcode);

// Exit Python and free memory of a initialization configuration.
// The function does not return.
PyAPI_FUNC(void) _Py_NO_RETURN Py_ExitWithInitConfig(PyInitConfig *config);
16 changes: 16 additions & 0 deletions Include/initconfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef Py_INITCONFIG_H
#define Py_INITCONFIG_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_LIMITED_API
# define Py_CPYTHON_INITCONFIG_H
# include "cpython/initconfig.h"
# undef Py_CPYTHON_INITCONFIG_H
#endif

#ifdef __cplusplus
}
#endif
#endif // !Py_INITCONFIG_H
4 changes: 4 additions & 0 deletions Include/internal/pycore_initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ extern int _PyWideStringList_Copy(PyWideStringList *list,
extern PyStatus _PyWideStringList_Extend(PyWideStringList *list,
const PyWideStringList *list2);
extern PyObject* _PyWideStringList_AsList(const PyWideStringList *list);
extern PyStatus _PyWideStringList_FromBytes(
PyWideStringList *list,
Py_ssize_t length,
char * const *items);


/* --- _PyArgv ---------------------------------------------------- */
Expand Down
Loading

0 comments on commit 2022d23

Please sign in to comment.