mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Provide a better error message if the master document is not included in the project documents (#12011)
This commit is contained in:
parent
e04b0d4bec
commit
f0d8e2ef5e
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import pickle
|
import pickle
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
from os import path
|
from os import path
|
||||||
from typing import TYPE_CHECKING, Any, Literal, final
|
from typing import TYPE_CHECKING, Any, Literal, final
|
||||||
@ -21,7 +22,7 @@ from sphinx.util.console import bold
|
|||||||
from sphinx.util.display import progress_message, status_iterator
|
from sphinx.util.display import progress_message, status_iterator
|
||||||
from sphinx.util.docutils import sphinx_domains
|
from sphinx.util.docutils import sphinx_domains
|
||||||
from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain
|
from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain
|
||||||
from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
|
from sphinx.util.osutil import SEP, canon_path, ensuredir, relative_uri, relpath
|
||||||
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available
|
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available
|
||||||
|
|
||||||
# side effect: registers roles and directives
|
# side effect: registers roles and directives
|
||||||
@ -423,9 +424,40 @@ class Builder:
|
|||||||
else:
|
else:
|
||||||
self._read_serial(docnames)
|
self._read_serial(docnames)
|
||||||
|
|
||||||
if self.config.root_doc not in self.env.all_docs:
|
if self.config.master_doc not in self.env.all_docs:
|
||||||
raise SphinxError('root file %s not found' %
|
from sphinx.project import EXCLUDE_PATHS
|
||||||
self.env.doc2path(self.config.root_doc))
|
from sphinx.util.matching import _translate_pattern
|
||||||
|
|
||||||
|
master_doc_path = self.env.doc2path(self.config.master_doc)
|
||||||
|
master_doc_canon = canon_path(master_doc_path)
|
||||||
|
for pat in EXCLUDE_PATHS:
|
||||||
|
if not re.match(_translate_pattern(pat), master_doc_canon):
|
||||||
|
continue
|
||||||
|
msg = __('Sphinx is unable to load the master document (%s) '
|
||||||
|
'because it matches a built-in exclude pattern %r. '
|
||||||
|
'Please move your master document to a different location.')
|
||||||
|
raise SphinxError(msg % (master_doc_path, pat))
|
||||||
|
for pat in self.config.exclude_patterns:
|
||||||
|
if not re.match(_translate_pattern(pat), master_doc_canon):
|
||||||
|
continue
|
||||||
|
msg = __('Sphinx is unable to load the master document (%s) '
|
||||||
|
'because it matches an exclude pattern specified '
|
||||||
|
'in conf.py, %r. '
|
||||||
|
'Please remove this pattern from conf.py.')
|
||||||
|
raise SphinxError(msg % (master_doc_path, pat))
|
||||||
|
if set(self.config.include_patterns) != {'**'} and not any(
|
||||||
|
re.match(_translate_pattern(pat), master_doc_canon)
|
||||||
|
for pat in self.config.include_patterns
|
||||||
|
):
|
||||||
|
msg = __('Sphinx is unable to load the master document (%s) '
|
||||||
|
'because it is not included in the custom include_patterns = %r. '
|
||||||
|
'Ensure that a pattern in include_patterns matches the '
|
||||||
|
'master document.')
|
||||||
|
raise SphinxError(msg % (master_doc_path, self.config.include_patterns))
|
||||||
|
msg = __('Sphinx is unable to load the master document (%s). '
|
||||||
|
'The master document must be within the source directory '
|
||||||
|
'or a subdirectory of it.')
|
||||||
|
raise SphinxError(msg % master_doc_path)
|
||||||
|
|
||||||
for retval in self.events.emit('env-updated', self.env):
|
for retval in self.events.emit('env-updated', self.env):
|
||||||
if retval is not None:
|
if retval is not None:
|
||||||
|
@ -416,11 +416,12 @@ class Config:
|
|||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
logger.warning("%s", exc)
|
logger.warning("%s", exc)
|
||||||
else:
|
else:
|
||||||
self.__dict__[name] = value
|
self.__setattr__(name, value)
|
||||||
return value
|
return value
|
||||||
# then check values from 'conf.py'
|
# then check values from 'conf.py'
|
||||||
if name in self._raw_config:
|
if name in self._raw_config:
|
||||||
self.__dict__[name] = value = self._raw_config[name]
|
value = self._raw_config[name]
|
||||||
|
self.__setattr__(name, value)
|
||||||
return value
|
return value
|
||||||
# finally, fall back to the default value
|
# finally, fall back to the default value
|
||||||
default = self._options[name].default
|
default = self._options[name].default
|
||||||
|
@ -34,7 +34,7 @@ def test_config_status(make_app, app_params):
|
|||||||
assert app3.env.config_status == CONFIG_CHANGED
|
assert app3.env.config_status == CONFIG_CHANGED
|
||||||
app3.build()
|
app3.build()
|
||||||
shutil.move(fname[:-4] + 'x.rst', fname)
|
shutil.move(fname[:-4] + 'x.rst', fname)
|
||||||
assert "[config changed ('root_doc')] 1 added" in app3._status.getvalue()
|
assert "[config changed ('master_doc')] 1 added" in app3._status.getvalue()
|
||||||
|
|
||||||
# incremental build (extension changed)
|
# incremental build (extension changed)
|
||||||
app4 = make_app(*args, confoverrides={'extensions': ['sphinx.ext.autodoc']}, **kwargs)
|
app4 = make_app(*args, confoverrides={'extensions': ['sphinx.ext.autodoc']}, **kwargs)
|
||||||
|
Loading…
Reference in New Issue
Block a user