diff --git a/CHANGES b/CHANGES index 23a4d0f3b..cd2acfd0c 100644 --- a/CHANGES +++ b/CHANGES @@ -166,6 +166,7 @@ Features added * C++: add ``cpp:struct`` to complement ``cpp:class``. * #1341 the HTML search considers words that contain a search term of length three or longer a match. +* #4611: epub: Show warning for duplicated ToC entries Bugs fixed ---------- diff --git a/sphinx/builders/_epub_base.py b/sphinx/builders/_epub_base.py index 7038f45f6..5516fdaf8 100644 --- a/sphinx/builders/_epub_base.py +++ b/sphinx/builders/_epub_base.py @@ -35,7 +35,7 @@ except ImportError: if False: # For type annotation - from typing import Any, Dict, List, Tuple # NOQA + from typing import Any, Dict, List, Set, Tuple # NOQA from sphinx.application import Sphinx # NOQA @@ -213,6 +213,15 @@ class EpubBuilder(StandaloneHTMLBuilder): result = self.get_refnodes(elem, result) return result + def check_refnodes(self, nodes): + # type: (List[Dict[str, Any]]) -> None + appeared = set() # type: Set[str] + for node in nodes: + if node['refuri'] in appeared: + logger.warning(__('duplicated ToC entry found: %s'), node['refuri']) + else: + appeared.add(node['refuri']) + def get_toc(self): # type: () -> None """Get the total table of contents, containing the master_doc @@ -726,6 +735,7 @@ class EpubBuilder(StandaloneHTMLBuilder): else: # 'includehidden' refnodes = self.refnodes + self.check_refnodes(refnodes) navpoints = self.build_navpoints(refnodes) level = max(item['level'] for item in self.refnodes) level = min(level, self.config.epub_tocdepth) diff --git a/tests/roots/test-root/index.txt b/tests/roots/test-root/index.txt index ce0338cf7..27f90f357 100644 --- a/tests/roots/test-root/index.txt +++ b/tests/roots/test-root/index.txt @@ -24,7 +24,6 @@ Contents: math autodoc extensions - extensions footnote lists otherext diff --git a/tests/roots/test-toctree-duplicated/conf.py b/tests/roots/test-toctree-duplicated/conf.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/roots/test-toctree-duplicated/foo.rst b/tests/roots/test-toctree-duplicated/foo.rst new file mode 100644 index 000000000..f23d4ce05 --- /dev/null +++ b/tests/roots/test-toctree-duplicated/foo.rst @@ -0,0 +1,2 @@ +foo +=== diff --git a/tests/roots/test-toctree-duplicated/index.rst b/tests/roots/test-toctree-duplicated/index.rst new file mode 100644 index 000000000..38a8c44c1 --- /dev/null +++ b/tests/roots/test-toctree-duplicated/index.rst @@ -0,0 +1,7 @@ +test-toctree-duplicated +======================= + +.. toctree:: + + foo + foo diff --git a/tests/test_build_epub.py b/tests/test_build_epub.py index 86e40b65d..337363832 100644 --- a/tests/test_build_epub.py +++ b/tests/test_build_epub.py @@ -367,6 +367,12 @@ def test_html_download_role(app, status, warning): '/_static/sphinxheader.png]

' in content) +@pytest.mark.sphinx('epub', testroot='toctree-duplicated') +def test_duplicated_toctree_entry(app, status, warning): + app.build() + assert 'WARNING: duplicated ToC entry found: foo.xhtml' in warning.getvalue() + + @pytest.mark.skipif('DO_EPUBCHECK' not in os.environ, reason='Skipped because DO_EPUBCHECK is not set') @pytest.mark.sphinx('epub')