File 12888.patch of Package python-Sphinx
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index 151df6a..c6e5687 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -598,6 +598,9 @@ class Builder:
docnames.add(tocdocname)
docnames.add(self.config.root_doc)
+ # sort to ensure deterministic toctree generation
+ self.env.toctree_includes = dict(sorted(self.env.toctree_includes.items()))
+
with progress_message(__('preparing documents')):
self.prepare_writing(docnames)
diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py
index 20bfd86..40c2eac 100644
--- a/sphinx/environment/__init__.py
+++ b/sphinx/environment/__init__.py
@@ -752,6 +752,7 @@ class BuildEnvironment:
continue
logger.warning(__("document isn't included in any toctree"),
location=docname)
+ _check_toc_parents(self.toctree_includes)
# call check-consistency for all extensions
for domain in self.domains.values():
@@ -782,3 +783,24 @@ def _traverse_toctree(
if sub_docname not in traversed:
yield sub_parent, sub_docname
traversed.add(sub_docname)
+
+
+def _check_toc_parents(toctree_includes: dict[str, list[str]]) -> None:
+ toc_parents: dict[str, list[str]] = {}
+ for parent, children in toctree_includes.items():
+ for child in children:
+ toc_parents.setdefault(child, []).append(parent)
+
+ 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,
+ max(parents),
+ doc,
+ location=doc,
+ type='toc',
+ subtype='multiple_toc_parents',
+ )