Skip to content

Commit 0fcf2b7

Browse files
encukouhugovk
andauthored
gh-146636: PEP 803: Reference documentation (GH-148013)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
1 parent 1f6a09f commit 0fcf2b7

File tree

9 files changed

+290
-116
lines changed

9 files changed

+290
-116
lines changed

Doc/c-api/module.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,12 @@ remove it.
685685
Usually, there is only one variable of this type for each extension module
686686
defined this way.
687687
688+
The struct, including all members, is part of the
689+
:ref:`Stable ABI <stable-abi>` for non-free-threaded builds (``abi3``).
690+
In the Stable ABI for free-threaded builds (``abi3t``),
691+
this struct is opaque, and unusable in practice; see :ref:`pymoduledef_slot`
692+
for a replacement.
693+
688694
.. c:member:: PyModuleDef_Base m_base
689695
690696
Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`:
@@ -695,6 +701,11 @@ remove it.
695701
696702
The type of :c:member:`!PyModuleDef.m_base`.
697703

704+
The struct is part of the :ref:`Stable ABI <stable-abi>` for
705+
non-free-threaded builds (``abi3``).
706+
In the Stable ABI for Free-Threaded Builds
707+
(``abi3t``), this struct is opaque, and unusable in practice.
708+
698709
.. c:macro:: PyModuleDef_HEAD_INIT
699710
700711
The required initial value for :c:member:`!PyModuleDef.m_base`.

Doc/c-api/stable.rst

Lines changed: 173 additions & 97 deletions
Large diffs are not rendered by default.

Doc/c-api/structures.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ under :ref:`reference counting <countingrefs>`.
3333
The members must not be accessed directly; instead use macros such as
3434
:c:macro:`Py_REFCNT` and :c:macro:`Py_TYPE`.
3535

36+
In the :ref:`Stable ABI <stable-abi>` for Free-Threaded Builds (``abi3t``),
37+
this struct is opaque; its size and layout may change between
38+
Python versions.
39+
In Stable ABI for non-free-threaded builds (``abi3``), the
40+
:c:member:`!ob_refcnt` and :c:member:`!ob_type` fields are available,
41+
but using them directly is discouraged.
42+
3643
.. c:member:: Py_ssize_t ob_refcnt
3744
3845
The object's reference count, as returned by :c:macro:`Py_REFCNT`.
@@ -72,6 +79,19 @@ under :ref:`reference counting <countingrefs>`.
7279
instead use macros such as :c:macro:`Py_SIZE`, :c:macro:`Py_REFCNT` and
7380
:c:macro:`Py_TYPE`.
7481

82+
In the :ref:`Stable ABI <stable-abi>` for Free-Threaded Builds (``abi3t``),
83+
this struct is opaque; its size and layout may change between
84+
Python versions.
85+
In Stable ABI for non-free-threaded builds (``abi3``), the
86+
:c:member:`!ob_base` and :c:member:`!ob_size` fields are available,
87+
but using them directly is discouraged.
88+
89+
.. c:member:: PyObject ob_base
90+
91+
Common object header.
92+
Typically, this field is not accessed directly; instead
93+
:c:type:`!PyVarObject` can be cast to :c:type:`PyObject`.
94+
7595
.. c:member:: Py_ssize_t ob_size
7696
7797
A size field, whose contents should be considered an object's internal

Doc/data/stable_abi.dat

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/tools/extensions/c_annotations.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -249,18 +249,17 @@ def _stable_abi_annotation(
249249
reftype="ref",
250250
refexplicit="False",
251251
)
252-
struct_abi_kind = record.struct_abi_kind
253-
if struct_abi_kind in {"opaque", "members"}:
254-
ref_node += nodes.Text(sphinx_gettext("Limited API"))
255-
else:
256-
ref_node += nodes.Text(sphinx_gettext("Stable ABI"))
252+
ref_node += nodes.Text(sphinx_gettext("Stable ABI"))
257253
emph_node += ref_node
254+
struct_abi_kind = record.struct_abi_kind
258255
if struct_abi_kind == "opaque":
259256
emph_node += nodes.Text(" " + sphinx_gettext("(as an opaque struct)"))
260257
elif struct_abi_kind == "full-abi":
261258
emph_node += nodes.Text(
262259
" " + sphinx_gettext("(including all members)")
263260
)
261+
elif struct_abi_kind in {"members", "abi3t-opaque"}:
262+
emph_node += nodes.Text(" " + sphinx_gettext("(see below)"))
264263
if record.ifdef_note:
265264
emph_node += nodes.Text(f" {record.ifdef_note}")
266265
if stable_added == "3.2":
@@ -271,11 +270,7 @@ def _stable_abi_annotation(
271270
" " + sphinx_gettext("since version %s") % stable_added
272271
)
273272
emph_node += nodes.Text(".")
274-
if struct_abi_kind == "members":
275-
msg = " " + sphinx_gettext(
276-
"(Only some members are part of the stable ABI.)"
277-
)
278-
emph_node += nodes.Text(msg)
273+
279274
return emph_node
280275

281276

@@ -378,6 +373,33 @@ def run(self) -> list[nodes.Node]:
378373
return [node]
379374

380375

376+
class VersionHexCheatsheet(SphinxDirective):
377+
"""Show results of Py_PACK_VERSION(3, x) for a few relevant Python versions
378+
379+
This is useful for defining version before Python.h is included.
380+
It should auto-update with the version being documented, so it must be an
381+
extension.
382+
"""
383+
384+
has_content = False
385+
required_arguments = 0
386+
optional_arguments = 0
387+
final_argument_whitespace = True
388+
389+
def run(self) -> list[nodes.Node]:
390+
content = [
391+
".. code-block:: c",
392+
"",
393+
]
394+
current_minor = int(self.config.version.removeprefix('3.'))
395+
for minor in range(current_minor - 5, current_minor + 1):
396+
value = (3 << 24) | (minor << 16)
397+
content.append(f' {value:#x} /* Py_PACK_VERSION(3.{minor}) */')
398+
node = nodes.paragraph()
399+
self.state.nested_parse(StringList(content), 0, node)
400+
return [node]
401+
402+
381403
class CorrespondingTypeSlot(SphinxDirective):
382404
"""Type slot annotations
383405
@@ -443,6 +465,7 @@ def setup(app: Sphinx) -> ExtensionMetadata:
443465
app.add_config_value("stable_abi_file", "", "env", types={str})
444466
app.add_config_value("threadsafety_file", "", "env", types={str})
445467
app.add_directive("limited-api-list", LimitedAPIList)
468+
app.add_directive("version-hex-cheatsheet", VersionHexCheatsheet)
446469
app.add_directive("corresponding-type-slot", CorrespondingTypeSlot)
447470
app.connect("builder-inited", init_annotations)
448471
app.connect("doctree-read", add_annotations)

Doc/whatsnew/3.15.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ Summary -- Release highlights
8282
<whatsnew315-typeform>`
8383
* :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object
8484
<whatsnew315-pybyteswriter>`
85+
* :pep:`803`: :ref:`Stable ABI for Free-Threaded Builds <whatsnew315-abi3t>`
8586
* :ref:`The JIT compiler has been significantly upgraded <whatsnew315-jit>`
8687
* :ref:`Improved error messages <whatsnew315-improved-error-messages>`
8788
* :ref:`The official Windows 64-bit binaries now use the tail-calling interpreter
@@ -381,6 +382,41 @@ agen() for x in a)``.
381382

