Enable automatic formatting for `sphinx/environment/` (#12968)

This commit is contained in:
Adam Turner authored and GitHub committed 2024-10-04 16:40:48 +01:00
1 parent 81c6f1e8cc
commit 4dfddc533c
10 files changed
+392 -165

No files matched your search

-1
View File
@@ -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",
+80 -39
View File
@@ -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
+73 -32
View File
@@ -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]
+100 -43
View File
@@ -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
)
+19 -8
View File
@@ -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.
+47 -15
View File
@@ -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)
+7 -2
View File
@@ -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]
+7 -2
View File
@@ -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]
+51 -19
View File
@@ -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):