You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
9.2 KiB
284 lines
9.2 KiB
from __future__ import division, absolute_import, print_function |
|
|
|
import sys, re, inspect, textwrap, pydoc |
|
import sphinx |
|
import collections |
|
from .docscrape import NumpyDocString, FunctionDoc, ClassDoc |
|
|
|
if sys.version_info[0] >= 3: |
|
sixu = lambda s: s |
|
else: |
|
sixu = lambda s: unicode(s, "unicode_escape") |
|
|
|
|
|
class SphinxDocString(NumpyDocString): |
|
def __init__(self, docstring, config={}): |
|
NumpyDocString.__init__(self, docstring, config=config) |
|
self.load_config(config) |
|
|
|
def load_config(self, config): |
|
self.use_plots = config.get("use_plots", False) |
|
self.class_members_toctree = config.get("class_members_toctree", True) |
|
|
|
# string conversion routines |
|
def _str_header(self, name, symbol="`"): |
|
return [".. rubric:: " + name, ""] |
|
|
|
def _str_field_list(self, name): |
|
return [":" + name + ":"] |
|
|
|
def _str_indent(self, doc, indent=4): |
|
out = [] |
|
for line in doc: |
|
out += [" " * indent + line] |
|
return out |
|
|
|
def _str_signature(self): |
|
return [""] |
|
if self["Signature"]: |
|
return ["``%s``" % self["Signature"]] + [""] |
|
else: |
|
return [""] |
|
|
|
def _str_summary(self): |
|
return self["Summary"] + [""] |
|
|
|
def _str_extended_summary(self): |
|
return self["Extended Summary"] + [""] |
|
|
|
def _str_returns(self): |
|
out = [] |
|
if self["Returns"]: |
|
out += self._str_field_list("Returns") |
|
out += [""] |
|
for param, param_type, desc in self["Returns"]: |
|
if param_type: |
|
out += self._str_indent( |
|
["**%s** : %s" % (param.strip(), param_type)] |
|
) |
|
else: |
|
out += self._str_indent([param.strip()]) |
|
if desc: |
|
out += [""] |
|
out += self._str_indent(desc, 8) |
|
out += [""] |
|
return out |
|
|
|
def _str_param_list(self, name): |
|
out = [] |
|
if self[name]: |
|
out += self._str_field_list(name) |
|
out += [""] |
|
for param, param_type, desc in self[name]: |
|
if param_type: |
|
out += self._str_indent( |
|
["**%s** : %s" % (param.strip(), param_type)] |
|
) |
|
else: |
|
out += self._str_indent(["**%s**" % param.strip()]) |
|
if desc: |
|
out += [""] |
|
out += self._str_indent(desc, 8) |
|
out += [""] |
|
return out |
|
|
|
@property |
|
def _obj(self): |
|
if hasattr(self, "_cls"): |
|
return self._cls |
|
elif hasattr(self, "_f"): |
|
return self._f |
|
return None |
|
|
|
def _str_member_list(self, name): |
|
""" |
|
Generate a member listing, autosummary:: table where possible, |
|
and a table where not. |
|
|
|
""" |
|
out = [] |
|
if self[name]: |
|
out += [".. rubric:: %s" % name, ""] |
|
prefix = getattr(self, "_name", "") |
|
|
|
if prefix: |
|
prefix = "~%s." % prefix |
|
|
|
autosum = [] |
|
others = [] |
|
for param, param_type, desc in self[name]: |
|
param = param.strip() |
|
|
|
# Check if the referenced member can have a docstring or not |
|
param_obj = getattr(self._obj, param, None) |
|
if not ( |
|
callable(param_obj) |
|
or isinstance(param_obj, property) |
|
or inspect.isgetsetdescriptor(param_obj) |
|
): |
|
param_obj = None |
|
|
|
if param_obj and (pydoc.getdoc(param_obj) or not desc): |
|
# Referenced object has a docstring |
|
autosum += [" %s%s" % (prefix, param)] |
|
else: |
|
others.append((param, param_type, desc)) |
|
|
|
if autosum: |
|
out += [".. autosummary::"] |
|
if self.class_members_toctree: |
|
out += [" :toctree:"] |
|
out += [""] + autosum |
|
|
|
if others: |
|
maxlen_0 = max(3, max([len(x[0]) for x in others])) |
|
hdr = sixu("=") * maxlen_0 + sixu(" ") + sixu("=") * 10 |
|
fmt = sixu("%%%ds %%s ") % (maxlen_0,) |
|
out += ["", hdr] |
|
for param, param_type, desc in others: |
|
desc = sixu(" ").join(x.strip() for x in desc).strip() |
|
if param_type: |
|
desc = "(%s) %s" % (param_type, desc) |
|
out += [fmt % (param.strip(), desc)] |
|
out += [hdr] |
|
out += [""] |
|
return out |
|
|
|
def _str_section(self, name): |
|
out = [] |
|
if self[name]: |
|
out += self._str_header(name) |
|
out += [""] |
|
content = textwrap.dedent("\n".join(self[name])).split("\n") |
|
out += content |
|
out += [""] |
|
return out |
|
|
|
def _str_see_also(self, func_role): |
|
out = [] |
|
if self["See Also"]: |
|
see_also = super(SphinxDocString, self)._str_see_also(func_role) |
|
out = [".. seealso::", ""] |
|
out += self._str_indent(see_also[2:]) |
|
return out |
|
|
|
def _str_warnings(self): |
|
out = [] |
|
if self["Warnings"]: |
|
out = [".. warning::", ""] |
|
out += self._str_indent(self["Warnings"]) |
|
return out |
|
|
|
def _str_index(self): |
|
idx = self["index"] |
|
out = [] |
|
if len(idx) == 0: |
|
return out |
|
|
|
out += [".. index:: %s" % idx.get("default", "")] |
|
for section, references in idx.items(): |
|
if section == "default": |
|
continue |
|
elif section == "refguide": |
|
out += [" single: %s" % (", ".join(references))] |
|
else: |
|
out += [" %s: %s" % (section, ",".join(references))] |
|
return out |
|
|
|
def _str_references(self): |
|
out = [] |
|
if self["References"]: |
|
out += self._str_header("References") |
|
if isinstance(self["References"], str): |
|
self["References"] = [self["References"]] |
|
out.extend(self["References"]) |
|
out += [""] |
|
# Latex collects all references to a separate bibliography, |
|
# so we need to insert links to it |
|
if sphinx.__version__ >= "0.6": |
|
out += [".. only:: latex", ""] |
|
else: |
|
out += [".. latexonly::", ""] |
|
items = [] |
|
for line in self["References"]: |
|
m = re.match(r".. \[([a-z0-9._-]+)\]", line, re.I) |
|
if m: |
|
items.append(m.group(1)) |
|
out += [" " + ", ".join(["[%s]_" % item for item in items]), ""] |
|
return out |
|
|
|
def _str_examples(self): |
|
examples_str = "\n".join(self["Examples"]) |
|
|
|
if ( |
|
self.use_plots |
|
and "import matplotlib" in examples_str |
|
and "plot::" not in examples_str |
|
): |
|
out = [] |
|
out += self._str_header("Examples") |
|
out += [".. plot::", ""] |
|
out += self._str_indent(self["Examples"]) |
|
out += [""] |
|
return out |
|
else: |
|
return self._str_section("Examples") |
|
|
|
def __str__(self, indent=0, func_role="obj"): |
|
out = [] |
|
out += self._str_signature() |
|
out += self._str_index() + [""] |
|
out += self._str_summary() |
|
out += self._str_extended_summary() |
|
out += self._str_param_list("Parameters") |
|
out += self._str_returns() |
|
for param_list in ("Other Parameters", "Raises", "Warns"): |
|
out += self._str_param_list(param_list) |
|
out += self._str_warnings() |
|
out += self._str_see_also(func_role) |
|
out += self._str_section("Notes") |
|
out += self._str_references() |
|
out += self._str_examples() |
|
for param_list in ("Attributes", "Methods"): |
|
out += self._str_member_list(param_list) |
|
out = self._str_indent(out, indent) |
|
return "\n".join(out) |
|
|
|
|
|
class SphinxFunctionDoc(SphinxDocString, FunctionDoc): |
|
def __init__(self, obj, doc=None, config={}): |
|
self.load_config(config) |
|
FunctionDoc.__init__(self, obj, doc=doc, config=config) |
|
|
|
|
|
class SphinxClassDoc(SphinxDocString, ClassDoc): |
|
def __init__(self, obj, doc=None, func_doc=None, config={}): |
|
self.load_config(config) |
|
ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) |
|
|
|
|
|
class SphinxObjDoc(SphinxDocString): |
|
def __init__(self, obj, doc=None, config={}): |
|
self._f = obj |
|
self.load_config(config) |
|
SphinxDocString.__init__(self, doc, config=config) |
|
|
|
|
|
def get_doc_object(obj, what=None, doc=None, config={}): |
|
if what is None: |
|
if inspect.isclass(obj): |
|
what = "class" |
|
elif inspect.ismodule(obj): |
|
what = "module" |
|
elif isinstance(obj, collections.Callable): |
|
what = "function" |
|
else: |
|
what = "object" |
|
if what == "class": |
|
return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, config=config) |
|
elif what in ("function", "method"): |
|
return SphinxFunctionDoc(obj, doc=doc, config=config) |
|
else: |
|
if doc is None: |
|
doc = pydoc.getdoc(obj) |
|
return SphinxObjDoc(obj, doc, config=config)
|
|
|