382383
(Contributed by Adam Hartz in :gh:`143055`.)
383384

385+
.. _whatsnew315-abi3t:
386+
387+
:pep:`803`: ``abi3t`` -- Stable ABI for Free-Threaded Builds
388+
------------------------------------------------------------
389+
390+
C extensions that target the :ref:`Stable ABI <stable-abi>` can now be
391+
compiled for the new *Stable ABI for Free-Threaded Builds* (also known
392+
as ``abi3t``), which makes them compatible with
393+
:term:`free-threaded builds <free-threaded build>` of CPython.
394+
This usually requires some non-trivial changes to the source code;
395+
specifically:
396+
397+
- Switching to API introduced in :pep:`697` (Python 3.12), such as
398+
negative :c:member:`~PyType_Spec.basicsize` and
399+
:c:func:`PyObject_GetTypeData`, rather than making :c:type:`PyObject`
400+
part of the instance struct; and
401+
- Switching from a ``PyInit_`` function to a new export hook,
402+
:c:func:`PyModExport_* <PyModExport_modulename>`, introduced for this
403+
purpose in :pep:`793`.
404+
405+
Note that Stable ABI does not offer all the functionality that CPython
406+
has to offer.
407+
Extensions that cannot switch to ``abi3t`` should continue to build for
408+
the existing Stable ABI (``abi3``) and the version-specific ABI for
409+
free-threading (``cp315t``) separately.
410+
411+
Stable ABI for Free-Threaded Builds should typically
412+
be selected in a build tool (such as, for example, Setuptools, meson-python,
413+
scikit-build-core, or Maturin).
414+
At the time of writing, these tools did **not** support ``abi3t``.
415+
If this is the case for your tool, compile for ``cp315t`` separately.
416+
If not using a build tool -- or when writing such a tool -- you can select
417+
``abi3t`` by setting the macro :c:macro:`!Py_TARGET_ABI3T` as discussed
418+
in :ref:`abi3-compiling`.
419+
384420

