From f371bbbc79d109ead676c9e91ef4d4d3f399f091 Mon Sep 17 00:00:00 2001 From: khanxmetu Date: Fri, 18 Oct 2024 18:11:23 +0300 Subject: [PATCH 1/3] `_check_toc_parents` considers only the descendants of root_doc and not the whole toctree_includes graph --- sphinx/environment/__init__.py | 21 +++++++++++++------ .../pdfindex.rst | 7 +++++++ .../relation_graph.txt | 4 ++-- tests/test_builders/test_build.py | 3 +++ 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 tests/roots/test-toctree-multiple-parents/pdfindex.rst diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 85e2dc9a930..631192b3b74 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -771,7 +771,7 @@ def check_consistency(self) -> None: # Call _check_toc_parents here rather than in _get_toctree_ancestors() # because that method is called multiple times per document and would # lead to duplicate warnings. - _check_toc_parents(self.toctree_includes) + _check_toc_parents(self.toctree_includes, self.config.root_doc) # call check-consistency for all extensions self.domains._check_consistency() @@ -819,19 +819,28 @@ def _traverse_toctree( traversed.add(sub_docname) -def _check_toc_parents(toctree_includes: dict[str, list[str]]) -> None: +def _check_toc_parents(toctree_includes: dict[str, list[str]], root_doc: str) -> None: + """Checks if document is referenced in multiple toctrees. + Based on the current implementation of `global_toctree_for_doc`, + it considers only the descendants of root_doc and not the whole graph. + """ toc_parents: dict[str, list[str]] = {} - for parent, children in toctree_includes.items(): - for child in children: - toc_parents.setdefault(child, []).append(parent) + def _find_toc_parents_dfs(node: str) -> None: + for child in toctree_includes.get(node, []): + toc_parents.setdefault(child, []).append(node) + is_child_already_visited = len(toc_parents[child]) > 1 + if not is_child_already_visited: + _find_toc_parents_dfs(child) + + _find_toc_parents_dfs(root_doc) for doc, parents in sorted(toc_parents.items()): if len(parents) > 1: logger.info( __( 'document is referenced in multiple toctrees: %s, selecting: %s <- %s' ), - parents, + sorted(parents), max(parents), doc, location=doc, diff --git a/tests/roots/test-toctree-multiple-parents/pdfindex.rst b/tests/roots/test-toctree-multiple-parents/pdfindex.rst new file mode 100644 index 00000000000..3802732bed3 --- /dev/null +++ b/tests/roots/test-toctree-multiple-parents/pdfindex.rst @@ -0,0 +1,7 @@ +test-toctree-multiple-parents +============================= + +.. literalinclude:: relation_graph.txt + +.. toctree:: + delta diff --git a/tests/roots/test-toctree-multiple-parents/relation_graph.txt b/tests/roots/test-toctree-multiple-parents/relation_graph.txt index a610eac2622..909de7a9a1e 100644 --- a/tests/roots/test-toctree-multiple-parents/relation_graph.txt +++ b/tests/roots/test-toctree-multiple-parents/relation_graph.txt @@ -1,5 +1,5 @@ - index - / \ + index pdfindex + / \ / alpha delta \ / bravo / diff --git a/tests/test_builders/test_build.py b/tests/test_builders/test_build.py index 5f396cc48af..3b19826a438 100644 --- a/tests/test_builders/test_build.py +++ b/tests/test_builders/test_build.py @@ -106,6 +106,9 @@ def test_multiple_parents_toctree(app): assert ( "document is referenced in multiple toctrees: ['bravo', 'delta'], selecting: delta <- charlie" ) in app.status.getvalue() + assert ( + "document is referenced in multiple toctrees: ['index', 'pdfindex'], selecting: pdfindex <- delta" + ) not in app.status.getvalue() @pytest.mark.usefixtures('_http_teapot') From cc5f3f84776e6e798994b3c5ff529013fb69e3cc Mon Sep 17 00:00:00 2001 From: khanxmetu Date: Sat, 19 Oct 2024 15:54:35 +0300 Subject: [PATCH 2/3] Code refactoring suggestion Co-authored-by: James Addison <55152140+jayaddison@users.noreply.github.com> --- sphinx/environment/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 631192b3b74..0d339dff35f 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -828,10 +828,11 @@ def _check_toc_parents(toctree_includes: dict[str, list[str]], root_doc: str) -> def _find_toc_parents_dfs(node: str) -> None: for child in toctree_includes.get(node, []): + already_visited = child in toc_parents toc_parents.setdefault(child, []).append(node) - is_child_already_visited = len(toc_parents[child]) > 1 - if not is_child_already_visited: - _find_toc_parents_dfs(child) + if already_visited: + continue + _find_toc_parents_dfs(child) _find_toc_parents_dfs(root_doc) for doc, parents in sorted(toc_parents.items()): From 26b216ee3a6a81df13e62d725df748f519cb96e0 Mon Sep 17 00:00:00 2001 From: khanxmetu Date: Fri, 25 Oct 2024 21:41:52 +0300 Subject: [PATCH 3/3] Keep parents list as unsorted --- sphinx/environment/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 0d339dff35f..c1a1e96d17c 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -841,7 +841,7 @@ def _find_toc_parents_dfs(node: str) -> None: __( 'document is referenced in multiple toctrees: %s, selecting: %s <- %s' ), - sorted(parents), + parents, max(parents), doc, location=doc,