Skip to content
Closed
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
87 changes: 87 additions & 0 deletions Doc/c-api/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1117,124 +1117,186 @@ For completeness, here are all the variables:
Exception types
---------------

These pointers are part of the :ref:`Stable ABI <stable>` since the version
in the *S.ABI* column, or since 3.2 if that column is empty.
Exceptions marked N/A are *not* part of the Stable ABI.

.. list-table::
:align: left
:widths: auto
:header-rows: 1
:class: no-stable-abi-notes

* * C name
* :ref:`S.ABI <stable>`
* Python name
* * .. c:var:: PyObject *PyExc_BaseException
*
* :exc:`BaseException`
* * .. c:var:: PyObject *PyExc_BaseExceptionGroup
* 3.11
* :exc:`BaseExceptionGroup`
* * .. c:var:: PyObject *PyExc_Exception
*
* :exc:`Exception`
* * .. c:var:: PyObject *PyExc_ArithmeticError
*
* :exc:`ArithmeticError`
* * .. c:var:: PyObject *PyExc_AssertionError
*
* :exc:`AssertionError`
* * .. c:var:: PyObject *PyExc_AttributeError
*
* :exc:`AttributeError`
* * .. c:var:: PyObject *PyExc_BlockingIOError
* 3.7
* :exc:`BlockingIOError`
* * .. c:var:: PyObject *PyExc_BrokenPipeError
* 3.7
* :exc:`BrokenPipeError`
* * .. c:var:: PyObject *PyExc_BufferError
*
* :exc:`BufferError`
* * .. c:var:: PyObject *PyExc_ChildProcessError
* 3.7
* :exc:`ChildProcessError`
* * .. c:var:: PyObject *PyExc_ConnectionAbortedError
* 3.7
* :exc:`ConnectionAbortedError`
* * .. c:var:: PyObject *PyExc_ConnectionError
* 3.7
* :exc:`ConnectionError`
* * .. c:var:: PyObject *PyExc_ConnectionRefusedError
* 3.7
* :exc:`ConnectionRefusedError`
* * .. c:var:: PyObject *PyExc_ConnectionResetError
* 3.7
* :exc:`ConnectionResetError`
* * .. c:var:: PyObject *PyExc_EOFError
*
* :exc:`EOFError`
* * .. c:var:: PyObject *PyExc_FileExistsError
* 3.7
* :exc:`FileExistsError`
* * .. c:var:: PyObject *PyExc_FileNotFoundError
* 3.7
* :exc:`FileNotFoundError`
* * .. c:var:: PyObject *PyExc_FloatingPointError
*
* :exc:`FloatingPointError`
* * .. c:var:: PyObject *PyExc_GeneratorExit
*
* :exc:`GeneratorExit`
* * .. c:var:: PyObject *PyExc_ImportCycleError
* N/A
* :exc:`ImportCycleError`
* * .. c:var:: PyObject *PyExc_ImportError
*
* :exc:`ImportError`
* * .. c:var:: PyObject *PyExc_IndentationError
*
* :exc:`IndentationError`
* * .. c:var:: PyObject *PyExc_IndexError
*
* :exc:`IndexError`
* * .. c:var:: PyObject *PyExc_InterruptedError
* 3.7
* :exc:`InterruptedError`
* * .. c:var:: PyObject *PyExc_IsADirectoryError
* 3.7
* :exc:`IsADirectoryError`
* * .. c:var:: PyObject *PyExc_KeyError
*
* :exc:`KeyError`
* * .. c:var:: PyObject *PyExc_KeyboardInterrupt
*
* :exc:`KeyboardInterrupt`
* * .. c:var:: PyObject *PyExc_LookupError
*
* :exc:`LookupError`
* * .. c:var:: PyObject *PyExc_MemoryError
*
* :exc:`MemoryError`
* * .. c:var:: PyObject *PyExc_ModuleNotFoundError
* 3.6
* :exc:`ModuleNotFoundError`
* * .. c:var:: PyObject *PyExc_NameError
*
* :exc:`NameError`
* * .. c:var:: PyObject *PyExc_NotADirectoryError
* 3.7
* :exc:`NotADirectoryError`
* * .. c:var:: PyObject *PyExc_NotImplementedError
*
* :exc:`NotImplementedError`
* * .. c:var:: PyObject *PyExc_OSError
*
* :exc:`OSError`
* * .. c:var:: PyObject *PyExc_OverflowError
*
* :exc:`OverflowError`
* * .. c:var:: PyObject *PyExc_PermissionError
* 3.7
* :exc:`PermissionError`
* * .. c:var:: PyObject *PyExc_ProcessLookupError
* 3.7
* :exc:`ProcessLookupError`
* * .. c:var:: PyObject *PyExc_PythonFinalizationError
* N/A
* :exc:`PythonFinalizationError`
* * .. c:var:: PyObject *PyExc_RecursionError
* 3.7
* :exc:`RecursionError`
* * .. c:var:: PyObject *PyExc_ReferenceError
*
* :exc:`ReferenceError`
* * .. c:var:: PyObject *PyExc_RuntimeError
*
* :exc:`RuntimeError`
* * .. c:var:: PyObject *PyExc_StopAsyncIteration
* 3.7
* :exc:`StopAsyncIteration`
* * .. c:var:: PyObject *PyExc_StopIteration
*
* :exc:`StopIteration`
* * .. c:var:: PyObject *PyExc_SyntaxError
*
* :exc:`SyntaxError`
* * .. c:var:: PyObject *PyExc_SystemError
*
* :exc:`SystemError`
* * .. c:var:: PyObject *PyExc_SystemExit
*
* :exc:`SystemExit`
* * .. c:var:: PyObject *PyExc_TabError
*
* :exc:`TabError`
* * .. c:var:: PyObject *PyExc_TimeoutError
* 3.7
* :exc:`TimeoutError`
* * .. c:var:: PyObject *PyExc_TypeError
*
* :exc:`TypeError`
* * .. c:var:: PyObject *PyExc_UnboundLocalError
*
* :exc:`UnboundLocalError`
* * .. c:var:: PyObject *PyExc_UnicodeDecodeError
*
* :exc:`UnicodeDecodeError`
* * .. c:var:: PyObject *PyExc_UnicodeEncodeError
*
* :exc:`UnicodeEncodeError`
* * .. c:var:: PyObject *PyExc_UnicodeError
*
* :exc:`UnicodeError`
* * .. c:var:: PyObject *PyExc_UnicodeTranslateError
*
* :exc:`UnicodeTranslateError`
* * .. c:var:: PyObject *PyExc_ValueError
*
* :exc:`ValueError`
* * .. c:var:: PyObject *PyExc_ZeroDivisionError
*
* :exc:`ZeroDivisionError`

