mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2026-10-16 18:32:09 -05:00
Enable automatic formatting for `sphinx/environment/` (#12968)
This commit is contained in:
1 parent
81c6f1e8cc
commit
4dfddc533c
10 files changed
+392
-165
No files matched your search
@@ -449,7 +449,6 @@ exclude = [
|
||||
"sphinx/builders/*",
|
||||
"sphinx/config.py",
|
||||
"sphinx/domains/*",
|
||||
"sphinx/environment/*",
|
||||
"sphinx/ext/autodoc/__init__.py",
|
||||
"sphinx/ext/autodoc/directive.py",
|
||||
"sphinx/ext/autodoc/importer.py",
|
||||
|
||||
@@ -274,7 +274,9 @@ class BuildEnvironment:
|
||||
self._update_settings(app.config)
|
||||
|
||||
@staticmethod
|
||||
def _config_status(*, old_config: Config | None, new_config: Config) -> tuple[int, str]:
|
||||
def _config_status(
|
||||
*, old_config: Config | None, new_config: Config
|
||||
) -> tuple[int, str]:
|
||||
"""Report the differences between two Config objects.
|
||||
|
||||
Returns a triple of:
|
||||
@@ -306,7 +308,9 @@ class BuildEnvironment:
|
||||
def _update_settings(self, config: Config) -> None:
|
||||
"""Update settings by new config."""
|
||||
self.settings['input_encoding'] = config.source_encoding
|
||||
self.settings['trim_footnote_reference_space'] = config.trim_footnote_reference_space
|
||||
self.settings['trim_footnote_reference_space'] = (
|
||||
config.trim_footnote_reference_space
|
||||
)
|
||||
self.settings['language_code'] = config.language
|
||||
|
||||
# Allow to disable by 3rd party extension (workaround)
|
||||
@@ -331,9 +335,12 @@ class BuildEnvironment:
|
||||
condition = versioning_conditions[method]
|
||||
|
||||
if self.versioning_condition not in {None, condition}:
|
||||
raise SphinxError(__('This environment is incompatible with the '
|
||||
'selected builder, please choose another '
|
||||
'doctree directory.'))
|
||||
msg = __(
|
||||
'This environment is incompatible with the '
|
||||
'selected builder, please choose another '
|
||||
'doctree directory.'
|
||||
)
|
||||
raise SphinxError(msg)
|
||||
self.versioning_condition = condition
|
||||
self.versioning_compare = compare
|
||||
|
||||
@@ -346,8 +353,9 @@ class BuildEnvironment:
|
||||
|
||||
self.domains._clear_doc(docname)
|
||||
|
||||
def merge_info_from(self, docnames: Iterable[str], other: BuildEnvironment,
|
||||
app: Sphinx) -> None:
|
||||
def merge_info_from(
|
||||
self, docnames: Iterable[str], other: BuildEnvironment, app: Sphinx
|
||||
) -> None:
|
||||
"""Merge global information gathered about *docnames* while reading them
|
||||
from the *other* environment.
|
||||
|
||||
@@ -390,12 +398,13 @@ class BuildEnvironment:
|
||||
if filename.startswith(('/', os.sep)):
|
||||
rel_fn = filename[1:]
|
||||
else:
|
||||
docdir = path.dirname(self.doc2path(docname or self.docname,
|
||||
base=False))
|
||||
docdir = path.dirname(self.doc2path(docname or self.docname, base=False))
|
||||
rel_fn = path.join(docdir, filename)
|
||||
|
||||
return (canon_path(path.normpath(rel_fn)),
|
||||
path.normpath(path.join(self.srcdir, rel_fn)))
|
||||
return (
|
||||
canon_path(path.normpath(rel_fn)),
|
||||
path.normpath(path.join(self.srcdir, rel_fn)),
|
||||
)
|
||||
|
||||
@property
|
||||
def found_docs(self) -> set[str]:
|
||||
@@ -407,9 +416,11 @@ class BuildEnvironment:
|
||||
self.found_docs.
|
||||
"""
|
||||
try:
|
||||
exclude_paths = (self.config.exclude_patterns +
|
||||
self.config.templates_path +
|
||||
builder.get_asset_paths())
|
||||
exclude_paths = (
|
||||
self.config.exclude_patterns
|
||||
+ self.config.templates_path
|
||||
+ builder.get_asset_paths()
|
||||
)
|
||||
self.project.discover(exclude_paths, self.config.include_patterns)
|
||||
|
||||
# Current implementation is applying translated messages in the reading
|
||||
@@ -420,18 +431,25 @@ class BuildEnvironment:
|
||||
# move i18n process into the writing phase, and remove these lines.
|
||||
if builder.use_message_catalog:
|
||||
# add catalog mo file dependency
|
||||
repo = CatalogRepository(self.srcdir, self.config.locale_dirs,
|
||||
self.config.language, self.config.source_encoding)
|
||||
repo = CatalogRepository(
|
||||
self.srcdir,
|
||||
self.config.locale_dirs,
|
||||
self.config.language,
|
||||
self.config.source_encoding,
|
||||
)
|
||||
mo_paths = {c.domain: c.mo_path for c in repo.catalogs}
|
||||
for docname in self.found_docs:
|
||||
domain = docname_to_domain(docname, self.config.gettext_compact)
|
||||
if domain in mo_paths:
|
||||
self.dependencies[docname].add(mo_paths[domain])
|
||||
except OSError as exc:
|
||||
raise DocumentError(__('Failed to scan documents in %s: %r') %
|
||||
(self.srcdir, exc)) from exc
|
||||
raise DocumentError(
|
||||
__('Failed to scan documents in %s: %r') % (self.srcdir, exc)
|
||||
) from exc
|
||||
|
||||
def get_outdated_files(self, config_changed: bool) -> tuple[set[str], set[str], set[str]]:
|
||||
def get_outdated_files(
|
||||
self, config_changed: bool
|
||||
) -> tuple[set[str], set[str], set[str]]:
|
||||
"""Return (added, changed, removed) sets."""
|
||||
# clear all files no longer present
|
||||
removed = set(self.all_docs) - self.found_docs
|
||||
@@ -463,10 +481,12 @@ class BuildEnvironment:
|
||||
mtime = self.all_docs[docname]
|
||||
newmtime = _last_modified_time(self.doc2path(docname))
|
||||
if newmtime > mtime:
|
||||
logger.debug('[build target] outdated %r: %s -> %s',
|
||||
docname,
|
||||
_format_rfc3339_microseconds(mtime),
|
||||
_format_rfc3339_microseconds(newmtime))
|
||||
logger.debug(
|
||||
'[build target] outdated %r: %s -> %s',
|
||||
docname,
|
||||
_format_rfc3339_microseconds(mtime),
|
||||
_format_rfc3339_microseconds(newmtime),
|
||||
)
|
||||
changed.add(docname)
|
||||
continue
|
||||
# finally, check the mtime of dependencies
|
||||
@@ -477,7 +497,8 @@ class BuildEnvironment:
|
||||
if not path.isfile(deppath):
|
||||
logger.debug(
|
||||
'[build target] changed %r missing dependency %r',
|
||||
docname, deppath,
|
||||
docname,
|
||||
deppath,
|
||||
)
|
||||
changed.add(docname)
|
||||
break
|
||||
@@ -485,7 +506,8 @@ class BuildEnvironment:
|
||||
if depmtime > mtime:
|
||||
logger.debug(
|
||||
'[build target] outdated %r from dependency %r: %s -> %s',
|
||||
docname, deppath,
|
||||
docname,
|
||||
deppath,
|
||||
_format_rfc3339_microseconds(mtime),
|
||||
_format_rfc3339_microseconds(depmtime),
|
||||
)
|
||||
@@ -619,7 +641,10 @@ class BuildEnvironment:
|
||||
# now, resolve all toctree nodes
|
||||
for toctreenode in doctree.findall(addnodes.toctree):
|
||||
result = toctree_adapters._resolve_toctree(
|
||||
self, docname, builder, toctreenode,
|
||||
self,
|
||||
docname,
|
||||
builder,
|
||||
toctreenode,
|
||||
prune=prune_toctrees,
|
||||
includehidden=includehidden,
|
||||
)
|
||||
@@ -630,9 +655,17 @@ class BuildEnvironment:
|
||||
|
||||
return doctree
|
||||
|
||||
def resolve_toctree(self, docname: str, builder: Builder, toctree: addnodes.toctree,
|
||||
prune: bool = True, maxdepth: int = 0, titles_only: bool = False,
|
||||
collapse: bool = False, includehidden: bool = False) -> Node | None:
|
||||
def resolve_toctree(
|
||||
self,
|
||||
docname: str,
|
||||
builder: Builder,
|
||||
toctree: addnodes.toctree,
|
||||
prune: bool = True,
|
||||
maxdepth: int = 0,
|
||||
titles_only: bool = False,
|
||||
collapse: bool = False,
|
||||
includehidden: bool = False,
|
||||
) -> Node | None:
|
||||
"""Resolve a *toctree* node into individual bullet lists with titles
|
||||
as items, returning None (if no containing titles are found) or
|
||||
a new node.
|
||||
@@ -645,7 +678,10 @@ class BuildEnvironment:
|
||||
be collapsed.
|
||||
"""
|
||||
return toctree_adapters._resolve_toctree(
|
||||
self, docname, builder, toctree,
|
||||
self,
|
||||
docname,
|
||||
builder,
|
||||
toctree,
|
||||
prune=prune,
|
||||
maxdepth=maxdepth,
|
||||
titles_only=titles_only,
|
||||
@@ -653,8 +689,9 @@ class BuildEnvironment:
|
||||
includehidden=includehidden,
|
||||
)
|
||||
|
||||
def resolve_references(self, doctree: nodes.document, fromdocname: str,
|
||||
builder: Builder) -> None:
|
||||
def resolve_references(
|
||||
self, doctree: nodes.document, fromdocname: str, builder: Builder
|
||||
) -> None:
|
||||
self.apply_post_transforms(doctree, fromdocname)
|
||||
|
||||
def apply_post_transforms(self, doctree: nodes.document, docname: str) -> None:
|
||||
@@ -679,7 +716,7 @@ class BuildEnvironment:
|
||||
|
||||
relations = {}
|
||||
docnames = _traverse_toctree(
|
||||
traversed, None, self.config.root_doc, self.toctree_includes,
|
||||
traversed, None, self.config.root_doc, self.toctree_includes
|
||||
)
|
||||
prev_doc = None
|
||||
parent, docname = next(docnames)
|
||||
@@ -706,8 +743,9 @@ class BuildEnvironment:
|
||||
continue
|
||||
if 'orphan' in self.metadata[docname]:
|
||||
continue
|
||||
logger.warning(__("document isn't included in any toctree"),
|
||||
location=docname)
|
||||
logger.warning(
|
||||
__("document isn't included in any toctree"), location=docname
|
||||
)
|
||||
|
||||
# call check-consistency for all extensions
|
||||
self.domains._check_consistency()
|
||||
@@ -721,9 +759,12 @@ def _traverse_toctree(
|
||||
toctree_includes: dict[str, list[str]],
|
||||
) -> Iterator[tuple[str | None, str]]:
|
||||
if parent == docname:
|
||||
logger.warning(__('self referenced toctree found. Ignored.'),
|
||||
location=docname, type='toc',
|
||||
subtype='circular')
|
||||
logger.warning(
|
||||
__('self referenced toctree found. Ignored.'),
|
||||
location=docname,
|
||||
type='toc',
|
||||
subtype='circular',
|
||||
)
|
||||
return
|
||||
|
||||
# traverse toctree by pre-order
|
||||
@@ -732,7 +773,7 @@ def _traverse_toctree(
|
||||
|
||||
for child in toctree_includes.get(docname, ()):
|
||||
for sub_parent, sub_docname in _traverse_toctree(
|
||||
traversed, docname, child, toctree_includes,
|
||||
traversed, docname, child, toctree_includes
|
||||
):
|
||||
if sub_docname not in traversed:
|
||||
yield sub_parent, sub_docname
|
||||
|
||||
@@ -40,10 +40,10 @@ if TYPE_CHECKING:
|
||||
tuple[
|
||||
_IndexEntryTargets,
|
||||
list[tuple[str, _IndexEntryTargets]],
|
||||
_IndexEntryCategoryKey
|
||||
]
|
||||
_IndexEntryCategoryKey,
|
||||
],
|
||||
]
|
||||
]
|
||||
],
|
||||
]
|
||||
]
|
||||
|
||||
@@ -80,41 +80,77 @@ class IndexEntries:
|
||||
try:
|
||||
entry, sub_entry = _split_into(2, 'single', value)
|
||||
except ValueError:
|
||||
entry, = _split_into(1, 'single', value)
|
||||
(entry,) = _split_into(1, 'single', value)
|
||||
sub_entry = ''
|
||||
_add_entry(entry, sub_entry, main,
|
||||
dic=new, link=uri, key=category_key)
|
||||
_add_entry(
|
||||
entry, sub_entry, main, dic=new, link=uri, key=category_key
|
||||
)
|
||||
elif entry_type == 'pair':
|
||||
first, second = _split_into(2, 'pair', value)
|
||||
_add_entry(first, second, main,
|
||||
dic=new, link=uri, key=category_key)
|
||||
_add_entry(second, first, main,
|
||||
dic=new, link=uri, key=category_key)
|
||||
_add_entry(
|
||||
first, second, main, dic=new, link=uri, key=category_key
|
||||
)
|
||||
_add_entry(
|
||||
second, first, main, dic=new, link=uri, key=category_key
|
||||
)
|
||||
elif entry_type == 'triple':
|
||||
first, second, third = _split_into(3, 'triple', value)
|
||||
_add_entry(first, second + ' ' + third, main,
|
||||
dic=new, link=uri, key=category_key)
|
||||
_add_entry(second, third + ', ' + first, main,
|
||||
dic=new, link=uri, key=category_key)
|
||||
_add_entry(third, first + ' ' + second, main,
|
||||
dic=new, link=uri, key=category_key)
|
||||
_add_entry(
|
||||
first,
|
||||
second + ' ' + third,
|
||||
main,
|
||||
dic=new,
|
||||
link=uri,
|
||||
key=category_key,
|
||||
)
|
||||
_add_entry(
|
||||
second,
|
||||
third + ', ' + first,
|
||||
main,
|
||||
dic=new,
|
||||
link=uri,
|
||||
key=category_key,
|
||||
)
|
||||
_add_entry(
|
||||
third,
|
||||
first + ' ' + second,
|
||||
main,
|
||||
dic=new,
|
||||
link=uri,
|
||||
key=category_key,
|
||||
)
|
||||
elif entry_type == 'see':
|
||||
first, second = _split_into(2, 'see', value)
|
||||
_add_entry(first, _('see %s') % second, None,
|
||||
dic=new, link=False, key=category_key)
|
||||
_add_entry(
|
||||
first,
|
||||
_('see %s') % second,
|
||||
None,
|
||||
dic=new,
|
||||
link=False,
|
||||
key=category_key,
|
||||
)
|
||||
elif entry_type == 'seealso':
|
||||
first, second = _split_into(2, 'see', value)
|
||||
_add_entry(first, _('see also %s') % second, None,
|
||||
dic=new, link=False, key=category_key)
|
||||
_add_entry(
|
||||
first,
|
||||
_('see also %s') % second,
|
||||
None,
|
||||
dic=new,
|
||||
link=False,
|
||||
key=category_key,
|
||||
)
|
||||
else:
|
||||
logger.warning(__('unknown index entry type %r'), entry_type,
|
||||
location=docname)
|
||||
logger.warning(
|
||||
__('unknown index entry type %r'),
|
||||
entry_type,
|
||||
location=docname,
|
||||
)
|
||||
except ValueError as err:
|
||||
logger.warning(str(err), location=docname)
|
||||
|
||||
for (targets, sub_items, _category_key) in new.values():
|
||||
for targets, sub_items, _category_key in new.values():
|
||||
targets.sort(key=_key_func_0)
|
||||
for (sub_targets, _sub_category_key) in sub_items.values():
|
||||
for sub_targets, _sub_category_key in sub_items.values():
|
||||
sub_targets.sort(key=_key_func_0)
|
||||
|
||||
new_list: list[tuple[str, _IndexEntry]] = sorted(new.items(), key=_key_func_1)
|
||||
@@ -139,8 +175,8 @@ class IndexEntries:
|
||||
if old_key == m.group(1):
|
||||
# prefixes match: add entry as subitem of the
|
||||
# previous entry
|
||||
old_sub_items.setdefault(
|
||||
m.group(2), ([], category_key))[0].extend(targets)
|
||||
prev = old_sub_items.setdefault(m[2], ([], category_key))
|
||||
prev[0].extend(targets)
|
||||
del new_list[i]
|
||||
continue
|
||||
old_key = m.group(1)
|
||||
@@ -150,14 +186,13 @@ class IndexEntries:
|
||||
i += 1
|
||||
|
||||
grouped = []
|
||||
for (group_key, group) in groupby(new_list, _group_by_func):
|
||||
for group_key, group in groupby(new_list, _group_by_func):
|
||||
group_list = []
|
||||
for group_entry in group:
|
||||
entry_key, (targets, sub_items, category_key) = group_entry
|
||||
pairs = [
|
||||
(sub_key, sub_targets)
|
||||
for (sub_key, (sub_targets, _sub_category_key))
|
||||
in sub_items.items()
|
||||
for (sub_key, (sub_targets, _sub_category_key)) in sub_items.items()
|
||||
]
|
||||
pairs.sort(key=_key_func_2)
|
||||
group_list.append((entry_key, (targets, pairs, category_key)))
|
||||
@@ -165,9 +200,15 @@ class IndexEntries:
|
||||
return grouped
|
||||
|
||||
|
||||
def _add_entry(word: str, subword: str, main: str | None, *,
|
||||
dic: _IndexEntryMap,
|
||||
link: str | Literal[False], key: _IndexEntryCategoryKey) -> None:
|
||||
def _add_entry(
|
||||
word: str,
|
||||
subword: str,
|
||||
main: str | None,
|
||||
*,
|
||||
dic: _IndexEntryMap,
|
||||
link: str | Literal[False],
|
||||
key: _IndexEntryCategoryKey,
|
||||
) -> None:
|
||||
entry = dic.setdefault(word, ([], {}, key))
|
||||
if subword:
|
||||
targets = entry[1].setdefault(subword, ([], key))[0]
|
||||
|
||||
@@ -24,7 +24,9 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def note_toctree(env: BuildEnvironment, docname: str, toctreenode: addnodes.toctree) -> None:
|
||||
def note_toctree(
|
||||
env: BuildEnvironment, docname: str, toctreenode: addnodes.toctree
|
||||
) -> None:
|
||||
"""Note a TOC tree directive in a document and gather information about
|
||||
file relations from it.
|
||||
"""
|
||||
@@ -87,9 +89,7 @@ def global_toctree_for_doc(
|
||||
)
|
||||
for toctree_node in env.master_doctree.findall(addnodes.toctree)
|
||||
)
|
||||
toctrees = [
|
||||
toctree for toctree in resolved if toctree is not None
|
||||
]
|
||||
toctrees = [toctree for toctree in resolved if toctree is not None]
|
||||
|
||||
if not toctrees:
|
||||
return None
|
||||
@@ -100,9 +100,16 @@ def global_toctree_for_doc(
|
||||
|
||||
|
||||
def _resolve_toctree(
|
||||
env: BuildEnvironment, docname: str, builder: Builder, toctree: addnodes.toctree, *,
|
||||
prune: bool = True, maxdepth: int = 0, titles_only: bool = False,
|
||||
collapse: bool = False, includehidden: bool = False,
|
||||
env: BuildEnvironment,
|
||||
docname: str,
|
||||
builder: Builder,
|
||||
toctree: addnodes.toctree,
|
||||
*,
|
||||
prune: bool = True,
|
||||
maxdepth: int = 0,
|
||||
titles_only: bool = False,
|
||||
collapse: bool = False,
|
||||
includehidden: bool = False,
|
||||
) -> Element | None:
|
||||
"""Resolve a *toctree* node into individual bullet lists with titles
|
||||
as items, returning None (if no containing titles are found) or
|
||||
@@ -178,9 +185,13 @@ def _resolve_toctree(
|
||||
|
||||
# prune the tree to maxdepth, also set toc depth and current classes
|
||||
_toctree_add_classes(newnode, 1, docname)
|
||||
newnode = _toctree_copy(newnode, 1, maxdepth if prune else 0, collapse, builder.tags)
|
||||
newnode = _toctree_copy(
|
||||
newnode, 1, maxdepth if prune else 0, collapse, builder.tags
|
||||
)
|
||||
|
||||
if isinstance(newnode[-1], nodes.Element) and len(newnode[-1]) == 0: # No titles found
|
||||
if (
|
||||
isinstance(newnode[-1], nodes.Element) and len(newnode[-1]) == 0
|
||||
): # No titles found
|
||||
return None
|
||||
|
||||
# set the target paths in the toctrees (they are not known at TOC
|
||||
@@ -208,11 +219,20 @@ def _entries_from_toctree(
|
||||
) -> list[Element]:
|
||||
"""Return TOC entries for a toctree node."""
|
||||
entries: list[Element] = []
|
||||
for (title, ref) in toctreenode['entries']:
|
||||
for title, ref in toctreenode['entries']:
|
||||
try:
|
||||
toc, refdoc = _toctree_entry(
|
||||
title, ref, env, prune, collapse, tags, toctree_ancestors,
|
||||
included, excluded, toctreenode, parents,
|
||||
title,
|
||||
ref,
|
||||
env,
|
||||
prune,
|
||||
collapse,
|
||||
tags,
|
||||
toctree_ancestors,
|
||||
included,
|
||||
excluded,
|
||||
toctreenode,
|
||||
parents,
|
||||
)
|
||||
except LookupError:
|
||||
continue
|
||||
@@ -294,10 +314,14 @@ def _toctree_entry(
|
||||
toc = _toctree_generated_entry(title, ref)
|
||||
else:
|
||||
if ref in parents:
|
||||
logger.warning(__('circular toctree references '
|
||||
'detected, ignoring: %s <- %s'),
|
||||
ref, ' <- '.join(parents),
|
||||
location=ref, type='toc', subtype='circular')
|
||||
logger.warning(
|
||||
__('circular toctree references ' 'detected, ignoring: %s <- %s'),
|
||||
ref,
|
||||
' <- '.join(parents),
|
||||
location=ref,
|
||||
type='toc',
|
||||
subtype='circular',
|
||||
)
|
||||
msg = 'circular reference'
|
||||
raise LookupError(msg)
|
||||
|
||||
@@ -314,9 +338,16 @@ def _toctree_entry(
|
||||
|
||||
if not toc.children:
|
||||
# empty toc means: no titles will show up in the toctree
|
||||
logger.warning(__('toctree contains reference to document %r that '
|
||||
"doesn't have a title: no link will be generated"),
|
||||
ref, location=toctreenode, type='toc', subtype='no_title')
|
||||
logger.warning(
|
||||
__(
|
||||
'toctree contains reference to document %r that '
|
||||
"doesn't have a title: no link will be generated"
|
||||
),
|
||||
ref,
|
||||
location=toctreenode,
|
||||
type='toc',
|
||||
subtype='no_title',
|
||||
)
|
||||
except KeyError:
|
||||
# this is raised if the included file does not exist
|
||||
ref_path = str(env.doc2path(ref, False))
|
||||
@@ -335,9 +366,9 @@ def _toctree_entry(
|
||||
def _toctree_url_entry(title: str, ref: str) -> nodes.bullet_list:
|
||||
if title is None:
|
||||
title = ref
|
||||
reference = nodes.reference('', '', internal=False,
|
||||
refuri=ref, anchorname='',
|
||||
*[nodes.Text(title)])
|
||||
reference = nodes.reference(
|
||||
'', '', internal=False, refuri=ref, anchorname='', *[nodes.Text(title)]
|
||||
)
|
||||
para = addnodes.compact_paragraph('', '', reference)
|
||||
item = nodes.list_item('', para)
|
||||
toc = nodes.bullet_list('', item)
|
||||
@@ -345,16 +376,17 @@ def _toctree_url_entry(title: str, ref: str) -> nodes.bullet_list:
|
||||
|
||||
|
||||
def _toctree_self_entry(
|
||||
title: str, ref: str, titles: dict[str, nodes.title],
|
||||
title: str,
|
||||
ref: str,
|
||||
titles: dict[str, nodes.title],
|
||||
) -> nodes.bullet_list:
|
||||
# 'self' refers to the document from which this
|
||||
# toctree originates
|
||||
if not title:
|
||||
title = clean_astext(titles[ref])
|
||||
reference = nodes.reference('', '', internal=True,
|
||||
refuri=ref,
|
||||
anchorname='',
|
||||
*[nodes.Text(title)])
|
||||
reference = nodes.reference(
|
||||
'', '', internal=True, refuri=ref, anchorname='', *[nodes.Text(title)]
|
||||
)
|
||||
para = addnodes.compact_paragraph('', '', reference)
|
||||
item = nodes.list_item('', para)
|
||||
# don't show subitems
|
||||
@@ -368,8 +400,7 @@ def _toctree_generated_entry(title: str, ref: str) -> nodes.bullet_list:
|
||||
docname, sectionname = StandardDomain._virtual_doc_names[ref]
|
||||
if not title:
|
||||
title = sectionname
|
||||
reference = nodes.reference('', title, internal=True,
|
||||
refuri=docname, anchorname='')
|
||||
reference = nodes.reference('', title, internal=True, refuri=docname, anchorname='')
|
||||
para = addnodes.compact_paragraph('', '', reference)
|
||||
item = nodes.list_item('', para)
|
||||
# don't show subitems
|
||||
@@ -434,11 +465,13 @@ def _toctree_add_classes(node: Element, depth: int, docname: str) -> None:
|
||||
ET = TypeVar('ET', bound=Element)
|
||||
|
||||
|
||||
def _toctree_copy(node: ET, depth: int, maxdepth: int, collapse: bool, tags: Tags) -> ET:
|
||||
def _toctree_copy(
|
||||
node: ET, depth: int, maxdepth: int, collapse: bool, tags: Tags
|
||||
) -> ET:
|
||||
"""Utility: Cut and deep-copy a TOC at a specified depth."""
|
||||
keep_bullet_list_sub_nodes = (depth <= 1
|
||||
or ((depth <= maxdepth or maxdepth <= 0)
|
||||
and (not collapse or 'iscurrent' in node)))
|
||||
keep_bullet_list_sub_nodes = depth <= 1 or (
|
||||
(depth <= maxdepth or maxdepth <= 0) and (not collapse or 'iscurrent' in node)
|
||||
)
|
||||
|
||||
copy = node.copy()
|
||||
for subnode in node.children:
|
||||
@@ -459,9 +492,15 @@ def _toctree_copy(node: ET, depth: int, maxdepth: int, collapse: bool, tags: Tag
|
||||
# only keep children if the only node matches the tags
|
||||
if _only_node_keep_children(subnode, tags):
|
||||
for child in subnode.children:
|
||||
copy.append(_toctree_copy(
|
||||
child, depth, maxdepth, collapse, tags, # type: ignore[type-var]
|
||||
))
|
||||
copy.append(
|
||||
_toctree_copy(
|
||||
child,
|
||||
depth,
|
||||
maxdepth,
|
||||
collapse,
|
||||
tags, # type: ignore[type-var]
|
||||
)
|
||||
)
|
||||
elif isinstance(subnode, nodes.reference | nodes.title):
|
||||
# deep copy references and captions
|
||||
sub_node_copy = subnode.copy()
|
||||
@@ -476,7 +515,8 @@ def _toctree_copy(node: ET, depth: int, maxdepth: int, collapse: bool, tags: Tag
|
||||
|
||||
|
||||
def _get_toctree_ancestors(
|
||||
toctree_includes: dict[str, list[str]], docname: str,
|
||||
toctree_includes: dict[str, list[str]],
|
||||
docname: str,
|
||||
) -> Set[str]:
|
||||
parent: dict[str, str] = {}
|
||||
for p, children in toctree_includes.items():
|
||||
@@ -497,11 +537,22 @@ class TocTree:
|
||||
def note(self, docname: str, toctreenode: addnodes.toctree) -> None:
|
||||
note_toctree(self.env, docname, toctreenode)
|
||||
|
||||
def resolve(self, docname: str, builder: Builder, toctree: addnodes.toctree,
|
||||
prune: bool = True, maxdepth: int = 0, titles_only: bool = False,
|
||||
collapse: bool = False, includehidden: bool = False) -> Element | None:
|
||||
def resolve(
|
||||
self,
|
||||
docname: str,
|
||||
builder: Builder,
|
||||
toctree: addnodes.toctree,
|
||||
prune: bool = True,
|
||||
maxdepth: int = 0,
|
||||
titles_only: bool = False,
|
||||
collapse: bool = False,
|
||||
includehidden: bool = False,
|
||||
) -> Element | None:
|
||||
return _resolve_toctree(
|
||||
self.env, docname, builder, toctree,
|
||||
self.env,
|
||||
docname,
|
||||
builder,
|
||||
toctree,
|
||||
prune=prune,
|
||||
maxdepth=maxdepth,
|
||||
titles_only=titles_only,
|
||||
@@ -516,6 +567,12 @@ class TocTree:
|
||||
return document_toc(self.env, docname, self.env.app.builder.tags)
|
||||
|
||||
def get_toctree_for(
|
||||
self, docname: str, builder: Builder, collapse: bool, **kwargs: Any,
|
||||
self,
|
||||
docname: str,
|
||||
builder: Builder,
|
||||
collapse: bool,
|
||||
**kwargs: Any,
|
||||
) -> Element | None:
|
||||
return global_toctree_for_doc(self.env, docname, builder, collapse=collapse, **kwargs)
|
||||
return global_toctree_for_doc(
|
||||
self.env, docname, builder, collapse=collapse, **kwargs
|
||||
)
|
||||
@@ -29,10 +29,10 @@ class EnvironmentCollector:
|
||||
def enable(self, app: Sphinx) -> None:
|
||||
assert self.listener_ids is None
|
||||
self.listener_ids = {
|
||||
'doctree-read': app.connect('doctree-read', self.process_doc),
|
||||
'env-merge-info': app.connect('env-merge-info', self.merge_other),
|
||||
'env-purge-doc': app.connect('env-purge-doc', self.clear_doc),
|
||||
'env-get-updated': app.connect('env-get-updated', self.get_updated_docs),
|
||||
'doctree-read': app.connect('doctree-read', self.process_doc),
|
||||
'env-merge-info': app.connect('env-merge-info', self.merge_other),
|
||||
'env-purge-doc': app.connect('env-purge-doc', self.clear_doc),
|
||||
'env-get-updated': app.connect('env-get-updated', self.get_updated_docs),
|
||||
'env-get-outdated': app.connect('env-get-outdated', self.get_outdated_docs),
|
||||
}
|
||||
|
||||
@@ -51,8 +51,13 @@ class EnvironmentCollector:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
"""Merge in specified data regarding docnames from a different `BuildEnvironment`
|
||||
object which coming from a subprocess in parallel builds.
|
||||
|
||||
@@ -78,8 +83,14 @@ class EnvironmentCollector:
|
||||
"""
|
||||
return []
|
||||
|
||||
def get_outdated_docs(self, app: Sphinx, env: BuildEnvironment,
|
||||
added: set[str], changed: set[str], removed: set[str]) -> list[str]:
|
||||
def get_outdated_docs(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
added: set[str],
|
||||
changed: set[str],
|
||||
removed: set[str],
|
||||
) -> list[str]:
|
||||
"""Return a list of docnames to re-read.
|
||||
|
||||
This method is called before reading the documents.
|
||||
|
||||
@@ -33,8 +33,13 @@ class ImageCollector(EnvironmentCollector):
|
||||
def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None:
|
||||
env.images.purge_doc(docname)
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
env.images.merge_other(docnames, other.images)
|
||||
|
||||
def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
|
||||
@@ -86,17 +91,26 @@ class ImageCollector(EnvironmentCollector):
|
||||
for imgpath in candidates.values():
|
||||
app.env.dependencies[docname].add(imgpath)
|
||||
if not os.access(path.join(app.srcdir, imgpath), os.R_OK):
|
||||
logger.warning(__('image file not readable: %s'), imgpath,
|
||||
location=node, type='image', subtype='not_readable')
|
||||
logger.warning(
|
||||
__('image file not readable: %s'),
|
||||
imgpath,
|
||||
location=node,
|
||||
type='image',
|
||||
subtype='not_readable',
|
||||
)
|
||||
continue
|
||||
app.env.images.add_file(docname, imgpath)
|
||||
|
||||
def collect_candidates(self, env: BuildEnvironment, imgpath: str,
|
||||
candidates: dict[str, str], node: Node) -> None:
|
||||
def collect_candidates(
|
||||
self,
|
||||
env: BuildEnvironment,
|
||||
imgpath: str,
|
||||
candidates: dict[str, str],
|
||||
node: Node,
|
||||
) -> None:
|
||||
globbed: dict[str, list[str]] = {}
|
||||
for filename in glob(imgpath):
|
||||
new_imgpath = relative_path(path.join(env.srcdir, 'dummy'),
|
||||
filename)
|
||||
new_imgpath = relative_path(path.join(env.srcdir, 'dummy'), filename)
|
||||
try:
|
||||
mimetype = guess_mimetype(filename)
|
||||
if mimetype is None:
|
||||
@@ -105,8 +119,14 @@ class ImageCollector(EnvironmentCollector):
|
||||
if mimetype not in candidates:
|
||||
globbed.setdefault(mimetype, []).append(new_imgpath)
|
||||
except OSError as err:
|
||||
logger.warning(__('image file %s not readable: %s'), filename, err,
|
||||
location=node, type='image', subtype='not_readable')
|
||||
logger.warning(
|
||||
__('image file %s not readable: %s'),
|
||||
filename,
|
||||
err,
|
||||
location=node,
|
||||
type='image',
|
||||
subtype='not_readable',
|
||||
)
|
||||
for key, files in globbed.items():
|
||||
candidates[key] = min(files, key=len) # select by similarity
|
||||
|
||||
@@ -117,8 +137,13 @@ class DownloadFileCollector(EnvironmentCollector):
|
||||
def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None:
|
||||
env.dlfiles.purge_doc(docname)
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
env.dlfiles.merge_other(docnames, other.dlfiles)
|
||||
|
||||
def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
|
||||
@@ -131,10 +156,17 @@ class DownloadFileCollector(EnvironmentCollector):
|
||||
rel_filename, filename = app.env.relfn2path(targetname, app.env.docname)
|
||||
app.env.dependencies[app.env.docname].add(rel_filename)
|
||||
if not os.access(filename, os.R_OK):
|
||||
logger.warning(__('download file not readable: %s'), filename,
|
||||
location=node, type='download', subtype='not_readable')
|
||||
logger.warning(
|
||||
__('download file not readable: %s'),
|
||||
filename,
|
||||
location=node,
|
||||
type='download',
|
||||
subtype='not_readable',
|
||||
)
|
||||
continue
|
||||
node['filename'] = app.env.dlfiles.add_file(app.env.docname, rel_filename)
|
||||
node['filename'] = app.env.dlfiles.add_file(
|
||||
app.env.docname, rel_filename
|
||||
)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||
|
||||
@@ -25,8 +25,13 @@ class DependenciesCollector(EnvironmentCollector):
|
||||
def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None:
|
||||
env.dependencies.pop(docname, None)
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
for docname in docnames:
|
||||
if docname in other.dependencies:
|
||||
env.dependencies[docname] = other.dependencies[docname]
|
||||
@@ -43,8 +48,7 @@ class DependenciesCollector(EnvironmentCollector):
|
||||
# one relative to the srcdir
|
||||
if isinstance(dep, bytes):
|
||||
dep = dep.decode(fs_encoding)
|
||||
relpath = relative_path(frompath,
|
||||
path.normpath(path.join(cwd, dep)))
|
||||
relpath = relative_path(frompath, path.normpath(path.join(cwd, dep)))
|
||||
app.env.dependencies[app.env.docname].add(relpath)
|
||||
|
||||
|
||||
|
||||
@@ -20,8 +20,13 @@ class MetadataCollector(EnvironmentCollector):
|
||||
def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None:
|
||||
env.metadata.pop(docname, None)
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
for docname in docnames:
|
||||
env.metadata[docname] = other.metadata[docname]
|
||||
|
||||
|
||||
@@ -22,8 +22,13 @@ class TitleCollector(EnvironmentCollector):
|
||||
env.titles.pop(docname, None)
|
||||
env.longtitles.pop(docname, None)
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: set[str], other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
for docname in docnames:
|
||||
env.titles[docname] = other.titles[docname]
|
||||
env.longtitles[docname] = other.longtitles[docname]
|
||||
|
||||
@@ -43,8 +43,13 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
if not fnset:
|
||||
del env.files_to_rebuild[subfn]
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment, docnames: set[str],
|
||||
other: BuildEnvironment) -> None:
|
||||
def merge_other(
|
||||
self,
|
||||
app: Sphinx,
|
||||
env: BuildEnvironment,
|
||||
docnames: set[str],
|
||||
other: BuildEnvironment,
|
||||
) -> None:
|
||||
for docname in docnames:
|
||||
env.tocs[docname] = other.tocs[docname]
|
||||
env.toc_num_entries[docname] = other.toc_num_entries[docname]
|
||||
@@ -84,8 +89,13 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
# make these nodes:
|
||||
# list_item -> compact_paragraph -> reference
|
||||
reference = nodes.reference(
|
||||
'', '', internal=True, refuri=docname,
|
||||
anchorname=anchorname, *nodetext)
|
||||
'',
|
||||
'',
|
||||
internal=True,
|
||||
refuri=docname,
|
||||
anchorname=anchorname,
|
||||
*nodetext,
|
||||
)
|
||||
para = addnodes.compact_paragraph('', '', reference)
|
||||
item: Element = nodes.list_item('', para)
|
||||
sub_item = build_toc(sectionnode, depth + 1)
|
||||
@@ -136,15 +146,23 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
anchorname = _make_anchor_name(ids, numentries)
|
||||
|
||||
reference = nodes.reference(
|
||||
'', '', nodes.literal('', sig_node['_toc_name']),
|
||||
internal=True, refuri=docname, anchorname=anchorname)
|
||||
para = addnodes.compact_paragraph('', '', reference,
|
||||
skip_section_number=True)
|
||||
'',
|
||||
'',
|
||||
nodes.literal('', sig_node['_toc_name']),
|
||||
internal=True,
|
||||
refuri=docname,
|
||||
anchorname=anchorname,
|
||||
)
|
||||
para = addnodes.compact_paragraph(
|
||||
'', '', reference, skip_section_number=True
|
||||
)
|
||||
entry = nodes.list_item('', para)
|
||||
|
||||
# Find parent node
|
||||
parent = sig_node.parent
|
||||
while parent not in memo_parents and parent != sectionnode:
|
||||
while (
|
||||
parent not in memo_parents and parent != sectionnode
|
||||
):
|
||||
parent = parent.parent
|
||||
# Note, it may both be the limit and in memo_parents,
|
||||
# prefer memo_parents, so we get the nesting.
|
||||
@@ -231,14 +249,21 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
def _walk_toctree(toctreenode: addnodes.toctree, depth: int) -> None:
|
||||
if depth == 0:
|
||||
return
|
||||
for (_title, ref) in toctreenode['entries']:
|
||||
for _title, ref in toctreenode['entries']:
|
||||
if url_re.match(ref) or ref == 'self':
|
||||
# don't mess with those
|
||||
continue
|
||||
if ref in assigned:
|
||||
logger.warning(__('%s is already assigned section numbers '
|
||||
'(nested numbered toctree?)'), ref,
|
||||
location=toctreenode, type='toc', subtype='secnum')
|
||||
logger.warning(
|
||||
__(
|
||||
'%s is already assigned section numbers '
|
||||
'(nested numbered toctree?)'
|
||||
),
|
||||
ref,
|
||||
location=toctreenode,
|
||||
type='toc',
|
||||
subtype='secnum',
|
||||
)
|
||||
elif ref in env.tocs:
|
||||
secnums: dict[str, tuple[int, ...]] = {}
|
||||
env.toc_secnumbers[ref] = secnums
|
||||
@@ -273,7 +298,9 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
def get_figtype(node: Node) -> str | None:
|
||||
for domain in env.domains.sorted():
|
||||
figtype = domain.get_enumerable_node_type(node)
|
||||
if isinstance(domain, StandardDomain) and not domain.get_numfig_title(node):
|
||||
if isinstance(domain, StandardDomain) and not domain.get_numfig_title(
|
||||
node
|
||||
):
|
||||
# Skip if uncaptioned node
|
||||
continue
|
||||
|
||||
@@ -292,22 +319,27 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
|
||||
return secnum or ()
|
||||
|
||||
def get_next_fignumber(figtype: str, secnum: tuple[int, ...]) -> tuple[int, ...]:
|
||||
def get_next_fignumber(
|
||||
figtype: str, secnum: tuple[int, ...]
|
||||
) -> tuple[int, ...]:
|
||||
counter = fignum_counter.setdefault(figtype, {})
|
||||
|
||||
secnum = secnum[:env.config.numfig_secnum_depth]
|
||||
secnum = secnum[: env.config.numfig_secnum_depth]
|
||||
counter[secnum] = counter.get(secnum, 0) + 1
|
||||
return (*secnum, counter[secnum])
|
||||
|
||||
def register_fignumber(docname: str, secnum: tuple[int, ...],
|
||||
figtype: str, fignode: Element) -> None:
|
||||
def register_fignumber(
|
||||
docname: str, secnum: tuple[int, ...], figtype: str, fignode: Element
|
||||
) -> None:
|
||||
env.toc_fignumbers.setdefault(docname, {})
|
||||
fignumbers = env.toc_fignumbers[docname].setdefault(figtype, {})
|
||||
figure_id = fignode['ids'][0]
|
||||
|
||||
fignumbers[figure_id] = get_next_fignumber(figtype, secnum)
|
||||
|
||||
def _walk_doctree(docname: str, doctree: Element, secnum: tuple[int, ...]) -> None:
|
||||
def _walk_doctree(
|
||||
docname: str, doctree: Element, secnum: tuple[int, ...]
|
||||
) -> None:
|
||||
nonlocal generated_docnames
|
||||
for subnode in doctree.children:
|
||||
if isinstance(subnode, nodes.section):
|
||||
|
||||
Reference in new issue
Block a user