diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 40522f8c7b13756..1fd2b1aa98dcd5b 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -1117,125 +1117,192 @@ For completeness, here are all the variables: Exception types --------------- -.. list-table:: - :align: left - :widths: auto - :header-rows: 1 - - * * C name - * Python name - * * .. c:var:: PyObject *PyExc_BaseException - * :exc:`BaseException` - * * .. c:var:: PyObject *PyExc_BaseExceptionGroup - * :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 - * :exc:`BlockingIOError` - * * .. c:var:: PyObject *PyExc_BrokenPipeError - * :exc:`BrokenPipeError` - * * .. c:var:: PyObject *PyExc_BufferError - * :exc:`BufferError` - * * .. c:var:: PyObject *PyExc_ChildProcessError - * :exc:`ChildProcessError` - * * .. c:var:: PyObject *PyExc_ConnectionAbortedError - * :exc:`ConnectionAbortedError` - * * .. c:var:: PyObject *PyExc_ConnectionError - * :exc:`ConnectionError` - * * .. c:var:: PyObject *PyExc_ConnectionRefusedError - * :exc:`ConnectionRefusedError` - * * .. c:var:: PyObject *PyExc_ConnectionResetError - * :exc:`ConnectionResetError` - * * .. c:var:: PyObject *PyExc_EOFError - * :exc:`EOFError` - * * .. c:var:: PyObject *PyExc_FileExistsError - * :exc:`FileExistsError` - * * .. c:var:: PyObject *PyExc_FileNotFoundError - * :exc:`FileNotFoundError` - * * .. c:var:: PyObject *PyExc_FloatingPointError - * :exc:`FloatingPointError` - * * .. c:var:: PyObject *PyExc_GeneratorExit - * :exc:`GeneratorExit` - * * .. c:var:: PyObject *PyExc_ImportCycleError - * :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 - * :exc:`InterruptedError` - * * .. c:var:: PyObject *PyExc_IsADirectoryError - * :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 - * :exc:`ModuleNotFoundError` - * * .. c:var:: PyObject *PyExc_NameError - * :exc:`NameError` - * * .. c:var:: PyObject *PyExc_NotADirectoryError - * :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 - * :exc:`PermissionError` - * * .. c:var:: PyObject *PyExc_ProcessLookupError - * :exc:`ProcessLookupError` - * * .. c:var:: PyObject *PyExc_PythonFinalizationError - * :exc:`PythonFinalizationError` - * * .. c:var:: PyObject *PyExc_RecursionError - * :exc:`RecursionError` - * * .. c:var:: PyObject *PyExc_ReferenceError - * :exc:`ReferenceError` - * * .. c:var:: PyObject *PyExc_RuntimeError - * :exc:`RuntimeError` - * * .. c:var:: PyObject *PyExc_StopAsyncIteration - * :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 - * :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` +.. stable-abi-note:: + + These pointers are part of the :ref:`Stable ABI ` since the + version in the *S.ABI* column (or since 3.2 when *S.ABI* is empty). + Exceptions marked N/A are *not* part of Stable ABI. + +.. omit-stable-abi-notes:: + + .. list-table:: + :align: left + :widths: auto + :header-rows: 1 + + * * C name + * .. stable-abi-note:: + + S.ABI + * 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 + * + * :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 :c:data:`PyExc_BlockingIOError`, :c:data:`PyExc_BrokenPipeError`, @@ -1295,37 +1362,59 @@ Notes: Warning types ------------- -.. list-table:: - :align: left - :widths: auto - :header-rows: 1 - - * * C name - * 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 - * :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 - * :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` +.. stable-abi-note:: + + These pointers are part of the :ref:`Stable ABI ` since the + version in the *S.ABI* column (or since 3.2 when *S.ABI* is empty). + +.. omit-stable-abi-notes:: + + .. list-table:: + :align: left + :widths: auto + :header-rows: 1 + + * * C name + * .. stable-abi-note:: + + S.ABI + * 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 :c:data:`PyExc_ResourceWarning`. diff --git a/Doc/c-api/iterator.rst b/Doc/c-api/iterator.rst index bfbfe3c92799809..2276620cc303141 100644 --- a/Doc/c-api/iterator.rst +++ b/Doc/c-api/iterator.rst @@ -72,23 +72,28 @@ Builtin Iterator Types These are built-in iteration types that are included in Python's C API, but provide no additional functions. They are here for completeness. - -.. list-table:: - :widths: auto - :header-rows: 1 - - * * C type - * Python type - * * .. c:var:: PyTypeObject PyEnum_Type - * :py:class:`enumerate` - * * .. c:var:: PyTypeObject PyFilter_Type - * :py:class:`filter` - * * .. c:var:: PyTypeObject PyMap_Type - * :py:class:`map` - * * .. c:var:: PyTypeObject PyReversed_Type - * :py:class:`reversed` - * * .. c:var:: PyTypeObject PyZip_Type - * :py:class:`zip` +.. stable-abi-note:: + + These pointers are part of the :ref:`Stable ABI `. + +.. omit-stable-abi-notes:: + + .. list-table:: + :widths: auto + :header-rows: 1 + + * * C type + * Python type + * * .. c:var:: PyTypeObject PyEnum_Type + * :py:class:`enumerate` + * * .. c:var:: PyTypeObject PyFilter_Type + * :py:class:`filter` + * * .. c:var:: PyTypeObject PyMap_Type + * :py:class:`map` + * * .. c:var:: PyTypeObject PyReversed_Type + * :py:class:`reversed` + * * .. c:var:: PyTypeObject PyZip_Type + * :py:class:`zip` Other Iterator Objects diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 0e762042979c2b7..2209c771368ef0b 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -183,8 +183,22 @@ 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) + + # Skip the note if any ancestor has 'omit-stable-abi-note' + # in a 'c_annotations' attribute. + ancestor = node + while ancestor: + if 'omit-stable-abi-note' not in ancestor.get( + 'c_annotations', + [], + ): + break + ancestor = node.parent + else: + # no skip; add the annotation + annotation = _stable_abi_annotation(record) + node.insert(0, annotation) + node.setdefault("classes", []).append('ADDED-HERE') # Unstable API annotation. if name.startswith("PyUnstable"): @@ -445,6 +459,45 @@ def run(self) -> list[nodes.Node]: return [node] +class StableABINote(SphinxDirective): + """A manual Stable ABI note + + Normally, notes are auto-generated. + This directive allows adding a similarly styled note manually. + Pair with omit-stable-abi-notes to override the automatic generation. + """ + + has_content = True + + def run(self) -> list[nodes.Node]: + node = nodes.Element() # Anonymous container for parsing + node.rawsource = '\n'.join(self.content) + self.state.nested_parse(self.content, self.content_offset, node) + for child in node.children: + child.setdefault("classes", []).append('stableabi') + return node.children + + +class OmitStableABINotes(SphinxDirective): + """A block where automatic Stable ABI notes are not generated + + Normally used for dense lists/tables of definitions, where individual notes + are omitted and the whole block has a common manual note. + """ + + has_content = True + + def run(self) -> list[nodes.Node]: + node = nodes.Element() # Anonymous container for parsing + node.rawsource = '\n'.join(self.content) + self.state.nested_parse(self.content, self.content_offset, node) + for child in node.children: + child.setdefault("c_annotations", []).append( + 'omit-stable-abi-notes', + ) + return node.children + + def init_annotations(app: Sphinx) -> None: # Using domaindata is a bit hack-ish, # but allows storing state without a global variable or closure. @@ -467,6 +520,8 @@ def setup(app: Sphinx) -> ExtensionMetadata: app.add_directive("limited-api-list", LimitedAPIList) app.add_directive("version-hex-cheatsheet", VersionHexCheatsheet) app.add_directive("corresponding-type-slot", CorrespondingTypeSlot) + app.add_directive("omit-stable-abi-notes", OmitStableABINotes) + app.add_directive("stable-abi-note", StableABINote) app.connect("builder-inited", init_annotations) app.connect("doctree-read", add_annotations)