385421
.. _whatsnew315-improved-error-messages:
386422

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement :pep:`803` -- ``abi3t``: Stable ABI for Free-Threaded Builds.

Misc/stable_abi.toml

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# This file lists the contents of the Limited API and Stable ABI.
1+
# This file lists the contents of Limited API and Stable ABI.
22
# Please append new items at the end.
33

44
# The syntax of this file is not fixed.
@@ -46,15 +46,24 @@
4646
# - 'opaque': No members are part of the ABI, nor is the size. The Limited
4747
# API only handles these via pointers. The C definition should be
4848
# incomplete (opaque).
49-
# - 'members': Only specific members are part of the stable ABI.
50-
# The struct's size may change, so it can't be used in arrays.
49+
# - 'abi3t-opaque': 'full-abi' in abi3; 'opaque' in abi3t.
50+
# For docs, the generated annotation refers to details that need to
51+
# be added to the ReST file manually.
52+
# - 'members':
53+
# - 'opaque' in abi3t.
54+
# - In abi3, only specific members are part of the stable ABI.
55+
# The struct's size may change, so it can't be used in arrays.
5156
# Do not add new structs of this kind without an extremely good reason.
57+
# For docs, the generated annotation refers to details that need to
58+
# be added to the ReST file manually.
5259
# - members: For `struct` with struct_abi_kind = 'members', a list of the
5360
# exposed members.
5461
# - doc: for `feature_macro`, the blurb added in documentation
5562
# - windows: for `feature_macro`, this macro is defined on Windows.
5663
# (This info is used to generate the DLL manifest and needs to be available
5764
# on all platforms.)
65+
# - abi3t_opaque: In abi3t, this struct is opaque (as if `struct_abi_kind`
66+
# was 'opaque' and `members` was missing).
5867

5968
# Removing items from this file is generally not allowed, and additions should
6069
# be considered with that in mind. See the devguide for exact rules:
@@ -107,10 +116,10 @@
107116
struct_abi_kind = 'full-abi'
108117
[struct.PyModuleDef_Base]
109118
added = '3.2'
110-
struct_abi_kind = 'full-abi'
119+
struct_abi_kind = 'abi3t-opaque'
111120
[struct.PyModuleDef]
112121
added = '3.2'
113-
struct_abi_kind = 'full-abi'
122+
struct_abi_kind = 'abi3t-opaque'
114123
[struct.PyStructSequence_Field]
115124
added = '3.2'
116125
struct_abi_kind = 'full-abi'

Tools/check-c-api-docs/ignored_c_api.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ Py_HasFileSystemDefaultEncoding
1818
Py_UTF8Mode
1919
# pyhash.h
2020
Py_HASH_EXTERNAL
21-
# modsupport.h
22-
PyABIInfo_FREETHREADING_AGNOSTIC
2321
# object.h
2422
Py_INVALID_SIZE
2523
# pyexpat.h

0 commit comments

Comments
 (0)