Ejemplo n.º 1
0
 def attrs(self) -> Iterator["ResolvedNode[Node]"]:
     if isinstance(self.node, Module):
         module_name = dot_join(self.module.name if self.module else None,
                                self.name)
         for attr, node in self.node.attrs.items():
             yield ResolvedNode(BoundNode(module_name, self.node), None,
                                attr, node)
     elif isinstance(self.node, Class):
         class_name = dot_join(self.class_.name if self.class_ else None,
                               self.name)
         for attr, node in self.node.attrs.items():
             yield ResolvedNode(self.module,
                                BoundNode(class_name,
                                          self.node), attr, node)
Ejemplo n.º 2
0
 def aux(resolved: ResolvedNode[Node], name: str) -> None:
     node = resolved.node
     if hasattr(node, "docstring"):
         var_name = name.replace(".", "_") + "_DOC"
         if args.header:
             output_file.write("extern ")
         output_file.write(f"const char {var_name}[]")
         if not args.header:
             output_file.write(" =")
             signature, lines = formatter.format(cast(
                 ResolvedNode[DocumentedNode], resolved),
                                                 rst=False)
             if signature:
                 lines[0:0] = [
                     name.rpartition(".")[2] + signature,
                     "",
                 ]
             if lines:
                 for i, line in enumerate(lines):
                     output_file.write(f'\n\t"{escape_string(line)}')
                     if i != len(lines) - 1:
                         output_file.write("\\n")
                     output_file.write('"')
             else:
                 output_file.write(' ""')
         output_file.write(";\n")
         if args.header:
             output_file.write(f"#define {var_name} (char *){var_name}\n")
     for attr in resolved.attrs():
         if isinstance(node, Class) and attr.name == "__init__":
             continue
         aux(attr, dot_join(name, attr.name))
Ejemplo n.º 3
0
 def attr(self, attr: str) -> "ResolvedNode[Node]":
     if isinstance(self.node, Module):
         module_name = dot_join(self.module.name if self.module else None,
                                self.name)
         return ResolvedNode(BoundNode(module_name, self.node), None, attr,
                             self.node.attrs[attr])
     elif isinstance(self.node, Class):
         class_name = dot_join(self.class_.name if self.class_ else None,
                               self.name)
         return ResolvedNode(
             self.module,
             BoundNode(class_name, self.node),
             attr,
             self.node.attrs[attr],
         )
     else:
         raise KeyError(attr)
Ejemplo n.º 4
0
Archivo: ext.py Proyecto: pzakha/drgn
    def _run_module(
        self,
        top_name: str,
        attr_name: str,
        resolved: ResolvedNode[Module],
        docnode: docutils.nodes.Node,
    ) -> None:
        node = resolved.node
        if node.docstring is None:
            # Not documented. Ignore it.
            return

        sourcename = node.path or ""
        if sourcename:
            self.env.note_dependency(sourcename)
        contents = docutils.statemachine.StringList(
            node.docstring.splitlines(), sourcename
        )

        sphinx.util.nodes.nested_parse_with_titles(self.state, contents, docnode)

        # If the module docstring defines any sections, then the contents
        # should go inside of the last one.
        section = docnode
        for child in reversed(docnode.children):
            if isinstance(child, docutils.nodes.section):
                section = child
                break

        try:
            old_py_module = self.env.ref_context["py:module"]
            have_old_py_module = True
        except KeyError:
            have_old_py_module = False
        self.env.ref_context["py:module"] = dot_join(top_name, attr_name)
        for attr in resolved.attrs():
            self._run(
                top_name, dot_join(attr_name, attr.name), attr.name, attr, section
            )
        if have_old_py_module:
            self.env.ref_context["py:module"] = old_py_module
        else:
            del self.env.ref_context["py:module"]
