Skip to content

gh-107954, PEP 741: Add PyInitConfig C API #123502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Initialization, Finalization, and Threads
*****************************************

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

.. _pre-init-safe:

Expand Down
245 changes: 235 additions & 10 deletions Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
Python Initialization Configuration
***********************************

PyConfig C API
==============

.. versionadded:: 3.8

Python can be initialized with :c:func:`Py_InitializeFromConfig` and the
Expand Down Expand Up @@ -34,7 +37,7 @@ See also :ref:`Initialization, Finalization, and Threads <initialization>`.


Example
=======
-------

Example of customized Python always running in isolated mode::

Expand Down Expand Up @@ -73,7 +76,7 @@ Example of customized Python always running in isolated mode::


PyWideStringList
================
----------------

.. c:type:: PyWideStringList

Expand Down Expand Up @@ -116,7 +119,7 @@ PyWideStringList
List items.

PyStatus
========
--------

.. c:type:: PyStatus

Expand Down Expand Up @@ -210,7 +213,7 @@ Example::


PyPreConfig
===========
-----------

.. c:type:: PyPreConfig

Expand Down Expand Up @@ -360,7 +363,7 @@ PyPreConfig
.. _c-preinit:

Preinitialize Python with PyPreConfig
=====================================
-------------------------------------

The preinitialization of Python:

Expand Down Expand Up @@ -440,7 +443,7 @@ the :ref:`Python UTF-8 Mode <utf8-mode>`::


PyConfig
========
--------

.. c:type:: PyConfig

Expand Down Expand Up @@ -1349,7 +1352,7 @@ the :option:`-X` command line option.


Initialization with PyConfig
============================
----------------------------

Function to initialize Python:

Expand Down Expand Up @@ -1461,7 +1464,7 @@ initialization::
.. _init-isolated-conf:

Isolated Configuration
======================
----------------------

:c:func:`PyPreConfig_InitIsolatedConfig` and
:c:func:`PyConfig_InitIsolatedConfig` functions create a configuration to
Expand All @@ -1481,7 +1484,7 @@ to avoid computing the default path configuration.
.. _init-python-config:

Python Configuration
====================
--------------------

:c:func:`PyPreConfig_InitPythonConfig` and :c:func:`PyConfig_InitPythonConfig`
functions create a configuration to build a customized Python which behaves as
Expand All @@ -1499,7 +1502,7 @@ and :ref:`Python UTF-8 Mode <utf8-mode>`
.. _init-path-config:

Python Path Configuration
=========================
-------------------------

:c:type:`PyConfig` contains multiple fields for the path configuration:

Expand Down Expand Up @@ -1585,6 +1588,228 @@ The ``__PYVENV_LAUNCHER__`` environment variable is used to set
:c:member:`PyConfig.base_executable`.


PyInitConfig C API
==================

C API to configure the Python initialization (:pep:`741`).

.. versionadded:: 3.14

Create Config
-------------

.. c:struct:: PyInitConfig

Opaque structure to configure the Python initialization.


.. c:function:: PyInitConfig* PyInitConfig_Create(void)

Create a new initialization configuration using :ref:`Isolated Configuration
<init-isolated-conf>` default values.

It must be freed by :c:func:`PyInitConfig_Free`.

Return ``NULL`` on memory allocation failure.


.. c:function:: void PyInitConfig_Free(PyInitConfig *config)

Free memory of the initialization configuration *config*.


Error Handling
--------------

.. 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.

An error message is an UTF-8 encoded string.

If *config* has an exit code, format the exit code as an error
message.

The error message remains valid until another ``PyInitConfig``
function is called with *config*. The caller doesn't have to free the
error message.


.. c:function:: int PyInitConfig_GetExitCode(PyInitConfig* config, int *exitcode)

Get the *config* exit code.

* Set *\*exitcode* and return ``1`` if *config* has an exit code set.
* Return ``0`` if *config* has no exit code set.

Only the ``Py_InitializeFromInitConfig()`` function can set an exit
code if the ``parse_argv`` option is non-zero.

An exit code can be set when parsing the command line failed (exit
code ``2``) or when a command line option asks to display the command
line help (exit code ``0``).


Get Options
-----------

The configuration option *name* parameter must be a non-NULL
null-terminated UTF-8 encoded string.

.. c:function:: int PyInitConfig_HasOption(PyInitConfig *config, const char *name)

Test if the configuration has an option called *name*.

Return ``1`` if the option exists, or return ``0`` otherwise.


