Esempio n. 1
0
    def fix_ids(self, tree: nodes.document) -> None:
        """Replace colons with hyphens in href and id attributes.

        Some readers crash because they interpret the part as a
        transport protocol specification.
        """
        def update_node_id(node: Element) -> None:
            """Update IDs of given *node*."""
            new_ids: List[str] = []
            for node_id in node['ids']:
                new_id = self.fix_fragment('', node_id)
                if new_id not in new_ids:
                    new_ids.append(new_id)
            node['ids'] = new_ids

        for reference in tree.findall(nodes.reference):
            if 'refuri' in reference:
                m = self.refuri_re.match(reference['refuri'])
                if m:
                    reference['refuri'] = self.fix_fragment(m.group(1), m.group(2))
            if 'refid' in reference:
                reference['refid'] = self.fix_fragment('', reference['refid'])

        for target in tree.findall(nodes.target):
            update_node_id(target)

            next_node: Node = target.next_node(ascend=True)
            if isinstance(next_node, nodes.Element):
                update_node_id(next_node)

        for desc_signature in tree.findall(addnodes.desc_signature):
            update_node_id(desc_signature)
Esempio n. 2
0
    def get_and_resolve_doctree(self,
                                docname: str,
                                builder: "Builder",
                                doctree: nodes.document = None,
                                prune_toctrees: bool = True,
                                includehidden: bool = False) -> nodes.document:
        """Read the doctree from the pickle, resolve cross-references and
        toctrees and return it.
        """
        if doctree is None:
            doctree = self.get_doctree(docname)

        # resolve all pending cross-references
        self.apply_post_transforms(doctree, docname)

        # now, resolve all toctree nodes
        for toctreenode in doctree.findall(addnodes.toctree):
            result = TocTree(self).resolve(docname,
                                           builder,
                                           toctreenode,
                                           prune=prune_toctrees,
                                           includehidden=includehidden)
            if result is None:
                toctreenode.replace_self([])
            else:
                toctreenode.replace_self(result)

        return doctree
Esempio n. 3
0
def inline_all_toctrees(builder: "Builder", docnameset: Set[str], docname: str,
                        tree: nodes.document, colorfunc: Callable, traversed: List[str]
                        ) -> nodes.document:
    """Inline all toctrees in the *tree*.

    Record all docnames in *docnameset*, and output docnames with *colorfunc*.
    """
    tree = cast(nodes.document, tree.deepcopy())
    for toctreenode in list(tree.findall(addnodes.toctree)):
        newnodes = []
        includefiles = map(str, toctreenode['includefiles'])
        for includefile in includefiles:
            if includefile not in traversed:
                try:
                    traversed.append(includefile)
                    logger.info(colorfunc(includefile) + " ", nonl=True)
                    subtree = inline_all_toctrees(builder, docnameset, includefile,
                                                  builder.env.get_doctree(includefile),
                                                  colorfunc, traversed)
                    docnameset.add(includefile)
                except Exception:
                    logger.warning(__('toctree contains ref to nonexisting file %r'),
                                   includefile, location=docname)
                else:
                    sof = addnodes.start_of_file(docname=includefile)
                    sof.children = subtree.children
                    for sectionnode in sof.findall(nodes.section):
                        if 'docname' not in sectionnode:
                            sectionnode['docname'] = includefile
                    newnodes.append(sof)
        toctreenode.parent.replace(toctreenode, newnodes)
    return tree
