diff --git a/CHANGES b/CHANGES index e1ded555674..5b057c55fde 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,8 @@ Release 7.2.4 (in development) Bugs fixed ---------- +* #11618: Fix a regression in the MoveModuleTargets transform, + introduced in #10478 (#9662). Release 7.2.3 (released Aug 23, 2023) ===================================== diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index d9a908c8d7b..8a806cd0390 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -145,10 +145,14 @@ def apply(self, **kwargs: Any) -> None: for node in list(self.document.findall(nodes.target)): if not node['ids']: continue - if ('ismod' in node and - node.parent.__class__ is nodes.section and - # index 0 is the section title node - node.parent.index(node) == 1): + if ( + 'ismod' in node + and type(node.parent) is nodes.section + # index 0: section title node + # index 1: index node + # index 2: target node + and node.parent.index(node) == 2 + ): node.parent['ids'][0:0] = node['ids'] node.parent.remove(node) diff --git a/tests/test_transforms_move_module_targets.py b/tests/test_transforms_move_module_targets.py new file mode 100644 index 00000000000..e0e9f1de53a --- /dev/null +++ b/tests/test_transforms_move_module_targets.py @@ -0,0 +1,77 @@ +import pytest +from docutils import nodes + +from sphinx import addnodes +from sphinx.testing.util import SphinxTestApp +from sphinx.transforms import MoveModuleTargets + +CONTENT_PY = """\ +move-module-targets +=================== + +.. py:module:: fish_licence.halibut +""" +CONTENT_JS = """\ +move-module-targets +=================== + +.. js:module:: fish_licence.halibut +""" + + +@pytest.mark.parametrize('content', [ + CONTENT_PY, # Python + CONTENT_JS, # JavaScript +]) +@pytest.mark.usefixtures("rollback_sysmodules") +def test_move_module_targets(tmp_path, content): + # Test for the MoveModuleTargets transform + tmp_path.joinpath("conf.py").touch() + tmp_path.joinpath("index.rst").write_text(content, encoding="utf-8") + + app = SphinxTestApp('dummy', srcdir=tmp_path) + app.build(force_all=True) + document = app.env.get_doctree('index') + section = document[0] + + # target ID has been lifted into the section node + assert section["ids"] == ['module-fish_licence.halibut', 'move-module-targets'] + # nodes.target has been removed from 'section' + assert isinstance(section[0], nodes.title) + assert isinstance(section[1], addnodes.index) + assert len(section) == 2 + + +@pytest.mark.usefixtures("rollback_sysmodules") +def test_move_module_targets_no_section(tmp_path): + # Test for the MoveModuleTargets transform + tmp_path.joinpath("conf.py").touch() + tmp_path.joinpath("index.rst").write_text(".. py:module:: fish_licence.halibut\n", encoding="utf-8") + + app = SphinxTestApp('dummy', srcdir=tmp_path) + app.build(force_all=True) + document = app.env.get_doctree('index') + + assert document["ids"] == [] + + +@pytest.mark.usefixtures("rollback_sysmodules") +def test_move_module_targets_disabled(tmp_path): + # Test for the MoveModuleTargets transform + tmp_path.joinpath("conf.py").touch() + tmp_path.joinpath("index.rst").write_text(CONTENT_PY, encoding="utf-8") + + app = SphinxTestApp('dummy', srcdir=tmp_path) + app.registry.transforms.remove(MoveModuleTargets) # disable the transform + app.build(force_all=True) + document = app.env.get_doctree('index') + section = document[0] + + # target ID is not lifted into the section node + assert section["ids"] == ['move-module-targets'] + assert section[2]["ids"] == ['module-fish_licence.halibut'] + # nodes.target remains in 'section' + assert isinstance(section[0], nodes.title) + assert isinstance(section[1], addnodes.index) + assert isinstance(section[2], nodes.target) + assert len(section) == 3