sphinx-autoapi/autoapi/directives.py

143 lines
4.4 KiB
Python
Raw Normal View History

"""AutoAPI directives"""
2017-08-31 23:42:47 +00:00
import posixpath
import re
from docutils.parsers.rst import Directive, directives
from docutils.statemachine import ViewList
from docutils import nodes
2017-08-31 23:42:47 +00:00
from sphinx import addnodes
import sphinx.ext.autosummary
from sphinx.util.nodes import nested_parse_with_titles
2019-01-27 00:26:39 +00:00
from sphinx.util.rst import escape
2017-08-31 23:42:47 +00:00
2019-10-05 22:11:23 +00:00
class AutoapiSummary(Directive): # pylint: disable=too-few-public-methods
2017-08-31 23:42:47 +00:00
"""A version of autosummary that uses static analysis."""
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
has_content = True
option_spec = {
2019-01-27 05:20:45 +00:00
"toctree": directives.unchanged,
"nosignatures": directives.flag,
"template": directives.unchanged,
2017-08-31 23:42:47 +00:00
}
def _get_names(self):
"""Get the names of the objects to include in the table.
:returns: The names of the objects to include.
:rtype: generator(str)
"""
for line in self.content:
line = line.strip()
2019-01-27 05:20:45 +00:00
if line and re.search("^[a-zA-Z0-9]", line):
2017-08-31 23:42:47 +00:00
yield line
def run(self):
env = self.state.document.settings.env
mapper = env.autoapi_mapper
objects = [mapper.all_objects[name] for name in self._get_names()]
nodes_ = self._get_table(objects)
2019-01-27 05:20:45 +00:00
if "toctree" in self.options:
2017-08-31 23:42:47 +00:00
dirname = posixpath.dirname(env.docname)
2019-01-27 05:20:45 +00:00
tree_prefix = self.options["toctree"].strip()
2017-08-31 23:42:47 +00:00
docnames = []
for obj in objects:
docname = posixpath.join(tree_prefix, obj.name)
docname = posixpath.normpath(posixpath.join(dirname, docname))
if docname not in env.found_docs:
2019-10-05 23:09:26 +00:00
self.reporter.warning(
"toctree references unknown document {}".format(docname)
)
2017-08-31 23:42:47 +00:00
docnames.append(docname)
tocnode = addnodes.toctree()
2019-01-27 05:20:45 +00:00
tocnode["includefiles"] = docnames
tocnode["entries"] = [(None, docn) for docn in docnames]
tocnode["maxdepth"] = -1
tocnode["glob"] = None
2017-08-31 23:42:47 +00:00
2019-01-27 05:20:45 +00:00
tocnode = sphinx.ext.autosummary.autosummary_toc("", "", tocnode)
2017-08-31 23:42:47 +00:00
nodes_.append(tocnode)
2019-10-05 22:11:23 +00:00
return nodes_
2017-08-31 23:42:47 +00:00
def _get_row(self, obj):
2019-01-27 05:20:45 +00:00
template = ":{}:`{} <{}>`\\ {}"
if "nosignatures" in self.options:
template = ":{}:`{} <{}>`"
2017-08-31 23:42:47 +00:00
col1 = template.format(
2019-01-27 05:20:45 +00:00
"obj", obj.short_name, obj.name, escape("({})".format(obj.args))
2017-08-31 23:42:47 +00:00
)
col2 = obj.summary
2019-01-27 05:20:45 +00:00
row = nodes.row("")
2017-08-31 23:42:47 +00:00
for text in (col1, col2):
2019-01-27 05:20:45 +00:00
node = nodes.paragraph("")
2017-08-31 23:42:47 +00:00
view_list = ViewList()
2019-01-27 05:20:45 +00:00
view_list.append(text, "<autosummary>")
2017-08-31 23:42:47 +00:00
self.state.nested_parse(view_list, 0, node)
try:
if isinstance(node[0], nodes.paragraph):
node = node[0]
except IndexError:
pass
2019-01-27 05:20:45 +00:00
row.append(nodes.entry("", node))
2017-08-31 23:42:47 +00:00
return row
def _get_table(self, objects):
table_spec = addnodes.tabular_col_spec()
2019-01-27 05:20:45 +00:00
table_spec["spec"] = r"p{0.5\linewidth}p{0.5\linewidth}"
2017-08-31 23:42:47 +00:00
2019-01-27 05:20:45 +00:00
table = sphinx.ext.autosummary.autosummary_table("")
real_table = nodes.table("", classes=["longtable"])
2017-08-31 23:42:47 +00:00
table.append(real_table)
2019-01-27 05:20:45 +00:00
group = nodes.tgroup("", cols=2)
2017-08-31 23:42:47 +00:00
real_table.append(group)
2019-01-27 05:20:45 +00:00
group.append(nodes.colspec("", colwidth=10))
group.append(nodes.colspec("", colwidth=90))
body = nodes.tbody("")
2017-08-31 23:42:47 +00:00
group.append(body)
for obj in objects:
body.append(self._get_row(obj))
return [table_spec, table]
2019-10-05 22:11:23 +00:00
class NestedParse(Directive): # pylint: disable=too-few-public-methods
"""Nested parsing to remove the first heading of included rST
This is used to handle the case where we like to remove user supplied
headings from module docstrings. This is required to reduce the number of
duplicate headings on sections.
"""
has_content = 1
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
def run(self):
node = nodes.paragraph()
node.document = self.state.document
nested_parse_with_titles(self.state, self.content, node)
try:
title_node = node[0][0]
if isinstance(title_node, nodes.title):
del node[0][0]
except IndexError:
pass
return [node]