Esempio n. 4
0
    def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
        """Process and rewrite image URIs."""
        docname = app.env.docname

        for node in doctree.findall(nodes.image):
            # Map the mimetype to the corresponding image.  The writer may
            # choose the best image from these candidates.  The special key * is
            # set if there is only single candidate to be used by a writer.
            # The special key ? is set for nonlocal URIs.
            candidates: Dict[str, str] = {}
            node['candidates'] = candidates
            imguri = node['uri']
            if imguri.startswith('data:'):
                candidates['?'] = imguri
                continue
            elif imguri.find('://') != -1:
                candidates['?'] = imguri
                continue

            if imguri.endswith(os.extsep + '*'):
                # Update `node['uri']` to a relative path from srcdir
                # from a relative path from current document.
                rel_imgpath, full_imgpath = app.env.relfn2path(imguri, docname)
                node['uri'] = rel_imgpath

                if app.config.language:
                    # Search language-specific figures at first
                    i18n_imguri = get_image_filename_for_language(
                        imguri, app.env)
                    _, full_i18n_imgpath = app.env.relfn2path(
                        i18n_imguri, docname)
                    self.collect_candidates(app.env, full_i18n_imgpath,
                                            candidates, node)

                self.collect_candidates(app.env, full_imgpath, candidates,
                                        node)
            else:
                if app.config.language:
                    # substitute imguri by figure_language_filename
                    # (ex. foo.png -> foo.en.png)
                    imguri = search_image_for_language(imguri, app.env)

                # Update `node['uri']` to a relative path from srcdir
                # from a relative path from current document.
                node['uri'], _ = app.env.relfn2path(imguri, docname)
                candidates['*'] = node['uri']

            # map image paths to unique image names (so that they can be put
            # into a single directory)
            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')
                    continue
                app.env.images.add_file(docname, imgpath)
Esempio n. 5
0
    def process_doc(self, env: BuildEnvironment, docname: str,
                    document: nodes.document) -> None:
        todos = self.todos.setdefault(docname, [])
        for todo in document.findall(todo_node):
            env.app.emit('todo-defined', todo)
            todos.append(todo)

            if env.config.todo_emit_warnings:
                logger.warning(__("TODO entry found: %s"), todo[1].astext(),
                               location=todo)
Esempio n. 6
0
        def footnote_spot(tree: nodes.document) -> Tuple[Element, int]:
            """Find or create a spot to place footnotes.

            The function returns the tuple (parent, index)."""
            # The code uses the following heuristic:
            # a) place them after the last existing footnote
            # b) place them after an (empty) Footnotes rubric
            # c) create an empty Footnotes rubric at the end of the document
            fns = list(tree.findall(nodes.footnote))
            if fns:
                fn = fns[-1]
                return fn.parent, fn.parent.index(fn) + 1
            for node in tree.findall(nodes.rubric):
                if len(node) == 1 and node.astext() == FOOTNOTES_RUBRIC_NAME:
                    return node.parent, node.parent.index(node) + 1
            doc = next(tree.findall(nodes.document))
            rub = nodes.rubric()
            rub.append(nodes.Text(FOOTNOTES_RUBRIC_NAME))
            doc.append(rub)
            return doc, doc.index(rub) + 1
Esempio n. 7
0
 def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
     """Process downloadable file paths. """
     for node in doctree.findall(addnodes.download_reference):
         targetname = node['reftarget']
         if '://' in targetname:
             node['refuri'] = targetname
         else:
             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')
                 continue
             node['filename'] = app.env.dlfiles.add_file(app.env.docname, rel_filename)
Esempio n. 8
0
def process_ifconfig_nodes(app: Sphinx, doctree: nodes.document, docname: str) -> None:
    ns = {confval.name: confval.value for confval in app.config}
    ns.update(app.config.__dict__.copy())
    ns['builder'] = app.builder.name
    for node in doctree.findall(ifconfig):
        try:
            res = eval(node['expr'], ns)
        except Exception as err:
            # handle exceptions in a clean fashion
            from traceback import format_exception_only
            msg = ''.join(format_exception_only(err.__class__, err))
            newnode = doctree.reporter.error('Exception occurred in '
                                             'ifconfig expression: \n%s' %
                                             msg, base_node=node)
            node.replace_self(newnode)
        else:
            if not res:
                node.replace_self([])
            else:
                node.replace_self(node.children)
Esempio n. 9
0
 def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
     """Add a title node to the document (just copy the first section title),
     and store that title in the environment.
     """
     titlenode = nodes.title()
     longtitlenode = titlenode
     # explicit title set with title directive; use this only for
     # the <title> tag in HTML output
     if 'title' in doctree:
         longtitlenode = nodes.title()
         longtitlenode += nodes.Text(doctree['title'])
     # look for first section title and use that as the title
     for node in doctree.findall(nodes.section):
         visitor = SphinxContentsFilter(doctree)
         node[0].walkabout(visitor)
         titlenode += visitor.get_entry_text()
         break
     else:
         # document has no title
         titlenode += nodes.Text(doctree.get('title', '<no title>'))
     app.env.titles[app.env.docname] = titlenode
     app.env.longtitles[app.env.docname] = longtitlenode