.. c:function:: int PyInitConfig_GetInt(PyInitConfig *config, const char *name, int64_t *value)

Get an integer configuration option.

* Set *\*value*, and return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.


.. c:function:: int PyInitConfig_GetStr(PyInitConfig *config, const char *name, char **value)

Get a string configuration option as a null-terminated UTF-8
encoded string.

* Set *\*value*, and return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.

*\*value* can be set to ``NULL`` if the option is an optional string and the
option is unset.

On success, the string must be released with ``free(value)`` if it's not
``NULL``.


.. c:function:: int PyInitConfig_GetStrList(PyInitConfig *config, const char *name, size_t *length, char ***items)

Get a string list configuration option as an array of
null-terminated UTF-8 encoded strings.

* Set *\*length* and *\*value*, and return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.

On success, the string list must be released with
``PyInitConfig_FreeStrList(length, items)``.


.. c:function:: void PyInitConfig_FreeStrList(size_t length, char **items)

Free memory of a string list created by
``PyInitConfig_GetStrList()``.


Set Options
-----------

The configuration option *name* parameter must be a non-NULL null-terminated
UTF-8 encoded string.

Some configuration options have side effects on other options. This logic is
only implemented when ``Py_InitializeFromInitConfig()`` is called, not by the
"Set" functions below. For example, setting ``dev_mode`` to ``1`` does not set
``faulthandler`` to ``1``.

.. 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 UTF-8
encoded string. The string is copied.

* 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 UTF-8 encoded strings. The string list is copied.

* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.


Initialize Python
-----------------

.. c:function:: int Py_InitializeFromInitConfig(PyInitConfig *config)

Initialize Python from the initialization configuration.

* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
* Set an exit code in *config* and return ``-1`` if Python wants to
exit.

See ``PyInitConfig_GetExitcode()`` for the exit code case.


Example
-------

Example initializing Python, set configuration options of various types,
return ``-1`` on error:

.. code-block:: c

int init_python(void)
{
PyInitConfig *config = PyInitConfig_Create();
if (config == NULL) {
printf("PYTHON INIT ERROR: memory allocation failed\n");
return -1;
}

// Set an integer (dev mode)
if (PyInitConfig_SetInt(config, "dev_mode", 1) < 0) {
goto error;
}

// Set a list of UTF-8 strings (argv)
char *argv[] = {"my_program", "-c", "pass"};
if (PyInitConfig_SetStrList(config, "argv",
Py_ARRAY_LENGTH(argv), argv) < 0) {
goto error;
}

// Set a UTF-8 string (program name)
if (PyInitConfig_SetStr(config, "program_name", L"my_program") < 0) {
goto error;
}

// Initialize Python with the configuration
if (Py_InitializeFromInitConfig(config) < 0) {
goto error;
}
PyInitConfig_Free(config);
return 0;

// Display the error message
const char *err_msg;
error:
(void)PyInitConfig_GetError(config, &err_msg);
printf("PYTHON INIT ERROR: %s\n", err_msg);
PyInitConfig_Free(config);

return -1;
}


Py_RunMain()
============

Expand Down
21 changes: 20 additions & 1 deletion Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,8 @@ New Features
* Add :c:func:`Py_HashBuffer` to compute and return the hash value of a buffer.
(Contributed by Antoine Pitrou and Victor Stinner in :gh:`122854`.)

* Add functions to get and set the current runtime Python configuration:
* Add functions to get and set the current runtime Python configuration
(:pep:`741`):

* :c:func:`PyConfig_Get`
* :c:func:`PyConfig_GetInt`
Expand All @@ -501,6 +502,24 @@ New Features

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

* Add functions to configure the Python initialization (:pep:`741`):

* :c:func:`PyInitConfig_Create`
* :c:func:`PyInitConfig_Free`
* :c:func:`PyInitConfig_GetError`
* :c:func:`PyInitConfig_GetExitCode`
* :c:func:`PyInitConfig_HasOption`
* :c:func:`PyInitConfig_GetInt`
* :c:func:`PyInitConfig_GetStr`
* :c:func:`PyInitConfig_GetStrList`
* :c:func:`PyInitConfig_FreeStrList`
* :c:func:`PyInitConfig_SetInt`
* :c:func:`PyInitConfig_SetStr`
* :c:func:`PyInitConfig_SetStrList`
* :c:func:`Py_InitializeFromInitConfig`

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


Porting to Python 3.14
----------------------
Expand Down
Loading
Loading