66
77from docutils import nodes
88from sphinx import addnodes
9+ from sphinx .builders .changes import ChangesBuilder
910from sphinx .domains .changeset import (
1011 VersionChange ,
1112 versionlabel_classes ,
1718if TYPE_CHECKING :
1819 from docutils .nodes import Node
1920 from sphinx .application import Sphinx
21+ from sphinx .environment import BuildEnvironment
2022 from sphinx .util .typing import ExtensionMetadata
2123
2224
@@ -146,6 +148,32 @@ def _add_glossary_link(cls, inline: nodes.inline) -> None:
146148 break
147149
148150
151+ def _fixup_changesets (app : Sphinx , env : BuildEnvironment ) -> None :
152+ changesets = env .get_domain ("changeset" ).changesets
153+
154+ # The changeset domain records each entry's plain text before SoftDeprecated
155+ # replaces the :term:, so strip the markup before the changes builder renders it.
156+ for entries in changesets .values ():
157+ for i , entry in enumerate (entries ):
158+ if entry .type == "soft-deprecated" :
159+ entries [i ] = entry ._replace (
160+ content = SoftDeprecated ._TERM_RE .sub (r"\1" , entry .content )
161+ )
162+
163+ # DeprecatedRemoved entries are recorded under their (deprecated,
164+ # removed) version tuple, which the changes builder ignores.
165+ # Re-file them under both versions.
166+ for versions in [v for v in changesets if isinstance (v , tuple )]:
167+ deprecated , removed = versions
168+ for entry in changesets .pop (versions ):
169+ changesets .setdefault (deprecated , []).append (
170+ entry ._replace (type = "deprecated" )
171+ )
172+ changesets .setdefault (removed , []).append (
173+ entry ._replace (type = "versionremoved" )
174+ )
175+
176+
149177def setup (app : Sphinx ) -> ExtensionMetadata :
150178 # Override Sphinx's directives with support for 'next'
151179 app .add_directive ("versionadded" , PyVersionChange , override = True )
@@ -155,9 +183,15 @@ def setup(app: Sphinx) -> ExtensionMetadata:
155183
156184 # Register the ``.. deprecated-removed::`` directive
157185 app .add_directive ("deprecated-removed" , DeprecatedRemoved )
186+ # _fixup_changesets() changes these entries to 'deprecated'/'versionremoved'
187+ ChangesBuilder .typemap ["deprecated-removed" ] = "deprecated-removed"
158188
159189 # Register the ``.. soft-deprecated::`` directive
160190 app .add_directive ("soft-deprecated" , SoftDeprecated )
191+ ChangesBuilder .typemap ["soft-deprecated" ] = "soft deprecated"
192+
193+ # Repair the recorded changesets for the couple of custom directives above
194+ app .connect ("env-updated" , _fixup_changesets )
161195
162196 return {
163197 "version" : "1.0" ,
0 commit comments