Esempio n. 10
0
    def process(self, doctree: nodes.document, docname: str) -> None:
        todos: List[todo_node] = sum(self.domain.todos.values(), [])
        for node in list(doctree.findall(todolist)):
            if not self.config.todo_include_todos:
                node.parent.remove(node)
                continue

            if node.get('ids'):
                content: List[Element] = [nodes.target()]
            else:
                content = []

            for todo in todos:
                # Create a copy of the todo node
                new_todo = todo.deepcopy()
                new_todo['ids'].clear()

                self.resolve_reference(new_todo, docname)
                content.append(new_todo)

                todo_ref = self.create_todo_reference(todo, docname)
                content.append(todo_ref)

            node.replace_self(content)
Esempio n. 11
0
    def process_doc(self, env: BuildEnvironment, docname: str,
                    document: nodes.document) -> None:
        def math_node(node: Node) -> bool:
            return isinstance(node, (nodes.math, nodes.math_block))

        self.data['has_equations'][docname] = any(document.findall(math_node))
Esempio n. 12
0
    def add_visible_links(self, tree: nodes.document, show_urls: str = 'inline') -> None:
        """Add visible link targets for external links"""

        def make_footnote_ref(doc: nodes.document, label: str) -> nodes.footnote_reference:
            """Create a footnote_reference node with children"""
            footnote_ref = nodes.footnote_reference('[#]_')
            footnote_ref.append(nodes.Text(label))
            doc.note_autofootnote_ref(footnote_ref)
            return footnote_ref

        def make_footnote(doc: nodes.document, label: str, uri: str) -> nodes.footnote:
            """Create a footnote node with children"""
            footnote = nodes.footnote(uri)
            para = nodes.paragraph()
            para.append(nodes.Text(uri))
            footnote.append(para)
            footnote.insert(0, nodes.label('', label))
            doc.note_autofootnote(footnote)
            return footnote

        def footnote_spot(tree: nodes.document) -> Tuple[Element, int]:
            """Find or create a spot to place footnotes.

            The function returns the tuple (parent, index)."""
            # The code uses the following heuristic:
            # a) place them after the last existing footnote
            # b) place them after an (empty) Footnotes rubric
            # c) create an empty Footnotes rubric at the end of the document
            fns = list(tree.findall(nodes.footnote))
            if fns:
                fn = fns[-1]
                return fn.parent, fn.parent.index(fn) + 1
            for node in tree.findall(nodes.rubric):
                if len(node) == 1 and node.astext() == FOOTNOTES_RUBRIC_NAME:
                    return node.parent, node.parent.index(node) + 1
            doc = next(tree.findall(nodes.document))
            rub = nodes.rubric()
            rub.append(nodes.Text(FOOTNOTES_RUBRIC_NAME))
            doc.append(rub)
            return doc, doc.index(rub) + 1

        if show_urls == 'no':
            return
        if show_urls == 'footnote':
            doc = next(tree.findall(nodes.document))
            fn_spot, fn_idx = footnote_spot(tree)
            nr = 1
        for node in list(tree.findall(nodes.reference)):
            uri = node.get('refuri', '')
            if (uri.startswith('http:') or uri.startswith('https:') or
                    uri.startswith('ftp:')) and uri not in node.astext():
                idx = node.parent.index(node) + 1
                if show_urls == 'inline':
                    uri = self.link_target_template % {'uri': uri}
                    link = nodes.inline(uri, uri)
                    link['classes'].append(self.css_link_target_class)
                    node.parent.insert(idx, link)
                elif show_urls == 'footnote':
                    label = FOOTNOTE_LABEL_TEMPLATE % nr
                    nr += 1
                    footnote_ref = make_footnote_ref(doc, label)
                    node.parent.insert(idx, footnote_ref)
                    footnote = make_footnote(doc, label, uri)
                    fn_spot.insert(fn_idx, footnote)
                    footnote_ref['refid'] = footnote['ids'][0]
                    footnote.add_backref(footnote_ref['ids'][0])
                    fn_idx += 1