PEP 741: Second version (#3652)

This commit is contained in:
Victor Stinner 2024-02-08 19:40:50 +01:00 committed by GitHub
parent ac8927ae3c
commit bbc39a5100
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 457 additions and 117 deletions

View File

@ -11,20 +11,26 @@ Post-History: `19-Jan-2024 <https://discuss.python.org/t/pep-741-python-configur
Abstract
========
Add a C API to the limited C API to configure the Python
preinitialization and initialization, and to get the current
configuration. It can be used with the stable ABI.
Add a C API to the limited C API to configure the Python initialization,
and to get the current configuration. It can be used with the stable
ABI.
Add ``sys.get_config(name)`` function to get the current value of a
configuration option.
Add also ``sys.get_config(name)`` function to get the current
configuration.
Allow setting custom configuration options, not used by Python but by
third-party code. Options are referred to by their name as a string.
Complete PEP 587 API by adding ``PyInitConfig_AddModule()`` which can be
used to add a built-in extension module; feature previously referred to
as the "inittab".
:pep:`587` "Python Initialization Configuration" unified all the ways to
configure the Python **initialization**. This PEP unifies also the
configuration of the Python **preinitialization** and the Python
**initialization** in a single API.
configure the Python **initialization**. This PEP (almost fully) unifies
also the configuration of the Python **preinitialization** and the
Python **initialization** in a single API, even if the
**preinitialization** is still required to decode strings from the
locale encoding.
This new API replaces the deprecated and incomplete legacy API which is
scheduled for removal between Python 3.13 and Python 3.15.
Rationale
@ -46,21 +52,49 @@ the stable ABI.
Since PyConfig was added to Python 3.8, the limited C API and the stable
ABI are getting more popular. For example, Rust bindings such as the
`PyO3 project <https://pyo3.rs/>`_ target the limited C API to embed
Python in Rust. In practice, PyO3 can use non-limited C API for specific
needs, but using them avoids the stable ABI advantages.
`PyO3 project <https://pyo3.rs/>`_ can target the limited C API to embed
Python in Rust (but it's not the default). In practice, PyO3 can use
non-limited C API for specific needs, but using them avoids the stable
ABI advantages.
Deprecated legacy API
---------------------
Limitations of the legacy API
-----------------------------
The legacy configuration API has been deprecated since Python 3.8:
The legacy API to configure the Python initialization is based on the
legacy ``Py_Initialize()`` function. It is now mostly deprecated:
* Set the initialization configuration such as ``Py_SetPath()``:
deprecated in Python 3.11.
deprecated in Python 3.11 and removed in Python 3.13.
* Global configuration variables such as ``Py_VerboseFlag``:
deprecated in Python 3.12.
deprecated in Python 3.12 and scheduled for removal in Python 3.14.
* Get the current configuration such as ``Py_GetPath()``:
deprecated in Python 3.13.
deprecated in Python 3.13 and scheduled for removal in Python 3.15.
The legacy API doesn't support the "Python Configuration" and the
"Isolated Configuration" of PEP 587 PyConfig API. It only provides a
"legacy configuration" of ``Py_Initialize()`` which is in the between,
and also uses the legacy global configuration variables (such as
``Py_VerboseFlag``).
Some options can only by set by environment variables, such as ``home``
set by the ``PYTHONHOME`` environment variable. The problem is that
environment variables are inherited by child processes which can be a
surprising and unwanted behavior.
Some configuration options, such as ``configure_locale``, simply cannot
be set.
Limitations of the limited C API
--------------------------------
The limited C API is a subset of the legacy API. For example,
global configuration variables, such as ``Py_VerboseFlag``, are not
part of the limited C API.
While some functions were removed from the limited C API version 3.13,
they are still part of the stable ABI. For example, building a
application with the limited C API version 3.12 can still run with
Python 3.13 stable ABI.
Get the current configuration
-----------------------------
@ -110,32 +144,153 @@ The redundancy is caused by the fact that the two structures are
separated, whereas some ``PyConfig`` members are needed by the
preinitialization.
Applications embedding Python
-----------------------------
Examples:
* `Blender 3D graphics <https://www.blender.org/>`_.
* `fontforge <https://fontforge.org/>`_ font editor.
* `Gimp <https://www.gimp.org/>`_.
* `LibreOffice <https://www.libreoffice.org/>`_.
* `OBS Studio <https://obsproject.com/>`_.
* `Tiled <https://www.mapeditor.org/>`_.
* `vim <https://www.vim.org/>`_ text editor.
On Linux, FreeBSD and macOS, applications are usually either statically
linked to a ``libpython``, or load dynamically a ``libpython`` . The
``libpython`` shared library is versionned, example:
``libpython3.12.so`` for Python 3.13 on Linux.
The vim project can target the stable ABI. Usually, the "system Python"
version is used. It's not currently possible to select which Python
version to use. Users would like the ability to select a newer Python
on demand.
On Linux, another approach to deploy an application embedding Python,
such as GIMP, is to include Python in Flatpack, AppImage or Snap
"container". In this case, the application brings its own copy of Python
version with the container.
Libraries embedding Python
--------------------------
Examples:
* `Apache mod_wsgi <https://modwsgi.readthedocs.io/>`_
(`source <https://github.com/GrahamDumpleton/mod_wsgi/blob/f54eadd6da8e3da0faccd497d4165de435b97242/src/server/wsgi_interp.c#L2367-L2404>`__).
* `nimpy <https://github.com/yglukhov/nimpy>`_:
Nim - Python bridge.
* `PyO3 <https://github.com/PyO3/pyo3>`__:
Rust bindings for the Python interpreter.
Utilities creating standalone applications
------------------------------------------
* `py2app <https://py2app.readthedocs.io/>`_ for macOS.
* `py2exe <http://www.py2exe.org/>`_ for Windows.
* `pyinstaller <https://pyinstaller.org/>`_.
* `PyOxidizer <https://github.com/indygreg/PyOxidizer>`_:
it uses the PEP 587 PyConfig API.
These utilities create standalone applications, they are not linked to
libpython.
Usage of a stable ABI
---------------------
`Ronald Oussoren
<https://discuss.python.org/t/fr-allow-private-runtime-config-to-enable-extending-without-breaking-the-pyconfig-abi/18004/9>`__:
For tools like py2app/py2exe/pyinstaller, it is pretty
**inconvenient to have to rebuild the launcher executable** thats
used to start the packaged application when theres a bug fix
release of Python.
`Gregory P. Smith
<https://discuss.python.org/t/fr-allow-private-runtime-config-to-enable-extending-without-breaking-the-pyconfig-abi/18004/10>`__:
You cant **extend a struct** and **assume embedding people all
rebuild**. They dont. Real world embedding uses exist that use an
installed Python minor version as a shared library. Update that to
use a different sized struct in a public API and someone is going to
have a bad time. Thats why I consider the struct frozen at rc1
time, even when only for use in the embedding / writing their own
launcher case.
`Colton Murphy
<https://discuss.python.org/t/fr-allow-private-runtime-config-to-enable-extending-without-breaking-the-pyconfig-abi/18004/11>`__:
I am trying to **embed the Python interpreter** using a **non C
language**. I have to stick with the limited API and private
structures for configuration in headers files is a no-no. Basically,
I need to be able to allocate and configure everything using only
exportable functions and the heap… no private structure details.
(...)
I am strictly limited to whats in the shared library (DLL). I dont
have headers, I cant statically “recompile” every time a new
version of python comes out. Thats unmaintainable for me.
`Milian Wolff
<https://github.com/python/cpython/issues/107954#issuecomment-1893988614>`__:
IIUC then there's still no non-deprecated API in the **limited C API
to customize the initialization**, right? Can you then please reopen
this task to indicate that this? Or should I report a separate issue
to track this? Thank you
`David Hewitt <https://discuss.python.org/t/pep-741-python-configuration-c-api/43637/38>`__ of the PyO3 project:
I think making the configuration structure opaque and using an API
to set/get configuration by name is a welcome simplification:
* Its a **smaller API** for language bindings like PyO3 to wrap and
re-expose, and
* Its **easier** for people to **support multiple Python versions
to embed into their application**; no need to conditionally
compile structure field access, can just use normal error handling
if configuration values are not available for a specific version
at runtime.
Specification
=============
C API:
Add C API functions and structure to configure the Python
initialization:
* ``PyInitConfig`` structure
* ``PyInitConfig_Python_New()``
* ``PyInitConfig_Isolated_New()``
* ``PyInitConfig_Free(config)``
* ``PyInitConfig_SetInt(config, name, value)``
* ``PyInitConfig_SetStr(config, name, value)``
* ``PyInitConfig_SetWStr(config, name, value)``
* ``PyInitConfig_SetStrList(config, name, length, items)``
* ``PyInitConfig_SetWStrList(config, name, length, items)``
* ``Py_InitializeFromInitConfig(config)``
* ``PyInitConfig_Exception(config)``
* ``PyInitConfig_GetError(config, &err_msg)``
* ``PyInitConfig_GetExitCode(config, &exitcode)``
* ``Py_ExitWithInitConfig(config)``
* ``PyConfig_Get(name)``
* ``PyConfig_GetInt(name, &value)``
* ``PyInitConfig`` opaque structure.
* ``PyInitConfig_CreatePython()``.
* ``PyInitConfig_CreateIsolated()``.
* ``PyInitConfig_Free(config)``.
* ``PyInitConfig_GetInt(config, name, &value)``.
* ``PyInitConfig_GetStr(config, name, &value)``.
* ``PyInitConfig_GetWStr(config, name, &value)``.
* ``PyInitConfig_GetStrList(config, name, &length, &items)``.
* ``PyInitConfig_FreeStrList()``.
* ``PyInitConfig_GetWStrList(config, name, &length, &items)``.
* ``PyInitConfig_FreeWStrList()``.
* ``PyInitConfig_SetInt(config, name, value)``.
* ``PyInitConfig_SetStr(config, name, value)``.
* ``PyInitConfig_SetStrLocale(config, name, value)``.
* ``PyInitConfig_SetWStr(config, name, value)``.
* ``PyInitConfig_SetStrList(config, name, length, items)``.
* ``PyInitConfig_SetStrLocaleList(config, name, length, items)``.
* ``PyInitConfig_SetWStrList(config, name, length, items)``.
* ``PyInitConfig_AddModule(config, name, initfunc)``
* ``Py_PreInitializeFromInitConfig(config)``.
* ``Py_InitializeFromInitConfig(config)``.
* ``PyInitConfig_GetError(config, &err_msg)``.
* ``Py_ExitWithInitConfig(config)``.
Python API:
Add C API and Python functions to get the current configuration:
* ``sys.get_config(name)``
* ``PyConfig_Get(name)``.
* ``PyConfig_GetInt(name, &value)``.
* ``PyConfig_Keys()``.
* ``sys.get_config(name)``.
The C API uses null-terminated UTF-8 encoded strings to refer to a
configuration option.
@ -143,11 +298,13 @@ configuration option.
All C API functions are added to the limited C API version 3.13.
The ``PyInitConfig`` structure is implemented by combining the three
structures of the ``PyConfig`` API:
structures of the ``PyConfig`` API and has an ``inittab`` member as
well:
* ``PyPreConfig preconfig``
* ``PyConfig config``
* ``PyStatus status``
* ``struct _inittab *inittab`` for ``PyInitConfig_AddModule()``
The ``PyStatus`` status is no longer separated, but part of the unified
``PyInitConfig`` structure, which makes the API easier to use.
@ -156,30 +313,123 @@ The ``PyStatus`` status is no longer separated, but part of the unified
Configuration Options
---------------------
Configuration options are named after ``PyPreConfig`` and
``PyConfig`` structure members such as ``"verbose"``
(``PyConfig.verbose``), ``"buffered_stdio"``
(``PyConfig.buffered_stdio``), or ``"allocator"``
(``PyPreConfig.allocator``).
Configuration option names:
The type of configuration options depends on the option. For example,
the ``"verbose"`` option type is an integer, whereas
``"module_search_paths"`` option type is an array of wide strings.
* ``"allocator"`` (integer)
* ``"argv"`` (string list).
* ``"base_exec_prefix"`` (string).
* ``"base_executable"`` (string).
* ``"base_prefix"`` (string).
* ``"buffered_stdio"`` (integer).
* ``"bytes_warning"`` (integer).
* ``"check_hash_pycs_mode"`` (string).
* ``"code_debug_ranges"`` (integer).
* ``"coerce_c_locale"`` (integer)
* ``"coerce_c_locale_warn"`` (integer)
* ``"configure_c_stdio"`` (integer).
* ``"configure_locale"`` (integer)
* ``"cpu_count"`` (integer).
* ``"dev_mode"`` (integer).
* ``"dump_refs"`` (integer).
* ``"dump_refs_file"`` (string).
* ``"exec_prefix"`` (string).
* ``"executable"`` (string).
* ``"faulthandler"`` (integer).
* ``"filesystem_encoding"`` (string).
* ``"filesystem_errors"`` (string).
* ``"hash_seed"`` (unsigned long).
* ``"home"`` (string).
* ``"import_time"`` (integer).
* ``"inspect"`` (integer).
* ``"install_signal_handlers"`` (integer).
* ``"int_max_str_digits"`` (integer).
* ``"interactive"`` (integer).
* ``"isolated"`` (integer).
* ``"legacy_windows_fs_encoding"`` (integer)
* ``"legacy_windows_stdio"`` (integer): only on Windows.
* ``"malloc_stats"`` (integer).
* ``"module_search_paths"`` (string list).
* ``"module_search_paths_set"`` (integer).
* ``"optimization_level"`` (integer).
* ``"orig_argv"`` (string list).
* ``"parse_argv"`` (integer).
* ``"parser_debug"`` (integer).
* ``"pathconfig_warnings"`` (integer).
* ``"perf_profiling"`` (integer).
* ``"platlibdir"`` (string).
* ``"prefix"`` (string).
* ``"program_name"`` (string).
* ``"pycache_prefix"`` (string).
* ``"pythonpath_env"`` (string).
* ``"quiet"`` (integer).
* ``"run_command"`` (string).
* ``"run_filename"`` (string).
* ``"run_module"`` (string).
* ``"run_presite"`` (string): only on a Python debug build.
* ``"safe_path"`` (integer).
* ``"show_ref_count"`` (integer).
* ``"site_import"`` (integer).
* ``"skip_source_first_line"`` (integer).
* ``"stdio_encoding"`` (string).
* ``"stdio_errors"`` (string).
* ``"stdlib_dir"`` (string).
* ``"sys_path_0"`` (string).
* ``"tracemalloc"`` (integer).
* ``"use_environment"`` (integer).
* ``"use_frozen_modules"`` (integer).
* ``"use_hash_seed"`` (integer).
* ``"user_site_directory"`` (integer).
* ``"utf8_mode"`` (integer)
* ``"verbose"`` (integer).
* ``"warn_default_encoding"`` (integer).
* ``"warnoptions"`` (string list).
* ``"write_bytecode"`` (integer).
* ``"xoptions"`` (string list).
See the `PyConfig documentation
<https://docs.python.org/dev/c-api/init_config.html#pyconfig>`_
and the `PyPreConfig documentation
<https://docs.python.org/dev/c-api/init_config.html#pypreconfig>`_.
Configuration options are named after ``PyPreConfig`` and ``PyConfig``
structure members even if ``PyConfig_Get()`` can also get values from
the ``sys`` module. See the `PyPreConfig documentation
<https://docs.python.org/dev/c-api/init_config.html#pypreconfig>`_ and
the `PyConfig documentation
<https://docs.python.org/dev/c-api/init_config.html#pyconfig>`_.
Deprecating and removing configuration options is out of the scope of
the PEP and should be discussed on a case by case basis.
Configure the Python initialization
-----------------------------------
Preconfiguration
----------------
Calling ``Py_PreInitializeFromInitConfig()`` preinitializes Python. For
example, it sets the memory allocation, and can configure the
``LC_CTYPE`` locale and configure the standard C streams such as
``stdin`` and ``stdout``.
The following option names can only be set during the Python
preconfiguration:
* ``"allocator"``,
* ``"coerce_c_locale"``,
* ``"coerce_c_locale_warn"``,
* ``"configure_locale"``,
* ``"legacy_windows_fs_encoding"``,
* ``"utf8_mode"``.
Trying to set these options after Python preinitialization fails with an
error.
``PyInitConfig_SetStrLocale()`` and ``PyInitConfig_SetStrLocaleList()``
functions cannot be called Python preinitialization.
Create PyInitConfig
-------------------
``PyInitConfig`` structure:
Opaque structure to configure the Python preinitialization and the
Python initialization.
``PyInitConfig* PyInitConfig_Python_New(void)``:
``PyInitConfig* PyInitConfig_CreatePython(void)``:
Create a new initialization configuration using default values
of the `Python Configuration
<https://docs.python.org/dev/c-api/init_config.html#python-configuration>`_.
@ -188,14 +438,71 @@ Configure the Python initialization
Return ``NULL`` on memory allocation failure.
``PyInitConfig* PyInitConfig_Isolated_New(void)``:
Similar to ``PyInitConfig_Python_New()``, but use default values
``PyInitConfig* PyInitConfig_CreateIsolated(void)``:
Similar to ``PyInitConfig_CreatePython()``, but use default values
of the `Isolated Configuration
<https://docs.python.org/dev/c-api/init_config.html#isolated-configuration>`_.
``void PyInitConfig_Free(PyInitConfig *config)``:
Free memory of an initialization configuration.
Get PyInitConfig Options
------------------------
``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.
``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.
On success, the string must be released with ``free(value)``.
``int PyInitConfig_GetWStr(PyInitConfig *config, const char *name, wchar_t **value)``:
Get a string configuration option as a null-terminated wide string.
* Set *\*value* and return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
On success, the string must be released with ``free(value)``.
``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)``.
``void PyInitConfig_FreeStrList(size_t length, char **items)``:
Free memory of a string list created by
``PyInitConfig_GetStrList()``.
``int PyInitConfig_GetWStrList(PyInitConfig *config, const char *name, size_t *length, wchar_t ***items)``:
Get a string list configuration option as an error of
null-terminated wide 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_FreeWStrList(length, items)``.
``void PyInitConfig_FreeWStrList(size_t length, wchar_t **items)``:
Free memory of a string list created by
``PyInitConfig_GetWStrList()``.
Set PyInitConfig Options
------------------------
``int PyInitConfig_SetInt(PyInitConfig *config, const char *name, int64_t value)``:
Set an integer configuration option.
@ -204,47 +511,76 @@ Configure the Python initialization
* Set an error in *config* and return ``-1`` on error.
``int PyInitConfig_SetStr(PyInitConfig *config, const char *name, const char *value)``:
Set a string configuration option from a null-terminated bytes
string.
Set a string configuration option from a null-terminated UTF-8
encoded string. The string is copied.
The bytes string is decoded by ``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.
``int PyInitConfig_SetStrLocale(PyInitConfig *config, const char *name, const char *value)``:
Set a string configuration option from a null-terminated bytes
string encoded in the locale encoding. The string is copied.
The bytes string is decoded by ``Py_DecodeLocale()``.
``Py_PreInitializeFromInitConfig()`` must be called before calling
this function.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
``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.
string. The string is copied.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
``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.
null-terminated UTF-8 encoded strings. The string list is copied.
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.
``int PyInitConfig_SetStrLocaleList(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 encoded in the locale encoding.
The string list is copied.
The bytes string is decoded by :c:func:`Py_DecodeLocale`.
``Py_PreInitializeFromInitConfig()`` must be called before calling
this function.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
``int PyInitConfig_SetWStrList(PyInitConfig *config, const char *name, size_t length, wchar_t * const *items)``:
Set a string list configuration option from an error of
null-terminated wide strings.
If Python is not yet preinitialized, this function preinitializes
it.
null-terminated wide strings. The string list is copied.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
``int PyInitConfig_AddModule(PyInitConfig *config, const char *name, PyObject* (*initfunc)(void))``:
Add a built-in extension module to the table of built-in modules.
The new module can be imported by the name *name*, and uses the
function *initfunc* as the initialization function called on the
first attempted import.
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
If Python is initialized multiple times,
``PyInitConfig_AddModule()`` must be called at each Python
initialization.
Similar to the ``PyImport_AppendInittab()`` function.
Initialize Python
-----------------
``int Py_PreInitializeFromInitConfig(PyInitConfig *config)``:
Preinitialize Python from the initialization configuration.
@ -256,17 +592,11 @@ Configure the Python initialization
* Return ``0`` on success.
* Set an error in *config* and return ``-1`` on error.
* Set an exit code in *config* and return ``-1`` on exit.
Error handling
--------------
``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.
``int PyInitConfig_GetError(PyInitConfig* config, const char **err_msg)``:
Get the *config* error message.
@ -275,26 +605,18 @@ Error handling
An error message is an UTF-8 encoded string.
The error message remains valid until a ``PyInitConfig`` function is
called with *config*. The caller doesn't have to free the error
message.
``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.
The error message remains valid until another ``PyInitConfig``
function is called with *config*. The caller doesn't have to free the
error message.
``void Py_ExitWithInitConfig(PyInitConfig *config)``:
Exit Python and free memory of an 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.
Get current configuration
-------------------------
@ -306,12 +628,42 @@ Get current configuration
The object type depends on the option.
The following options are read from the ``sys`` modules.
* ``"argv"``: ``sys.argv``.
* ``"base_exec_prefix"``: ``sys.base_exec_prefix``.
* ``"base_executable"``: ``sys._base_executable``.
* ``"base_prefix"``: ``sys.base_prefix``.
* ``"exec_prefix"``: ``sys.exec_prefix``.
* ``"executable"``: ``sys.executable``.
* ``"module_search_paths"``: ``sys.path``.
* ``"orig_argv"``: ``sys.orig_argv``.
* ``"platlibdir"``: ``sys.platlibdir``.
* ``"prefix"``: ``sys.prefix``.
* ``"pycache_prefix"``: ``sys.pycache_prefix``.
* ``"stdlib_dir"``: ``sys._stdlib_dir``.
* ``"warnoptions"``: ``sys.warnoptions``.
* ``"write_bytecode"``: ``not sys.dont_write_bytecode``
(opposite value).
* ``"xoptions"``: ``sys._xoptions``.
Other options are get from internal ``PyPreConfig`` and ``PyConfig`` structures.
The function cannot be called before Python initialization nor
after Python finalization.
``int PyConfig_GetInt(const char *name, int *value)``:
Similar to ``PyConfig_Get()``, but get the value as an integer.
* Set ``*value`` and return ``0`` success.
* Set an exception and return ``-1`` on error.
``PyObject* PyConfig_Keys(void)``:
Get all configuration option names as a tuple.
Set an exception and return ``NULL`` on error.
sys.get_config()
----------------
@ -321,26 +673,6 @@ Add ``sys.get_config(name: str)`` function which calls
* Return the configuration option value on success.
* Raise an exception on error.
Custom configuration options
----------------------------
It is possible to set custom configuration options, not used by Python
but only by third-party code, by calling:
``PyInitConfig_SetInt(config, "allow_custom_options", 1)``. In this
case, setting custom configuration options is accepted, rather than
failing with an "unknown option" error. By default, setting custom
configuration options is not allowed.
Custom configuration options are set with the ``PyInitConfig`` API, such
as ``PyInitConfig_SetInt()``, and can be got later with the
``PyConfig_Get()`` API.
To avoid conflicts with future Python configuration options, it is
recommended to use a prefix separated by a colon. For example, an
application called ``myapp`` can use the ``"myapp:verbose"`` option name
instead of ``"verbose"`` name, to avoid conflict with the Python
``verbose`` option.
Examples
========
@ -355,13 +687,13 @@ initialize Python.
void init_python(void)
{
PyInitConfig *config = PyInitConfig_Python_New();
PyInitConfig *config = PyInitConfig_CreatePython();
if (config == NULL) {
printf("Init allocation error\n");
return;
}
// Set an integer (dev_mode)
// Set an integer (dev mode)
if (PyInitConfig_SetInt(config, "dev_mode", 1) < 0) {
goto error;
}
@ -373,7 +705,7 @@ initialize Python.
goto error;
}
// Set a wide string (program_name)
// Set a wide string (program name)
if (PyInitConfig_SetWStr(config, "program_name", L"my_program") < 0) {
goto error;
}
@ -388,9 +720,15 @@ initialize Python.
// Initialize Python with the configuration
if (Py_InitializeFromInitConfig(config) < 0) {
Py_ExitWithInitConfig(config);
goto error;
}
PyInitConfig_Free(config);
return;
error:
// Display the error message an exit the process
// with a non-zero exit code
Py_ExitWithInitConfig(config);
}
@ -430,7 +768,9 @@ Backwards Compatibility
=======================
Changes are fully backward compatible. Only new APIs are added.
Existing API such as the ``PyConfig`` C API are left unchanged.
Existing API such as the ``PyConfig`` C API (PEP 587) are left
unchanged.
Rejected Ideas