.. versionadded:: 3.3
Expand Down Expand Up @@ -1265,21 +1327,29 @@ The following are a compatibility aliases to :c:data:`PyExc_OSError`.
.. versionchanged:: 3.3
These aliases used to be separate exception types.

These pointers are part of the :ref:`Stable ABI <stable>` since the version
in the *S.ABI* column, or since 3.2 if that column is empty.

.. list-table::
:align: left
:widths: auto
:header-rows: 1
:class: no-stable-abi-notes

* * C name
* :ref:`S.ABI <stable>`
* Python name
* Notes
* * .. c:var:: PyObject *PyExc_EnvironmentError
*
* :exc:`OSError`
*
* * .. c:var:: PyObject *PyExc_IOError
*
* :exc:`OSError`
*
* * .. c:var:: PyObject *PyExc_WindowsError
* 3.7
* :exc:`OSError`
* [win]_

Expand All @@ -1295,36 +1365,53 @@ Notes:
Warning types
-------------

These pointers are part of the :ref:`Stable ABI <stable>` since the version
in the *S.ABI* column, or since 3.2 if that column is empty.

.. list-table::
:align: left
:widths: auto
:header-rows: 1
:class: no-stable-abi-notes

* * C name
* :ref:`S.ABI <stable>`
* Python name
* * .. c:var:: PyObject *PyExc_Warning
*
* :exc:`Warning`
* * .. c:var:: PyObject *PyExc_BytesWarning
*
* :exc:`BytesWarning`
* * .. c:var:: PyObject *PyExc_DeprecationWarning
*
* :exc:`DeprecationWarning`
* * .. c:var:: PyObject *PyExc_EncodingWarning
* 3.10
* :exc:`EncodingWarning`
* * .. c:var:: PyObject *PyExc_FutureWarning
*
* :exc:`FutureWarning`
* * .. c:var:: PyObject *PyExc_ImportWarning
*
* :exc:`ImportWarning`
* * .. c:var:: PyObject *PyExc_PendingDeprecationWarning
*
* :exc:`PendingDeprecationWarning`
* * .. c:var:: PyObject *PyExc_ResourceWarning
* 3.7
* :exc:`ResourceWarning`
* * .. c:var:: PyObject *PyExc_RuntimeWarning
*
* :exc:`RuntimeWarning`
* * .. c:var:: PyObject *PyExc_SyntaxWarning
*
* :exc:`SyntaxWarning`
* * .. c:var:: PyObject *PyExc_UnicodeWarning
*
* :exc:`UnicodeWarning`
* * .. c:var:: PyObject *PyExc_UserWarning
*
* :exc:`UserWarning`

.. versionadded:: 3.2
Expand Down
30 changes: 28 additions & 2 deletions Doc/tools/extensions/c_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
"data": "var",
}

# Class that suppresses the generated Stable ABI notes for all C API
# elements documented inside the element it is set on (see
# ``_stable_abi_note_suppressed``).
NO_STABLE_ABI_NOTES_CLASS = "no-stable-abi-notes"


@dataclasses.dataclass(slots=True)
class RefCountEntry:
Expand Down Expand Up @@ -183,8 +188,9 @@ def add_annotations(app: Sphinx, doctree: nodes.document) -> None:
f"{ROLE_TO_OBJECT_TYPE[record.role]!r} != {objtype!r}"
)
raise ValueError(msg)
annotation = _stable_abi_annotation(record)
node.insert(0, annotation)
if not _stable_abi_note_suppressed(node):
annotation = _stable_abi_annotation(record)
node.insert(0, annotation)

# Unstable API annotation.
if name.startswith("PyUnstable"):
Expand All @@ -203,6 +209,26 @@ def add_annotations(app: Sphinx, doctree: nodes.document) -> None:
node.insert(0, annotation)


def _stable_abi_note_suppressed(node: nodes.Element) -> bool:
"""Return whether an ancestor of *node* opts out of Stable ABI notes.

In compact tables of many similar definitions, the generated notes
get repetitive and take up too much vertical space.
Such a table can instead carry a single manually written note, and
suppress the generated ones by setting the ``no-stable-abi-notes``
class, for example::

.. list-table::
:class: no-stable-abi-notes
"""
ancestor = node.parent
while ancestor is not None:
if NO_STABLE_ABI_NOTES_CLASS in ancestor.get("classes", ()):
return True
ancestor = ancestor.parent
return False


def _stable_abi_annotation(
record: StableABIEntry,
is_corresponding_slot: bool = False,
Expand Down
Loading