def visit_transition(self, node): if isinstance(node.parent, addnodes.only): process_only_nodes( node.parent.parent, tags=self.document.settings.env.app.builder.tags, )
def run(self, **kwargs): # type: (Any) -> None # A comment on the comment() nodes being inserted: replacing by [] would # result in a "Losing ids" exception if there is a target node before # the only node, so we make sure docutils can transfer the id to # something, even if it's just a comment and will lose the id anyway... process_only_nodes(self.document, self.app.builder.tags)
def apply(self, **kwargs): # type: (Any) -> None # A comment on the comment() nodes being inserted: replacing by [] would # result in a "Losing ids" exception if there is a target node before # the only node, so we make sure docutils can transfer the id to # something, even if it's just a comment and will lose the id anyway... process_only_nodes(self.document, self.app.builder.tags)
def get_toc_for(self, docname: str, builder: "Builder") -> Node: """Return a TOC nodetree -- for use on the same page only!""" tocdepth = self.env.metadata[docname].get('tocdepth', 0) try: toc = self.env.tocs[docname].deepcopy() self._toctree_prune(toc, 2, tocdepth) except KeyError: # the document does not exist anymore: return a dummy node that # renders to nothing return nodes.paragraph() process_only_nodes(toc, builder.tags) for node in toc.traverse(nodes.reference): node['refuri'] = node['anchorname'] or '#' return toc
def get_toc_for(self, docname, builder): """Return a TOC nodetree -- for use on the same page only!""" tocdepth = self.env.metadata[docname].get('tocdepth', 0) try: toc = self.tocs[docname].deepcopy() self._toctree_prune(toc, 2, tocdepth) except KeyError: # the document does not exist anymore: return a dummy node that # renders to nothing return nodes.paragraph() process_only_nodes(toc, builder.tags, warn_node=self.env.warn_node) for node in toc.traverse(nodes.reference): node['refuri'] = node['anchorname'] or '#' return toc
def resolve_references(self, doctree, fromdocname, builder): # type: (nodes.Node, unicode, Builder) -> None for node in doctree.traverse(addnodes.pending_xref): contnode = node[0].deepcopy() newnode = None typ = node['reftype'] target = node['reftarget'] refdoc = node.get('refdoc', fromdocname) domain = None try: if 'refdomain' in node and node['refdomain']: # let the domain try to resolve the reference try: domain = self.domains[node['refdomain']] except KeyError: raise NoUri newnode = domain.resolve_xref(self, refdoc, builder, typ, target, node, contnode) # really hardwired reference types elif typ == 'any': newnode = self._resolve_any_reference( builder, refdoc, node, contnode) elif typ == 'doc': newnode = self._resolve_doc_reference( builder, refdoc, node, contnode) # no new node found? try the missing-reference event if newnode is None: newnode = builder.app.emit_firstresult( 'missing-reference', self, node, contnode) # still not found? warn if node wishes to be warned about or # we are in nit-picky mode if newnode is None: self._warn_missing_reference(refdoc, typ, target, node, domain) except NoUri: newnode = contnode node.replace_self(newnode or contnode) # remove only-nodes that do not belong to our builder process_only_nodes(doctree, builder.tags) # allow custom references to be resolved builder.app.emit('doctree-resolved', doctree, fromdocname)
def get_local_toc_for(builder, docname, maxdepth=-1): """Return a TOC nodetree -- for use on the same page only!""" env = builder.env if maxdepth < 0: maxdepth = env.metadata[docname].get('tocdepth', 0) toctree = env.toctree try: toc = toctree.tocs[docname].deepcopy() toctree._toctree_prune(toc, 2, maxdepth) except KeyError: # the document does not exist anymore: return a dummy node that # renders to nothing return nodes.paragraph() sphinx_nodes.process_only_nodes(toc, builder.tags, warn_node=env.warn_node) for node in toc.traverse(nodes.reference): node['refuri'] = node['anchorname'] or '#' return toc
def resolve_references(self, doctree, fromdocname, builder): for node in doctree.traverse(addnodes.pending_xref): contnode = node[0].deepcopy() newnode = None typ = node['reftype'] target = node['reftarget'] refdoc = node.get('refdoc', fromdocname) domain = None try: if 'refdomain' in node and node['refdomain']: # let the domain try to resolve the reference try: domain = self.domains[node['refdomain']] except KeyError: raise NoUri newnode = domain.resolve_xref(self, refdoc, builder, typ, target, node, contnode) # really hardwired reference types elif typ == 'any': newnode = self._resolve_any_reference(builder, refdoc, node, contnode) elif typ == 'doc': newnode = self._resolve_doc_reference(builder, refdoc, node, contnode) # no new node found? try the missing-reference event if newnode is None: newnode = builder.app.emit_firstresult( 'missing-reference', self, node, contnode) # still not found? warn if node wishes to be warned about or # we are in nit-picky mode if newnode is None: self._warn_missing_reference(refdoc, typ, target, node, domain) except NoUri: newnode = contnode node.replace_self(newnode or contnode) # remove only-nodes that do not belong to our builder process_only_nodes(doctree, builder.tags, warn_node=self.warn_node) # allow custom references to be resolved builder.app.emit('doctree-resolved', doctree, fromdocname)
def test_sectioning(app, status, warning): def getsects(section): if not isinstance(section, nodes.section): return [getsects(n) for n in section.children] title = section.next_node(nodes.title).astext().strip() subsects = [] children = section.children[:] while children: node = children.pop(0) if isinstance(node, nodes.section): subsects.append(node) continue children = list(node.children) + children return [title, [getsects(subsect) for subsect in subsects]] def testsects(prefix, sects, indent=0): title = sects[0] parent_num = title.split()[0] assert prefix == parent_num, \ 'Section out of place: %r' % title for i, subsect in enumerate(sects[1]): num = subsect[0].split()[0] assert re.match('[0-9]+[.0-9]*[.]', num), \ 'Unnumbered section: %r' % subsect[0] testsects(prefix + str(i + 1) + '.', subsect, indent + 4) app.builder.build(['only']) doctree = app.env.get_doctree('only') process_only_nodes(doctree, app.builder.tags) parts = [ getsects(n) for n in [_n for _n in doctree.children if isinstance(_n, nodes.section)] ] for i, s in enumerate(parts): testsects(str(i + 1) + '.', s, 4) assert len(parts) == 4, 'Expected 4 document level headings, got:\n%s' % \ '\n'.join([p[0] for p in parts])
def test_sectioning(app, status, warning): def getsects(section): if not isinstance(section, nodes.section): return [getsects(n) for n in section.children] title = section.next_node(nodes.title).astext().strip() subsects = [] children = section.children[:] while children: node = children.pop(0) if isinstance(node, nodes.section): subsects.append(node) continue children = list(node.children) + children return [title, [getsects(subsect) for subsect in subsects]] def testsects(prefix, sects, indent=0): title = sects[0] parent_num = title.split()[0] assert prefix == parent_num, \ 'Section out of place: %r' % title for i, subsect in enumerate(sects[1]): num = subsect[0].split()[0] assert re.match('[0-9]+[.0-9]*[.]', num), \ 'Unnumbered section: %r' % subsect[0] testsects(prefix + str(i+1) + '.', subsect, indent+4) app.builder.build(['only']) doctree = app.env.get_doctree('only') process_only_nodes(doctree, app.builder.tags) parts = [getsects(n) for n in [_n for _n in doctree.children if isinstance(_n, nodes.section)]] for i, s in enumerate(parts): testsects(str(i+1) + '.', s, 4) assert len(parts) == 4, 'Expected 4 document level headings, got:\n%s' % \ '\n'.join([p[0] for p in parts])
def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): if title is None: title = ref 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) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.env.titles[ref]) 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 toc = nodes.bullet_list('', item) else: if ref in parents: logger.warning( 'circular toctree references ' 'detected, ignoring: %s <- %s', ref, ' <- '.join(parents), location=ref) continue refdoc = ref toc = self.tocs[ref].deepcopy() maxdepth = self.env.metadata[ref].get('tocdepth', 0) if ref not in toctree_ancestors or (prune and maxdepth > 0): self._toctree_prune(toc, 2, maxdepth, collapse) process_only_nodes(toc, builder.tags) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] 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) except KeyError: # this is raised if the included file does not exist logger.warning( 'toctree contains reference to nonexisting document %r', ref, location=toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) if subtrees: toplevel[1][:] = subtrees else: toplevel.pop(1) # resolve all sub-toctrees for subtocnode in toc.traverse(addnodes.toctree): if not (subtocnode.get('hidden', False) and not includehidden): i = subtocnode.parent.index(subtocnode) + 1 for item in _entries_from_toctree( subtocnode, [refdoc] + parents, subtree=True): subtocnode.parent.insert(i, item) i += 1 subtocnode.parent.remove(subtocnode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def _entries_from_toctree(toctreenode, parents, separate=False, subtree=False): """Return TOC entries for a toctree node.""" refs = [(e[0], e[1]) for e in toctreenode['entries']] entries = [] for (title, ref) in refs: try: refdoc = None if url_re.match(ref): if title is None: title = ref 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) elif ref == 'self': # 'self' refers to the document from which this # toctree originates ref = toctreenode['parent'] if not title: title = clean_astext(self.titles[ref]) 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 toc = nodes.bullet_list('', item) else: if ref in parents: self.env.warn(ref, 'circular toctree references ' 'detected, ignoring: %s <- %s' % (ref, ' <- '.join(parents))) continue refdoc = ref toc = self.tocs[ref].deepcopy() maxdepth = self.env.metadata[ref].get('tocdepth', 0) if ref not in toctree_ancestors or (prune and maxdepth > 0): self._toctree_prune(toc, 2, maxdepth, collapse) process_only_nodes(toc, builder.tags, warn_node=self.env.warn_node) if title and toc.children and len(toc.children) == 1: child = toc.children[0] for refnode in child.traverse(nodes.reference): if refnode['refuri'] == ref and \ not refnode['anchorname']: refnode.children = [nodes.Text(title)] if not toc.children: # empty toc means: no titles will show up in the toctree self.env.warn_node( 'toctree contains reference to document %r that ' 'doesn\'t have a title: no link will be generated' % ref, toctreenode) except KeyError: # this is raised if the included file does not exist self.env.warn_node( 'toctree contains reference to nonexisting document %r' % ref, toctreenode) else: # if titles_only is given, only keep the main title and # sub-toctrees if titles_only: # delete everything but the toplevel title(s) # and toctrees for toplevel in toc: # nodes with length 1 don't have any children anyway if len(toplevel) > 1: subtrees = toplevel.traverse(addnodes.toctree) if subtrees: toplevel[1][:] = subtrees else: toplevel.pop(1) # resolve all sub-toctrees for subtocnode in toc.traverse(addnodes.toctree): if not (subtocnode.get('hidden', False) and not includehidden): i = subtocnode.parent.index(subtocnode) + 1 for item in _entries_from_toctree( subtocnode, [refdoc] + parents, subtree=True): subtocnode.parent.insert(i, item) i += 1 subtocnode.parent.remove(subtocnode) if separate: entries.append(toc) else: entries.extend(toc.children) if not subtree and not separate: ret = nodes.bullet_list() ret += entries return [ret] return entries
def write(self, *ignored: Any) -> None: assert self.env is not None docwriter = LaTeXWriter(self) docsettings: Any = OptionParser( defaults=self.env.settings, components=(docwriter, ), read_config_files=True, ).get_default_values() if sphinx.version_info <= (4, 0): # 3rd party from sphinx.builders.latex import patch_settings # type: ignore patch_settings(docsettings) self.init_document_data() self.write_stylesheet() for entry in self.document_data: docname, targetname, title, author, themename = entry[:5] theme = self.themes.get(themename) toctree_only = False if len(entry) > 5: toctree_only = entry[5] destination = SphinxFileOutput(destination_path=os.path.join( self.outdir, targetname), encoding="utf-8", overwrite_if_changed=True) with progress_message(__("processing %s") % targetname): doctree = self.env.get_doctree(docname) process_only_nodes(doctree, self.tags) toctree = next(iter(doctree.traverse(addnodes.toctree)), None) if toctree and toctree.get("maxdepth") > 0: tocdepth = toctree.get("maxdepth") else: tocdepth = None doctree = self.assemble_doctree( docname, toctree_only, appendices=(self.config.latex_appendices if theme.name != "howto" else [])) doctree["docclass"] = theme.docclass doctree["contentsname"] = self.get_contentsname(docname) doctree["tocdepth"] = tocdepth self.post_process_images(doctree) self.update_doc_context(title, author, theme) if hasattr(self, "update_context"): # pragma: no cover # Only present in newer Sphinx versions self.update_context() with progress_message(__("writing")): docsettings._author = author docsettings._title = title docsettings._contentsname = doctree["contentsname"] docsettings._docname = docname docsettings._docclass = theme.name doctree.settings = docsettings docwriter.theme = theme docwriter.write(doctree, destination)