Ejemplo n.º 5
0
    def _run(
        self,
        top_name: str,
        attr_name: str,
        name: str,
        resolved: ResolvedNode[Node],
        docnode: docutils.nodes.Node,
    ) -> None:
        exclude_pattern = self.options.get("exclude")
        if exclude_pattern is not None and re.fullmatch(
                exclude_pattern, attr_name):
            return

        if isinstance(resolved.node, (Import, ImportFrom)):
            # Only include imports that are explicitly aliased (i.e., import
            # ... as ... or from ... import ... as ...).
            # TODO: we should also include imports listed in __all__.
            if not resolved.node.aliased:
                return
            imported = self.env.drgndoc_namespace.resolve_name_in_scope(
                resolved.modules, resolved.classes, resolved.name)
            if not isinstance(imported, ResolvedNode):
                return
            resolved = imported

        resolved = cast(ResolvedNode[DocumentedNode], resolved)

        if isinstance(resolved.node, Module):
            return self._run_module(top_name, attr_name,
                                    cast(ResolvedNode[Module], resolved),
                                    docnode)

        lines = self.env.drgndoc_formatter.format(
            resolved,
            name,
            self.env.ref_context.get("py:module", ""),
            ".".join(self.env.ref_context.get("py:classes", ())),
        )
        if not lines:
            # Not documented. Ignore it.
            return

        sourcename = ""
        if resolved.modules and resolved.modules[-1].node.path:
            sourcename = resolved.modules[-1].node.path
        if sourcename:
            self.env.note_dependency(sourcename)
        contents = docutils.statemachine.StringList(lines, sourcename)
        contents.append("", sourcename)

        self.state.nested_parse(contents, 0, docnode)
        if isinstance(resolved.node, Class):
            for desc in reversed(docnode.children):
                if isinstance(desc, sphinx.addnodes.desc):
                    break
            else:
                logger.warning("desc node not found")
                return
            for desc_content in reversed(desc.children):
                if isinstance(desc_content, sphinx.addnodes.desc_content):
                    break
            else:
                logger.warning("desc_content node not found")
                return

            py_classes = self.env.ref_context.setdefault("py:classes", [])
            py_classes.append(resolved.name)
            self.env.ref_context["py:class"] = resolved.name
            for member in resolved.attrs():
                if member.name != "__init__":
                    self._run(
                        top_name,
                        dot_join(attr_name, member.name),
                        member.name,
                        member,
                        desc_content,
                    )
            py_classes.pop()
            self.env.ref_context[
                "py:class"] = py_classes[-1] if py_classes else None
Ejemplo n.º 6
0
Archivo: ext.py Proyecto: zeta1999/drgn
    def _run(
        self,
        top_name: str,
        attr_name: str,
        resolved: ResolvedNode[Node],
        docnode: docutils.nodes.Node,
    ) -> None:
        if not self._include_attr(resolved, attr_name):
            return
        resolved = cast(ResolvedNode[DocumentedNode], resolved)

        node = resolved.node
        if isinstance(node, Module):
            directive = "py:module"
            return self._run_module(
                top_name, attr_name, cast(ResolvedNode[Module], resolved), docnode
            )

        sourcename = ""
        if resolved.module and resolved.module.node.path:
            sourcename = resolved.module.node.path
        if sourcename:
            self.env.note_dependency(sourcename)

        if isinstance(node, Class):
            directive = "py:class"
        elif isinstance(node, Function):
            directive = "py:method" if resolved.class_ else "py:function"
        elif isinstance(node, Variable):
            directive = "py:attribute" if resolved.class_ else "py:data"
        else:
            assert False, type(node).__name__

        argument = (attr_name or top_name).rpartition(".")[2]
        extra_argument, lines = self.env.drgndoc_formatter.format(
            resolved,
            self.env.ref_context.get("py:module", ""),
            ".".join(self.env.ref_context.get("py:classes", ())),
        )

        contents = docutils.statemachine.StringList()
        contents.append(
            f".. {directive}:: {argument}{extra_argument}", sourcename,
        )
        if isinstance(node, Function):
            if node.async_:
                contents.append("    :async:", sourcename)
            if resolved.class_:
                if node.have_decorator("classmethod"):
                    contents.append("    :classmethod:", sourcename)
                if node.have_decorator("staticmethod"):
                    contents.append("    :staticmethod:", sourcename)
        contents.append("", sourcename)
        if lines:
            for line in lines:
                contents.append("    " + line, sourcename)
            contents.append("", sourcename)

        self.state.nested_parse(contents, 0, docnode)
        if isinstance(node, Class):
            for desc in reversed(docnode.children):
                if isinstance(desc, sphinx.addnodes.desc):
                    break
            else:
                logger.warning("desc node not found")
                return
            for desc_content in reversed(desc.children):
                if isinstance(desc_content, sphinx.addnodes.desc_content):
                    break
            else:
                logger.warning("desc_content node not found")
                return

            py_classes = self.env.ref_context.setdefault("py:classes", [])
            py_classes.append(resolved.name)
            self.env.ref_context["py:class"] = resolved.name
            for member in resolved.attrs():
                self._run(
                    top_name, dot_join(attr_name, member.name), member, desc_content
                )
            py_classes.pop()
            self.env.ref_context["py:class"] = py_classes[-1] if py_classes else None
Ejemplo n.º 7
0
 def qualified_name(self) -> str:
     return dot_join(
         self.module.name if self.module else None,
         self.class_.name if self.class_ else None,
         self.name,
     )