Skip to content

Commit 2064e53

Browse files
AA-Turnersrinivasreddy
authored andcommitted
pythonGH-121970: Extract changes into a new extension (python#129105)
1 parent ed6cd73 commit 2064e53

File tree

3 files changed

+91
-57
lines changed

3 files changed

+91
-57
lines changed

Doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
'audit_events',
2626
'availability',
2727
'c_annotations',
28+
'changes',
2829
'glossary_search',
2930
'lexers',
3031
'pyspecific',

Doc/tools/extensions/changes.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""Support for documenting version of changes, additions, deprecations."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
7+
from sphinx.domains.changeset import (
8+
VersionChange,
9+
versionlabel_classes,
10+
versionlabels,
11+
)
12+
from sphinx.locale import _ as sphinx_gettext
13+
14+
if TYPE_CHECKING:
15+
from docutils.nodes import Node
16+
from sphinx.application import Sphinx
17+
from sphinx.util.typing import ExtensionMetadata
18+
19+
20+
def expand_version_arg(argument: str, release: str) -> str:
21+
"""Expand "next" to the current version"""
22+
if argument == "next":
23+
return sphinx_gettext("{} (unreleased)").format(release)
24+
return argument
25+
26+
27+
class PyVersionChange(VersionChange):
28+
def run(self) -> list[Node]:
29+
# Replace the 'next' special token with the current development version
30+
self.arguments[0] = expand_version_arg(
31+
self.arguments[0], self.config.release
32+
)
33+
return super().run()
34+
35+
36+
class DeprecatedRemoved(VersionChange):
37+
required_arguments = 2
38+
39+
_deprecated_label = sphinx_gettext(
40+
"Deprecated since version %s, will be removed in version %s"
41+
)
42+
_removed_label = sphinx_gettext(
43+
"Deprecated since version %s, removed in version %s"
44+
)
45+
46+
def run(self) -> list[Node]:
47+
# Replace the first two arguments (deprecated version and removed version)
48+
# with a single tuple of both versions.
49+
version_deprecated = expand_version_arg(
50+
self.arguments[0], self.config.release
51+
)
52+
version_removed = self.arguments.pop(1)
53+
if version_removed == "next":
54+
raise ValueError(
55+
"deprecated-removed:: second argument cannot be `next`"
56+
)
57+
self.arguments[0] = version_deprecated, version_removed
58+
59+
# Set the label based on if we have reached the removal version
60+
current_version = tuple(map(int, self.config.version.split(".")))
61+
removed_version = tuple(map(int, version_removed.split(".")))
62+
if current_version < removed_version:
63+
versionlabels[self.name] = self._deprecated_label
64+
versionlabel_classes[self.name] = "deprecated"
65+
else:
66+
versionlabels[self.name] = self._removed_label
67+
versionlabel_classes[self.name] = "removed"
68+
try:
69+
return super().run()
70+
finally:
71+
# reset versionlabels and versionlabel_classes
72+
versionlabels[self.name] = ""
73+
versionlabel_classes[self.name] = ""
74+
75+
76+
def setup(app: Sphinx) -> ExtensionMetadata:
77+
# Override Sphinx's directives with support for 'next'
78+
app.add_directive("versionadded", PyVersionChange, override=True)
79+
app.add_directive("versionchanged", PyVersionChange, override=True)
80+
app.add_directive("versionremoved", PyVersionChange, override=True)
81+
app.add_directive("deprecated", PyVersionChange, override=True)
82+
83+
# Register the ``.. deprecated-removed::`` directive
84+
app.add_directive("deprecated-removed", DeprecatedRemoved)
85+
86+
return {
87+
"version": "1.0",
88+
"parallel_read_safe": True,
89+
"parallel_write_safe": True,
90+
}

Doc/tools/extensions/pyspecific.py

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from docutils.utils import new_document, unescape
2222
from sphinx import addnodes
2323
from sphinx.builders import Builder
24-
from sphinx.domains.changeset import VersionChange, versionlabels, versionlabel_classes
2524
from sphinx.domains.python import PyFunction, PyMethod, PyModule
2625
from sphinx.locale import _ as sphinx_gettext
2726
from sphinx.util.docutils import SphinxDirective
@@ -184,57 +183,6 @@ def run(self):
184183
return PyMethod.run(self)
185184

186185

187-
# Support for documenting version of changes, additions, deprecations
188-
189-
def expand_version_arg(argument, release):
190-
"""Expand "next" to the current version"""
191-
if argument == 'next':
192-
return sphinx_gettext('{} (unreleased)').format(release)
193-
return argument
194-
195-
196-
class PyVersionChange(VersionChange):
197-
def run(self):
198-
# Replace the 'next' special token with the current development version
199-
self.arguments[0] = expand_version_arg(self.arguments[0],
200-
self.config.release)
201-
return super().run()
202-
203-
204-
class DeprecatedRemoved(VersionChange):
205-
required_arguments = 2
206-
207-
_deprecated_label = sphinx_gettext('Deprecated since version %s, will be removed in version %s')
208-
_removed_label = sphinx_gettext('Deprecated since version %s, removed in version %s')
209-
210-
def run(self):
211-
# Replace the first two arguments (deprecated version and removed version)
212-
# with a single tuple of both versions.
213-
version_deprecated = expand_version_arg(self.arguments[0],
214-
self.config.release)
215-
version_removed = self.arguments.pop(1)
216-
if version_removed == 'next':
217-
raise ValueError(
218-
'deprecated-removed:: second argument cannot be `next`')
219-
self.arguments[0] = version_deprecated, version_removed
220-
221-
# Set the label based on if we have reached the removal version
222-
current_version = tuple(map(int, self.config.version.split('.')))
223-
removed_version = tuple(map(int, version_removed.split('.')))
224-
if current_version < removed_version:
225-
versionlabels[self.name] = self._deprecated_label
226-
versionlabel_classes[self.name] = 'deprecated'
227-
else:
228-
versionlabels[self.name] = self._removed_label
229-
versionlabel_classes[self.name] = 'removed'
230-
try:
231-
return super().run()
232-
finally:
233-
# reset versionlabels and versionlabel_classes
234-
versionlabels[self.name] = ''
235-
versionlabel_classes[self.name] = ''
236-
237-
238186
# Support for including Misc/NEWS
239187

240188
issue_re = re.compile('(?:[Ii]ssue #|bpo-)([0-9]+)', re.I)
@@ -417,11 +365,6 @@ def setup(app):
417365
app.add_role('issue', issue_role)
418366
app.add_role('gh', gh_issue_role)
419367
app.add_directive('impl-detail', ImplementationDetail)
420-
app.add_directive('versionadded', PyVersionChange, override=True)
421-
app.add_directive('versionchanged', PyVersionChange, override=True)
422-
app.add_directive('versionremoved', PyVersionChange, override=True)
423-
app.add_directive('deprecated', PyVersionChange, override=True)
424-
app.add_directive('deprecated-removed', DeprecatedRemoved)
425368
app.add_builder(PydocTopicsBuilder)
426369
app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
427370
app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command)

0 commit comments

Comments
 (0)