From 19b61747df3d62c822285c488753d6fbdf91e3ac Mon Sep 17 00:00:00 2001 From: Daniel Garcia Moreno Date: Tue, 23 Sep 2025 10:20:16 +0200 Subject: [PATCH 1/2] gh-139257: Support docutils >= 0.22 --- Doc/Makefile | 2 - Doc/conf.py | 3 + Doc/tools/extensions/pyspecific.py | 68 +++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 23 deletions(-) Index: Python-3.14.3/Doc/Makefile =================================================================== --- Python-3.14.3.orig/Doc/Makefile 2026-02-03 16:32:20.000000000 +0100 +++ Python-3.14.3/Doc/Makefile 2026-02-13 20:28:48.460059340 +0100 @@ -14,7 +14,7 @@ SOURCES = DISTVERSION = $(shell $(PYTHON) tools/extensions/patchlevel.py) REQUIREMENTS = requirements.txt -SPHINXERRORHANDLING = --fail-on-warning +SPHINXERRORHANDLING = # Internal variables. PAPEROPT_a4 = --define latex_elements.papersize=a4paper Index: Python-3.14.3/Doc/conf.py =================================================================== --- Python-3.14.3.orig/Doc/conf.py 2026-02-03 16:32:20.000000000 +0100 +++ Python-3.14.3/Doc/conf.py 2026-02-13 20:21:11.034520886 +0100 @@ -582,3 +582,6 @@ '', '', ) + +# Fix devhelp doc build gh#python/cpython#120150 +master_doc = 'contents' Index: Python-3.14.3/Doc/tools/extensions/pyspecific.py =================================================================== --- Python-3.14.3.orig/Doc/tools/extensions/pyspecific.py 2026-02-03 16:32:20.000000000 +0100 +++ Python-3.14.3/Doc/tools/extensions/pyspecific.py 2026-02-13 17:09:31.987767795 +0100 @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ - pyspecific.py - ~~~~~~~~~~~~~ +pyspecific.py +~~~~~~~~~~~~~ - Sphinx extension with Python doc-specific markup. +Sphinx extension with Python doc-specific markup. - :copyright: 2008-2014 by Georg Brandl. - :license: Python license. +:copyright: 2008-2014 by Georg Brandl. +:license: Python license. """ import re @@ -15,6 +15,7 @@ from docutils import nodes from docutils.parsers.rst import directives +from docutils.parsers.rst.states import Body from docutils.utils import unescape from sphinx import addnodes from sphinx.domains.python import PyFunction, PyMethod, PyModule @@ -22,30 +23,48 @@ from sphinx.util.docutils import SphinxDirective # Used in conf.py and updated here by python/release-tools/run_release.py -SOURCE_URI = 'https://github.com/python/cpython/tree/3.14/%s' +SOURCE_URI = "https://github.com/python/cpython/tree/3.14/%s" + + +# monkey-patch reST parser to disable alphabetic and roman enumerated lists +def _disable_alphabetic_and_roman(text): + try: + # docutils >= 0.22 + from docutils.parsers.rst.states import InvalidRomanNumeralError + + raise InvalidRomanNumeralError(text) + except ImportError: + # docutils < 0.22 + return None + + +Body.enum.converters["loweralpha"] = Body.enum.converters["upperalpha"] = ( + Body.enum.converters["lowerroman"] +) = Body.enum.converters["upperroman"] = _disable_alphabetic_and_roman + class PyAwaitableMixin(object): def handle_signature(self, sig, signode): ret = super(PyAwaitableMixin, self).handle_signature(sig, signode) - signode.insert(0, addnodes.desc_annotation('awaitable ', 'awaitable ')) + signode.insert(0, addnodes.desc_annotation("awaitable ", "awaitable ")) return ret class PyAwaitableFunction(PyAwaitableMixin, PyFunction): def run(self): - self.name = 'py:function' + self.name = "py:function" return PyFunction.run(self) class PyAwaitableMethod(PyAwaitableMixin, PyMethod): def run(self): - self.name = 'py:method' + self.name = "py:method" return PyMethod.run(self) # Support for documenting Opcodes -opcode_sig_re = re.compile(r'(\w+(?:\+\d)?)(?:\s*\((.*)\))?') +opcode_sig_re = re.compile(r"(\w+(?:\+\d)?)(?:\s*\((.*)\))?") def parse_opcode_signature(env, sig, signode): @@ -64,7 +83,7 @@ # Support for documenting pdb commands -pdbcmd_sig_re = re.compile(r'([a-z()!]+)\s*(.*)') +pdbcmd_sig_re = re.compile(r"([a-z()!]+)\s*(.*)") # later... # pdbargs_tokens_re = re.compile(r'''[a-zA-Z]+ | # identifiers @@ -80,16 +99,16 @@ if m is None: raise ValueError name, args = m.groups() - fullname = name.replace('(', '').replace(')', '') + fullname = name.replace("(", "").replace(")", "") signode += addnodes.desc_name(name, name) if args: - signode += addnodes.desc_addname(' '+args, ' '+args) + signode += addnodes.desc_addname(" " + args, " " + args) return fullname def parse_monitoring_event(env, sig, signode): """Transform a monitoring event signature into RST nodes.""" - signode += addnodes.desc_addname('sys.monitoring.events.', 'sys.monitoring.events.') + signode += addnodes.desc_addname("sys.monitoring.events.", "sys.monitoring.events.") signode += addnodes.desc_name(sig, sig) return sig @@ -102,7 +121,7 @@ As such, we link this to ``env-check-consistency``, even though it has nothing to do with the environment consistency check. """ - if app.builder.name != 'gettext': + if app.builder.name != "gettext": return # allow translating deprecated index entries @@ -119,10 +138,15 @@ def setup(app): - app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature) - app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command) - app.add_object_type('monitoring-event', 'monitoring-event', '%s (monitoring event)', parse_monitoring_event) - app.add_directive_to_domain('py', 'awaitablefunction', PyAwaitableFunction) - app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod) - app.connect('env-check-consistency', patch_pairindextypes) - return {'version': '1.0', 'parallel_read_safe': True} + app.add_object_type("opcode", "opcode", "%s (opcode)", parse_opcode_signature) + app.add_object_type("pdbcommand", "pdbcmd", "%s (pdb command)", parse_pdb_command) + app.add_object_type( + "monitoring-event", + "monitoring-event", + "%s (monitoring event)", + parse_monitoring_event, + ) + app.add_directive_to_domain("py", "awaitablefunction", PyAwaitableFunction) + app.add_directive_to_domain("py", "awaitablemethod", PyAwaitableMethod) + app.connect("env-check-consistency", patch_pairindextypes) + return {"version": "1.0", "parallel_read_safe": True}