PEP 741: Add sys.set_config() (#3709)

This commit is contained in:
Victor Stinner 2024-03-09 21:44:22 +01:00 committed by GitHub
parent c4a5976ff3
commit 66ecf110b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 334 additions and 91 deletions

View File

@ -16,8 +16,10 @@ 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 also ``sys.get_config(name)`` and ``sys.get_config_names()``
functions to get the current configuration.
Add ``sys.get_config(name)`` and ``sys.get_config_names()`` functions to
get the current configuration. Add ``sys.set_config(name, value)``
function to set a configuration option. Unified API to access all
configuration options.
Complete :pep:`587` API by adding ``PyInitConfig_AddModule()`` which can be
used to add a built-in extension module; feature previously referred to
@ -120,7 +122,7 @@ Cython needs to access the ``optimization_level`` configuration option:
When global configuration variables were deprecated in 2022, `Marc-André
Lemburg requested
<https://github.com/python/cpython/issues/93103#issuecomment-1136462708>`_
<https://github.com/python/cpython/issues/93103#issuecomment-1136462708>`__
an API to access these configuration variables at runtime (not only
during Python initialization).
@ -359,6 +361,35 @@ which doesn't take in account environment variables.
The ``sys.get_int_max_str_digits()`` function can be used to get the
``int_max_str_digits`` option.
Set the current configuration
-----------------------------
`Marc-André Lemburg requested
<https://discuss.python.org/t/fr-allow-private-runtime-config-to-enable-extending-without-breaking-the-pyconfig-abi/18004/34>`__
an API to **set** the value of some configuration options at runtime:
* ``optimization_level``
* ``verbose``
* ``parser_debug``
* ``inspect``
* ``write_bytecode``
Moreover, currently, when a new configuration option is added, usually
"get" and "set" functions should be added as well. It makes the ``sys``
module bigger and bigger, whereas not all options deserves dedicated
functions. For example, when the ``int_max_str_digits`` option was
added, ``sys.get_int_max_str_digits()`` and
``sys.set_int_max_str_digits()`` functions were added as well.
Some options are exposed directly as ``sys`` attributes. For example,
the ``module_search_paths`` option is expoed as ``sys.path``. The
problem is that there is no validation when the attribute is modified
which can lead to various bugs or even crashes. The attribute can even
be removed: ``del sys.path``.
Having a single unified API with generic "get" and "set" functions would
avoid these issues and give access to all configuration options.
Specification
=============
@ -394,9 +425,11 @@ Add C API and Python functions to get the current configuration:
* ``PyConfig_Get(name)``.
* ``PyConfig_GetInt(name, &value)``.
* ``PyConfig_Set(name)``.
* ``PyConfig_Keys()``.
* ``sys.get_config(name)``.
* ``sys.get_config_names()``.
* ``sys.set_config(name, value)``.
The C API uses null-terminated UTF-8 encoded strings to refer to a
configuration option.
@ -419,82 +452,8 @@ The ``PyStatus`` status is no longer separated, but part of the unified
Configuration Options
---------------------
Configuration option names:
* ``"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).
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
structure members. 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>`_.
@ -502,6 +461,274 @@ the `PyConfig documentation
Deprecating and removing configuration options is out of the scope of
the PEP and should be discussed on a case by case basis.
Public configuration options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Following options can be get by ``sys.get_config()`` and set and
``sys.set_config()``.
.. list-table::
* - Option
- Type
- Comment
* - ``"argv"``
- ``list[str]``
- API: ``sys.argv`` (``list[str]``).
* - ``"base_exec_prefix"``
- ``str``
- API: ``sys.base_exec_prefix`` (``str``).
* - ``"base_executable"``
- ``str``
- API: ``sys.base_executable`` (``str``).
* - ``"base_prefix"``
- ``str``
- API: ``sys.base_prefix`` (``str``).
* - ``"bytes_warning"``
- ``int``
- API: ``sys.flags.bytes_warning`` (``int``).
* - ``"exec_prefix"``
- ``str``
- API: ``sys.base_prefix`` (``str``).
* - ``"executable"``
- ``str``
- API: ``sys.executable`` (``str``).
* - ``"inspect"``
- ``bool``
- API: ``sys.flags.inspect`` (``int``).
* - ``"int_max_str_digits"``
- ``int``
- API: ``sys.flags.int_max_str_digits`` (``int``),
``sys.get_int_max_str_digits()`` and
``sys.set_int_max_str_digits()``.
* - ``"interactive"``
- ``bool``
- API: ``sys.flags.interactive`` (``int``).
* - ``"module_search_paths"``
- ``list[str]``
- API: ``sys.path`` (``list[str]``).
* - ``"optimization_level"``
- ``int``
- API: ``sys.flags.optimize`` (``int``).
* - ``"parser_debug"``
- ``bool``
- API: ``sys.flags.debug`` (``int``).
* - ``"platlibdir"``
- ``str``
- API: ``sys.platlibdir`` (``str``).
* - ``"prefix"``
- ``str``
- API: ``sys.base_prefix`` (``str``).
* - ``"pycache_prefix"``
- ``str``
- API: ``sys.pycache_prefix`` (``str``).
* - ``"quiet"``
- ``bool``
- API: ``sys.flags.quiet`` (``int``).
* - ``"stdlib_dir"``
- ``str``
- API: ``sys._stdlib_dir`` (``str``).
* - ``"use_environment"``
- ``bool``
- API: ``sys.flags.ignore_environment`` (``int``).
* - ``"verbose"``
- ``int``
- API: ``sys.flags.verbose`` (``int``).
* - ``"warnoptions"``
- ``list[str]``
- API: ``sys.warnoptions`` (``list[str]``).
* - ``"write_bytecode"``
- ``bool``
- API: ``sys.flags.dont_write_bytecode`` (``int``) and ``sys.dont_write_bytecode`` (``bool``).
* - ``"xoptions"``
- ``dict[str, str]``
- API: ``sys._xoptions`` (``dict[str, str]``).
Some option names are different than ``sys`` attributes, such as
``"optimization_level"`` option and ``sys.flags.optimize`` attribute.
``sys.set_config(name, value)`` sets the corresponding ``sys``
attribute.
Read-only configuration options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Following options can be get ``sys.get_config()``, but cannot be set by
``sys.set_config()``.
.. list-table::
* - Option
- Type
- Comment
* - ``"check_hash_pycs_mode"``
- ``str``
- API: ``imp.check_hash_pycs_mode`` (``str``).
* - ``"code_debug_ranges"``
- ``bool``
-
* - ``"coerce_c_locale"``
- ``bool``
-
* - ``"coerce_c_locale_warn"``
- ``bool``
-
* - ``"configure_locale"``
- ``bool``
-
* - ``"cpu_count"``
- ``int``
- API: ``os.cpu_count()`` (``int | None``).
* - ``"dev_mode"``
- ``bool``
- API: ``sys.flags.dev_mode`` (``bool``).
* - ``"filesystem_encoding"``
- ``str``
- API: ``sys.getfilesystemencoding()`` (``str``).
* - ``"filesystem_errors"``
- ``str``
- API: ``sys.getfilesystemencodeerrors()`` (``str``).
* - ``"import_time"``
- ``bool``
-
* - ``"isolated"``
- ``bool``
- API: ``sys.flags.isolated`` (``int``).
* - ``"legacy_windows_fs_encoding"``
- ``bool``
-
* - ``"orig_argv"``
- ``list[str]``
- API: ``sys.orig_argv`` (``list[str]``).
* - ``"perf_profiling"``
- ``bool``
- API: ``sys.is_stack_trampoline_active()``.
* - ``"site_import"``
- ``bool``
- API: ``sys.flags.no_site`` (``int``).
* - ``"utf8_mode"``
- ``bool``
-
Initialization-only configuration options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Following options are only to initialize Python, are not in
``sys.get_config_names()``, and cannot be get with ``sys.get_config()``.
.. list-table::
* - Option
- Type
- Comment
* - ``"allocator"``
- ``int``
-
* - ``"buffered_stdio"``
- ``bool``
-
* - ``"configure_c_stdio"``
- ``bool``
-
* - ``"dump_refs"``
- ``bool``
-
* - ``"dump_refs_file"``
- ``str``
-
* - ``"faulthandler"``
- ``bool``
- API: ``faulthandler.is_enabled()`` (``bool``).
* - ``"hash_seed"``
- ``int``
-
* - ``"home"``
- ``str``
-
* - ``"install_signal_handlers"``
- ``bool``
-
* - ``"legacy_windows_stdio"``
- ``bool``
- Windows only
* - ``"malloc_stats"``
- ``bool``
-
* - ``"module_search_paths_set"``
- ``bool``
-
* - ``"pathconfig_warnings"``
- ``bool``
-
* - ``"parse_argv"``
- ``bool``
-
* - ``"program_name"``
- ``str``
-
* - ``"pythonpath_env"``
- ``str``
-
* - ``"run_command"``
- ``str``
-
* - ``"run_filename"``
- ``str``
-
* - ``"run_module"``
- ``str``
-
* - ``"run_presite"``
- ``str``
- need a debug build.
* - ``"safe_path"``
- ``bool``
-
* - ``"show_ref_count"``
- ``bool``
-
* - ``"skip_source_first_line"``
- ``bool``
-
* - ``"stdio_encoding"``
- ``str``
- API: ``sys.stdin.encoding``, ``sys.stdout.encoding`` and
``sys.stderr.encoding`` (``str``).
* - ``"stdio_errors"``
- ``str``
- API: ``sys.stdin.errors``, ``sys.stdout.errors`` and
``sys.stderr.errors`` (``str``).
* - ``"sys_path_0"``
- ``str``
-
* - ``"tracemalloc"``
- ``int``
- API: ``tracemalloc.is_tracing()`` (``bool``).
* - ``"use_frozen_modules"``
- ``bool``
-
* - ``"use_hash_seed"``
- ``bool``
-
* - ``"user_site_directory"``
- ``bool``
- API: ``sys.flags.no_user_site`` (``int``).
* - ``"warn_default_encoding"``
- ``bool``
-
* - ``"_install_importlib"``
- ``bool``
-
* - ``"_init_main"``
- ``bool``
-
* - ``"_is_python_build"``
- ``bool``
-
* - ``"_pystats"``
- ``bool``
- API: ``sys._stats_on()``, ``sys._stats_off()``.
Need a ``Py_STATS`` build.
Preconfiguration
----------------
@ -732,12 +959,17 @@ Error handling
error message.
Get current configuration
-------------------------
Get and set the current configuration
-------------------------------------
The configuration option *name* parameter must be a non-NULL
null-terminated UTF-8 encoded string.
Not all configuration options are accessible at runtime: see
`Configuration Options`_. For example, ``"module_search_paths_set"`` is
not relevant and cannot be accessed. Some options are read-only and can
only be read, such as ``"utf8_mode"``.
``PyObject* PyConfig_Get(const char *name)``:
Get the current value of a configuration option as an object.
@ -783,22 +1015,33 @@ null-terminated UTF-8 encoded string.
The caller must hold the GIL.
``PyObject* PyConfig_Set(const char *name, PyObject *value)``:
Set the value of a configuration option.
sys.get_config()
----------------
* Raise a ``ValueError`` if there is no option *name*.
* Raise a ``TypeError`` if *value* has not the proper type.
* Raise a ``ValueError`` if *value* is an invalid value.
* Raise a ``ValueError`` if the option is read-only: cannot be set.
Add ``sys.get_config(name: str)`` function which calls
``PyConfig_Get()``:
* Return the configuration option value on success.
* Raise an exception on error.
The caller must hold the GIL. The function cannot be called before
Python initialization nor after Python finalization.
sys.get_config_names()
----------------------
Add sys functions
-----------------
* Add ``sys.get_config(name: str)`` function which calls
``PyConfig_Get()``:
* Return the configuration option value on success.
* Raise an exception on error.
* Add ``sys.get_config_names()`` function which gets all configuration
option names as a ``frozenset``.
* Add ``sys.get_config(name: str, value)`` function which calls
``PyConfig_Set(name, value)``. Raise an exception on error.
Add ``sys.get_config_names()`` function which gets all configuration
option names as a ``frozenset``.
Scope of the stable ABI
-----------------------