Skip to content

Commit a315a34

Browse files
committed
PEP 743: Add Py_COMPAT_API_VERSION to the Python C API
1 parent e749257 commit a315a34

File tree

2 files changed

+215
-0
lines changed

2 files changed

+215
-0
lines changed

.github/CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ peps/pep-0738.rst @encukou
621621
peps/pep-0740.rst @dstufft
622622
peps/pep-0741.rst @vstinner
623623
peps/pep-0742.rst @JelleZijlstra
624+
peps/pep-0743.rst @vstinner
624625
# ...
625626
# peps/pep-0754.rst
626627
# ...

peps/pep-0743.rst

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
PEP: 743
2+
Title: Add Py_COMPAT_API_VERSION to the Python C API
3+
Author: Victor Stinner <[email protected]>
4+
Discussions-To: https://github.com/capi-workgroup/api-evolution/issues/24
5+
Status: Draft
6+
Type: Standards Track
7+
Created: 11-Mar-2024
8+
Python-Version: 3.13
9+
Post-History: `11-Oct-2023 <https://github.com/capi-workgroup/api-evolution/issues/24>`__,
10+
`23-Jun-2023 <https://github.com/capi-workgroup/problems/issues/54>`__,
11+
12+
13+
Abstract
14+
========
15+
16+
Add ``Py_COMPAT_API_VERSION`` and ``Py_COMPAT_API_VERSION_MAX`` macros
17+
to opt-in for planned incompatible C API changes in a C extension.
18+
Maintainers can decide when they make their C extension compatible
19+
and also decide which future Python version they want to be compatible
20+
with.
21+
22+
23+
Rationale
24+
=========
25+
26+
Python releases enforce C API changes
27+
-------------------------------------
28+
29+
Every Python 3.x release has a long list of C API changes, including
30+
incompatible changes. C extensions have to be updated to work on the
31+
newly released Python.
32+
33+
Some incompatible changes are driven by new features: they cannot be
34+
avoided, unless we decide to not add these features. Other reasons:
35+
36+
* Remove deprecated API (see :pep:`387`).
37+
* Ease the implementation of another change.
38+
* Change or remove error-prone API.
39+
40+
Currently, there is no middle ground between "not change the C API" and
41+
"incompatible C API changes impact everybody". Either a C extension is
42+
updated or the new Python version cannot be used. Such all-or-nothing
43+
deal does not satisfy C extension maintainers nor C extensions users.
44+
45+
46+
Limited C API
47+
-------------
48+
49+
The limited C API is versioned: the ``Py_LIMITED_API`` macro can be set
50+
to a Python version to select which API is available. On the Python
51+
side, it allows introducing incompatible changes at a specific
52+
``Py_LIMITED_API`` version. For example, if ``Py_LIMITED_API`` is set to
53+
Python 3.11 or newer, the ``<stdio.h>`` is no longer included by
54+
``Python.h``, whereas C extensions targeting Python 3.10 are not
55+
affected.
56+
57+
The difference here is that upgrading Python does not change if
58+
``<stdio.h>`` is included or not, but updating ``Py_LIMITED_API`` does.
59+
Updating ``Py_LIMITED_API`` is an deliberate action made by the C
60+
extension maintainer. It gives more freedom to decide **when** the
61+
maintainer is ready to deal with the latest batch of incompatible
62+
changes.
63+
64+
A similiar version can be used with the regular (non-limited) C API.
65+
66+
67+
Deprecation and compiler warnings
68+
---------------------------------
69+
70+
Some C API changes are scheduled over 3 years: deprecations. For
71+
example, a function is deprecated in Python 3.11 and only removed in
72+
Python 3.13. Deprecated functions are marked with ``Py_DEPRECATED()``
73+
which emits a compiler warning.
74+
75+
The problem is that ``pip`` and ``build`` tools hide compiler logs by
76+
default, unless a build fails. Moreover, it's easy to miss a single
77+
warning in the middle of hundred lines of logs.
78+
79+
Schedule changes
80+
----------------
81+
82+
Currently, there is no way to schedule a C API change: announce it but
83+
also provide a way to maintainers to test their C extensions with the
84+
change. Either a change is not made, or everybody must update their code
85+
if they want to update Python.
86+
87+
88+
Specification
89+
=============
90+
91+
New macros
92+
----------
93+
94+
Add new ``Py_COMPAT_API_VERSION`` and ``Py_COMPAT_API_VERSION_MAX``
95+
macros. They can be set to test if a C extension is prepared for future
96+
C API changes: compatible with future Python versions.
97+
98+
The ``Py_COMPAT_API_VERSION`` macro can be set to a specific Python
99+
version. For example, ``Py_COMPAT_API_VERSION=0x030e0000`` tests C API
100+
changes scheduled in Python 3.14.
101+
102+
If the ``Py_COMPAT_API_VERSION`` macro is set to
103+
``Py_COMPAT_API_VERSION_MAX``, all scheduled C API changes are tested at
104+
once.
105+
106+
If the ``Py_COMPAT_API_VERSION`` macro is not set, it is to
107+
``PY_VERSION_HEX`` by default.
108+
109+
The ``Py_COMPAT_API_VERSION`` macro can be set in a single C file or for
110+
a whole project in compiler flags. The macro does not affected other
111+
projects or Python itself.
112+
113+
114+
Example in Python
115+
-----------------
116+
117+
For example, the ``PyImport_ImportModuleNoBlock()`` function is
118+
deprecated in Python 3.13 and scheduled for removal in Python 3.15. The
119+
function can be declared in the Python C API with the following
120+
declaration::
121+
122+
#if Py_COMPAT_API_VERSION < 0x030f0000
123+
Py_DEPRECATED(3.13) PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock(
124+
const char *name /* UTF-8 encoded string */
125+
);
126+
#endif
127+
128+
If ``if Py_COMPAT_API_VERSION`` is equal to or greate than Python 3.15
129+
(``0x030f0000``), the ``PyImport_ImportModuleNoBlock()`` function is not
130+
declared, and so using it fails with a build error.
131+
132+
Goals
133+
-----
134+
135+
* Reduce the number of C API changes affecting C extensions when
136+
updating Python.
137+
* When testing C extensions (ex: optional CI test),
138+
``Py_COMPAT_API_VERSION`` can be set to ``Py_COMPAT_API_VERSION_MAX``
139+
to detect future incompatibilities. For mandatory tests, it is
140+
recommended to set ``Py_COMPAT_API_VERSION`` to a specific Python
141+
version.
142+
* For core developers, make sure that the C API can still evolve
143+
without being afraid of breaking an unknown number of C extensions.
144+
145+
Non-goals
146+
---------
147+
148+
* Freeze the API forever: this is not the stable ABI. For example,
149+
deprecated functions will continue to be removed on a regular basis.
150+
* C extensions maintainers not using ``Py_COMPAT_API_VERSION`` will
151+
still be affected by C API changes when updating Python.
152+
* Provide a stable ABI: the macro only impacts the regular (non-limited)
153+
API.
154+
* Silver bullet solving all C API issues.
155+
156+
157+
Examples of ``Py_COMPAT_API_VERSION`` usages
158+
============================================
159+
160+
* Remove deprecated functions.
161+
* Remove deprecated structure members, such as
162+
``PyBytesObject.ob_shash``.
163+
* Remove a standard ``#include``, such as ``#include <string.h>``,
164+
from ``<Python.h>``.
165+
* Change the behavior of a function or a macro. For example, calling
166+
``PyObject_SetAttr(obj, name, NULL)`` can fail, to enforce the usage
167+
of the ``PyObject_DelAttr()`` function instead to delete an attribute.
168+
169+
170+
Implementation
171+
==============
172+
173+
* `Issue gh-116587 <https://github.com/python/cpython/issues/116587>`_
174+
* PR: `Add Py_COMPAT_API_VERSION and Py_COMPAT_API_VERSION_MAX macros
175+
<https://github.com/python/cpython/pull/116588>`_
176+
177+
178+
Backwards Compatibility
179+
=======================
180+
181+
There is no impact on backward compatibility.
182+
183+
Adding ``Py_COMPAT_API_VERSION`` and ``Py_COMPAT_API_VERSION_MAX``
184+
macros has no effect on backward compatibility. Only developers setting
185+
the ``Py_COMPAT_API_VERSION`` macro in their project will be impacted by
186+
effects of this macro which is the expected behavior.
187+
188+
189+
Discussions
190+
===========
191+
192+
* C API Evolutions: `Macro to hide deprecated functions
193+
<https://github.com/capi-workgroup/api-evolution/issues/24>`_
194+
(October 2023)
195+
* C API Problems: `Opt-in macro for a new clean API? Subset of functions
196+
with no known issues
197+
<https://github.com/capi-workgroup/problems/issues/54>`_
198+
(June 2023)
199+
200+
201+
Prior Art
202+
=========
203+
204+
* ``Py_LIMITED_API`` macro of `PEP 384 – Defining a Stable ABI
205+
<https://peps.python.org/pep-0384/>`_.
206+
* Rejected `PEP 606 – Python Compatibility Version
207+
<https://peps.python.org/pep-0606/>`_ which has a global scope.
208+
209+
210+
Copyright
211+
=========
212+
213+
This document is placed in the public domain or under the
214+
CC0-1.0-Universal license, whichever is more permissive.

0 commit comments

Comments
 (0)