mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
merge with pv/sphinx-work
This commit is contained in:
commit
b13f61bc42
@ -6,7 +6,8 @@ import sys, os, re
|
|||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.addons.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo']
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
||||||
|
'sphinx.ext.autosummary']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
@ -6,4 +6,103 @@
|
|||||||
.. module:: sphinx.ext.autosummary
|
.. module:: sphinx.ext.autosummary
|
||||||
:synopsis: Generate autodoc summaries
|
:synopsis: Generate autodoc summaries
|
||||||
|
|
||||||
TBW.
|
.. versionadded: 0.6
|
||||||
|
|
||||||
|
This extension generates function/method/attribute summary lists,
|
||||||
|
similar to those output eg. by Epydoc and other API doc generation
|
||||||
|
tools. This is especially useful when your docstrings are long and
|
||||||
|
detailed, and putting each one of them on a separate page makes
|
||||||
|
them easier to read.
|
||||||
|
|
||||||
|
The :mod:`sphinx.ext.autosummary` extension does this in two parts:
|
||||||
|
|
||||||
|
1. There is an :dir:`autosummary` directive for generating summary
|
||||||
|
listings that contain links to the documented items, and short
|
||||||
|
summary blurbs extracted from their docstrings.
|
||||||
|
|
||||||
|
2. The convenience script :program:`sphinx-autogen` can be used to
|
||||||
|
generate short "stub" files for the entries listed in the
|
||||||
|
:dir:`autosummary` directives. These by default contain only the
|
||||||
|
corresponding :mod:`sphinx.ext.autodoc` directive.
|
||||||
|
|
||||||
|
.. directive:: autosummary
|
||||||
|
|
||||||
|
Insert a table that contains links to documented items, and a short
|
||||||
|
summary blurb (the first sentence of the docstring) for each of them.
|
||||||
|
The :dir:`autosummary` directive can also optionally serve as
|
||||||
|
a :dir:`toctree` entry for the included items.
|
||||||
|
|
||||||
|
For example,::
|
||||||
|
|
||||||
|
.. currentmodule:: sphinx
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
|
||||||
|
environment.BuildEnvironment
|
||||||
|
util.relative_uri
|
||||||
|
|
||||||
|
produces a table like this:
|
||||||
|
|
||||||
|
.. currentmodule:: sphinx
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
|
||||||
|
environment.BuildEnvironment
|
||||||
|
util.relative_uri
|
||||||
|
|
||||||
|
.. currentmodule:: sphinx.ext.autosummary
|
||||||
|
|
||||||
|
Autosummary preprocesses the docstrings and signatures with the same
|
||||||
|
:event:`autodoc-process-docstring` and
|
||||||
|
:event:`autodoc-process-signature` hooks as *autodoc*.
|
||||||
|
|
||||||
|
|
||||||
|
**Options**
|
||||||
|
|
||||||
|
* If you want the :dir:`autosummary` table to also serve as a
|
||||||
|
:dir:`toctree` entry, use the ``toctree`` option, for example::
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:toctree: DIRNAME
|
||||||
|
|
||||||
|
sphinx.environment.BuildEnvironment
|
||||||
|
sphinx.util.relative_uri
|
||||||
|
|
||||||
|
The ``toctree`` option also signals to the :program:`sphinx-autogen`
|
||||||
|
script that stub pages should be generated for the entries listed
|
||||||
|
in this directive. The option accepts a directory name as an
|
||||||
|
argument; :program:`sphinx-autogen` will by default place its output
|
||||||
|
in this directory.
|
||||||
|
|
||||||
|
* If you don't want the :dir:`autosummary` to show function signatures
|
||||||
|
in the listing, include the ``nosignatures`` option::
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
sphinx.environment.BuildEnvironment
|
||||||
|
sphinx.util.relative_uri
|
||||||
|
|
||||||
|
:program:`sphinx-autogen` -- generate autodoc stub pages
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
The :program:`sphinx-autogen` script can be used to conveniently
|
||||||
|
generate stub documentation pages for items included in
|
||||||
|
:dir:`autosummary` listings.
|
||||||
|
|
||||||
|
For example, the command::
|
||||||
|
|
||||||
|
$ sphinx-autogen -o generated *.rst
|
||||||
|
|
||||||
|
will read all :dir:`autosummary` tables in the :file:`*.rst` files
|
||||||
|
that have the ``:toctree:`` option set, and output corresponding stub
|
||||||
|
pages in directory ``generated`` for all documented items.
|
||||||
|
The generated pages by default contain text of the form::
|
||||||
|
|
||||||
|
sphinx.util.relative_uri
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. autofunction:: sphinx.util.relative_uri
|
||||||
|
|
||||||
|
If the ``-o`` option is not given, the script will place the output
|
||||||
|
files to the directories specified in the ``:toctree:`` options.
|
||||||
|
@ -372,8 +372,7 @@ class Documenter(object):
|
|||||||
else:
|
else:
|
||||||
# try to introspect the signature
|
# try to introspect the signature
|
||||||
args = self.format_args()
|
args = self.format_args()
|
||||||
if args is None:
|
|
||||||
return ''
|
|
||||||
retann = self.retann
|
retann = self.retann
|
||||||
|
|
||||||
result = self.env.app.emit_firstresult(
|
result = self.env.app.emit_firstresult(
|
||||||
|
@ -108,6 +108,29 @@ def autosummary_toc_visit_latex(self, node):
|
|||||||
def autosummary_noop(self, node):
|
def autosummary_noop(self, node):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# -- autodoc integration -------------------------------------------------------
|
||||||
|
|
||||||
|
def get_documenter(obj):
|
||||||
|
"""
|
||||||
|
Get an autodoc.Documenter class suitable for documenting the given object
|
||||||
|
"""
|
||||||
|
import sphinx.ext.autodoc as autodoc
|
||||||
|
|
||||||
|
if inspect.isclass(obj):
|
||||||
|
if issubclass(obj, Exception):
|
||||||
|
return autodoc.ExceptionDocumenter
|
||||||
|
return autodoc.ClassDocumenter
|
||||||
|
elif inspect.ismodule(obj):
|
||||||
|
return autodoc.ModuleDocumenter
|
||||||
|
elif inspect.ismethod(obj) or inspect.ismethoddescriptor(obj):
|
||||||
|
return autodoc.MethodDocumenter
|
||||||
|
elif (inspect.ismemberdescriptor(obj) or inspect.isgetsetdescriptor(obj)
|
||||||
|
or inspect.isdatadescriptor(obj)):
|
||||||
|
return autodoc.AttributeDocumenter
|
||||||
|
elif inspect.isroutine(obj):
|
||||||
|
return autodoc.FunctionDocumenter
|
||||||
|
else:
|
||||||
|
return autodoc.DataDocumenter
|
||||||
|
|
||||||
# -- .. autosummary:: ----------------------------------------------------------
|
# -- .. autosummary:: ----------------------------------------------------------
|
||||||
|
|
||||||
@ -127,33 +150,35 @@ class Autosummary(Directive):
|
|||||||
'nosignatures': directives.flag,
|
'nosignatures': directives.flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def warn(self, msg):
|
||||||
|
self.warnings.append(self.state.document.reporter.warning(
|
||||||
|
msg, line=self.lineno))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
names = []
|
self.env = env = self.state.document.settings.env
|
||||||
names += [x.strip() for x in self.content if x.strip()]
|
self.genopt = {}
|
||||||
|
self.warnings = []
|
||||||
|
|
||||||
table, warnings, real_names = get_autosummary(
|
names = [x.strip().split()[0] for x in self.content
|
||||||
names, self.state, 'nosignatures' in self.options)
|
if x.strip() and re.search(r'^[a-zA-Z_]', x.strip()[0])]
|
||||||
node = table
|
items = self.get_items(names)
|
||||||
|
nodes = [self.get_table(items)]
|
||||||
env = self.state.document.settings.env
|
|
||||||
suffix = env.config.source_suffix
|
|
||||||
all_docnames = env.found_docs.copy()
|
|
||||||
dirname = posixpath.dirname(env.docname)
|
|
||||||
|
|
||||||
if 'toctree' in self.options:
|
if 'toctree' in self.options:
|
||||||
|
suffix = env.config.source_suffix
|
||||||
|
all_docnames = env.found_docs.copy()
|
||||||
|
dirname = posixpath.dirname(env.docname)
|
||||||
|
|
||||||
tree_prefix = self.options['toctree'].strip()
|
tree_prefix = self.options['toctree'].strip()
|
||||||
docnames = []
|
docnames = []
|
||||||
for name in names:
|
for name, sig, summary, real_name in items:
|
||||||
name = real_names.get(name, name)
|
docname = posixpath.join(tree_prefix, real_name)
|
||||||
|
|
||||||
docname = posixpath.join(tree_prefix, name)
|
|
||||||
if docname.endswith(suffix):
|
if docname.endswith(suffix):
|
||||||
docname = docname[:-len(suffix)]
|
docname = docname[:-len(suffix)]
|
||||||
docname = posixpath.normpath(posixpath.join(dirname, docname))
|
docname = posixpath.normpath(posixpath.join(dirname, docname))
|
||||||
if docname not in env.found_docs:
|
if docname not in env.found_docs:
|
||||||
warnings.append(self.state.document.reporter.warning(
|
self.warn('toctree references unknown document %r'
|
||||||
'toctree references unknown document %r' % docname,
|
% docname)
|
||||||
line=self.lineno))
|
|
||||||
docnames.append(docname)
|
docnames.append(docname)
|
||||||
|
|
||||||
tocnode = addnodes.toctree()
|
tocnode = addnodes.toctree()
|
||||||
@ -163,63 +188,146 @@ class Autosummary(Directive):
|
|||||||
tocnode['glob'] = None
|
tocnode['glob'] = None
|
||||||
|
|
||||||
tocnode = autosummary_toc('', '', tocnode)
|
tocnode = autosummary_toc('', '', tocnode)
|
||||||
return warnings + [node] + [tocnode]
|
nodes.append(tocnode)
|
||||||
|
|
||||||
|
return self.warnings + nodes
|
||||||
|
|
||||||
|
def get_items(self, names):
|
||||||
|
"""
|
||||||
|
Try to import the given names, and return a list of
|
||||||
|
``[(name, signature, summary_string, real_name), ...]``
|
||||||
|
|
||||||
|
"""
|
||||||
|
prefixes = ['']
|
||||||
|
prefixes.insert(0, self.state.document.settings.env.currmodule)
|
||||||
|
|
||||||
|
items = []
|
||||||
|
|
||||||
|
for name in names:
|
||||||
|
try:
|
||||||
|
obj, real_name = import_by_name(name, prefixes=prefixes)
|
||||||
|
except ImportError:
|
||||||
|
self.warn('failed to import %s' % name)
|
||||||
|
items.append((name, '', '', name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# NB. using real_name here is important, since Documenters
|
||||||
|
# don't handle module prefixes slightly differently
|
||||||
|
documenter = get_documenter(obj)(self, real_name)
|
||||||
|
if not documenter.parse_name():
|
||||||
|
self.warn('failed to parse name %s' % real_name)
|
||||||
|
items.append((name, '', '', real_name))
|
||||||
|
continue
|
||||||
|
if not documenter.import_object():
|
||||||
|
self.warn('failed to import object %s' % real_name)
|
||||||
|
items.append((name, '', '', real_name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# -- Grab the signature
|
||||||
|
|
||||||
|
sig = documenter.format_signature()
|
||||||
|
if not sig:
|
||||||
|
sig = ''
|
||||||
|
else:
|
||||||
|
sig = mangle_signature(sig).replace('*', r'\*')
|
||||||
|
|
||||||
|
# -- Grab the summary
|
||||||
|
|
||||||
|
doc = list(documenter.process_doc(documenter.get_doc()))
|
||||||
|
|
||||||
|
while doc and not doc[0].strip():
|
||||||
|
doc.pop(0)
|
||||||
|
m = re.search(r"^([A-Z][^A-Z]*?\.\s)", " ".join(doc).strip())
|
||||||
|
if m:
|
||||||
|
summary = m.group(1).strip()
|
||||||
|
elif doc:
|
||||||
|
summary = doc[0].strip()
|
||||||
|
else:
|
||||||
|
summary = ''
|
||||||
|
|
||||||
|
items.append((name, sig, summary, real_name))
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
def get_table(self, items):
|
||||||
|
"""
|
||||||
|
Generate a proper table node for autosummary:: directive.
|
||||||
|
|
||||||
|
*items* is a list produced by :meth:`get_items`
|
||||||
|
|
||||||
|
"""
|
||||||
|
table = nodes.table('')
|
||||||
|
group = nodes.tgroup('', cols=2)
|
||||||
|
table.append(group)
|
||||||
|
group.append(nodes.colspec('', colwidth=10))
|
||||||
|
group.append(nodes.colspec('', colwidth=90))
|
||||||
|
body = nodes.tbody('')
|
||||||
|
group.append(body)
|
||||||
|
|
||||||
|
def append_row(*column_texts):
|
||||||
|
row = nodes.row('')
|
||||||
|
for text in column_texts:
|
||||||
|
node = nodes.paragraph('')
|
||||||
|
vl = ViewList()
|
||||||
|
vl.append(text, '<autosummary>')
|
||||||
|
self.state.nested_parse(vl, 0, node)
|
||||||
|
try:
|
||||||
|
if isinstance(node[0], nodes.paragraph):
|
||||||
|
node = node[0]
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
row.append(nodes.entry('', node))
|
||||||
|
body.append(row)
|
||||||
|
|
||||||
|
for name, sig, summary, real_name in items:
|
||||||
|
qualifier = 'obj'
|
||||||
|
if 'nosignatures' not in self.options:
|
||||||
|
col1 = ':%s:`%s <%s>`\ %s' % (qualifier, name, real_name, sig)
|
||||||
|
else:
|
||||||
|
col1 = ':%s:`%s <%s>`' % (qualifier, name, real_name)
|
||||||
|
col2 = summary
|
||||||
|
append_row(col1, col2)
|
||||||
|
|
||||||
|
return table
|
||||||
|
|
||||||
|
def mangle_signature(sig, max_chars=30):
|
||||||
|
"""
|
||||||
|
Reformat function signature to a more compact form.
|
||||||
|
|
||||||
|
"""
|
||||||
|
sig = re.sub(r"^\((.*)\)$", r"\1", sig) + ", "
|
||||||
|
r = re.compile(r"(?P<name>[a-zA_Z0-9_*]+)(?P<default>=.*?)?, ")
|
||||||
|
items = r.findall(sig)
|
||||||
|
|
||||||
|
args = []
|
||||||
|
opts = []
|
||||||
|
|
||||||
|
total_len = 4
|
||||||
|
for name, default in items:
|
||||||
|
if default:
|
||||||
|
opts.append(name)
|
||||||
else:
|
else:
|
||||||
return warnings + [node]
|
args.append(name)
|
||||||
|
total_len += len(name) + 2
|
||||||
|
|
||||||
|
if total_len > max_chars:
|
||||||
|
if opts:
|
||||||
|
opts.append('...')
|
||||||
|
else:
|
||||||
|
args.append('...')
|
||||||
|
break
|
||||||
|
|
||||||
def get_autosummary(names, state, no_signatures=False):
|
if opts and args:
|
||||||
"""
|
sig = ", ".join(args) + "[, " + ", ".join(opts) + "]"
|
||||||
Generate a proper table node for autosummary:: directive.
|
elif opts and not args:
|
||||||
|
sig = "[" + ", ".join(opts) + "]"
|
||||||
|
else:
|
||||||
|
sig = ", ".join(args)
|
||||||
|
|
||||||
*names* is a list of names of Python objects to be imported and added to the
|
sig = unicode(sig).replace(u" ", u"\u00a0")
|
||||||
table. *document* is the Docutils document object.
|
return u"(%s)" % sig
|
||||||
|
|
||||||
"""
|
# -- Importing items -----------------------------------------------------------
|
||||||
document = state.document
|
|
||||||
|
|
||||||
real_names = {}
|
|
||||||
warnings = []
|
|
||||||
|
|
||||||
prefixes = ['']
|
|
||||||
prefixes.insert(0, document.settings.env.currmodule)
|
|
||||||
|
|
||||||
table = nodes.table('')
|
|
||||||
group = nodes.tgroup('', cols=2)
|
|
||||||
table.append(group)
|
|
||||||
group.append(nodes.colspec('', colwidth=30))
|
|
||||||
group.append(nodes.colspec('', colwidth=70))
|
|
||||||
body = nodes.tbody('')
|
|
||||||
group.append(body)
|
|
||||||
|
|
||||||
def append_row(*column_texts):
|
|
||||||
row = nodes.row('')
|
|
||||||
for text in column_texts:
|
|
||||||
node = nodes.paragraph('')
|
|
||||||
vl = ViewList()
|
|
||||||
vl.append(text, '<autosummary>')
|
|
||||||
state.nested_parse(vl, 0, node)
|
|
||||||
row.append(nodes.entry('', node))
|
|
||||||
body.append(row)
|
|
||||||
|
|
||||||
for name in names:
|
|
||||||
try:
|
|
||||||
obj, real_name = import_by_name(name, prefixes=prefixes)
|
|
||||||
except ImportError:
|
|
||||||
warnings.append(document.reporter.warning(
|
|
||||||
'failed to import %s' % name))
|
|
||||||
append_row(':obj:`%s`' % name, '')
|
|
||||||
continue
|
|
||||||
|
|
||||||
real_names[name] = real_name
|
|
||||||
|
|
||||||
title = ''
|
|
||||||
qualifier = 'obj'
|
|
||||||
col1 = ':'+qualifier+':`%s <%s>`' % (name, real_name)
|
|
||||||
col2 = title
|
|
||||||
append_row(col1, col2)
|
|
||||||
|
|
||||||
return table, warnings, real_names
|
|
||||||
|
|
||||||
def import_by_name(name, prefixes=[None]):
|
def import_by_name(name, prefixes=[None]):
|
||||||
"""
|
"""
|
||||||
|
@ -20,16 +20,31 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import getopt
|
import optparse
|
||||||
import inspect
|
import inspect
|
||||||
|
import pydoc
|
||||||
|
|
||||||
from jinja2 import Environment, PackageLoader
|
from jinja2 import Environment, PackageLoader
|
||||||
|
|
||||||
from sphinx.ext.autosummary import import_by_name
|
from sphinx.ext.autosummary import import_by_name, get_documenter
|
||||||
from sphinx.util import ensuredir
|
from sphinx.util import ensuredir
|
||||||
|
|
||||||
# create our own templating environment, for module template only
|
def main(argv):
|
||||||
env = Environment(loader=PackageLoader('sphinx.ext.autosummary', 'templates'))
|
usage = """%prog [OPTIONS] SOURCEFILE ..."""
|
||||||
|
p = optparse.OptionParser(usage.strip())
|
||||||
|
p.add_option("-o", "--output-dir", action="store", type="string",
|
||||||
|
dest="output_dir", default=None,
|
||||||
|
help="Directory to place all output in")
|
||||||
|
p.add_option("-s", "--suffix", action="store", type="string",
|
||||||
|
dest="suffix", default="rst",
|
||||||
|
help="Default suffix for files (default: %default)")
|
||||||
|
options, args = p.parse_args(argv[1:])
|
||||||
|
|
||||||
|
if len(args) < 1:
|
||||||
|
p.error('no input files given')
|
||||||
|
|
||||||
|
generate_autosummary_docs(args, options.output_dir,
|
||||||
|
"." + options.suffix)
|
||||||
|
|
||||||
|
|
||||||
def _simple_info(msg):
|
def _simple_info(msg):
|
||||||
@ -38,14 +53,22 @@ def _simple_info(msg):
|
|||||||
def _simple_warn(msg):
|
def _simple_warn(msg):
|
||||||
print >>sys.stderr, 'WARNING: ' + msg
|
print >>sys.stderr, 'WARNING: ' + msg
|
||||||
|
|
||||||
def generate_autosummary_docs(sources, output_dir=None, suffix=None,
|
#------------------------------------------------------------------------------
|
||||||
|
# Generating output
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# create our own templating environment, for module template only
|
||||||
|
env = Environment(loader=PackageLoader('sphinx.ext.autosummary', 'templates'))
|
||||||
|
|
||||||
|
def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||||
warn=_simple_warn, info=_simple_info):
|
warn=_simple_warn, info=_simple_info):
|
||||||
info('generating autosummary for: %s' % ', '.join(sources))
|
info('generating autosummary for: %s' % ', '.join(sources))
|
||||||
if output_dir:
|
if output_dir:
|
||||||
info('writing to %s' % output_dir)
|
info('writing to %s' % output_dir)
|
||||||
|
|
||||||
# read
|
# read
|
||||||
names = {}
|
names = {}
|
||||||
for name, loc in get_documented(sources).items():
|
for name, loc in get_documented_in_files(sources).items():
|
||||||
for (filename, sec_title, keyword, toctree) in loc:
|
for (filename, sec_title, keyword, toctree) in loc:
|
||||||
if toctree is not None:
|
if toctree is not None:
|
||||||
path = os.path.join(os.path.dirname(filename), toctree)
|
path = os.path.join(os.path.dirname(filename), toctree)
|
||||||
@ -62,7 +85,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix=None,
|
|||||||
warn('failed to import %r: %s' % (name, e))
|
warn('failed to import %r: %s' % (name, e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
fn = os.path.join(path, name + (suffix or '.rst'))
|
fn = os.path.join(path, name + suffix)
|
||||||
# skip it if it exists
|
# skip it if it exists
|
||||||
if os.path.isfile(fn):
|
if os.path.isfile(fn):
|
||||||
continue
|
continue
|
||||||
@ -73,17 +96,16 @@ def generate_autosummary_docs(sources, output_dir=None, suffix=None,
|
|||||||
if inspect.ismodule(obj):
|
if inspect.ismodule(obj):
|
||||||
# XXX replace this with autodoc's API?
|
# XXX replace this with autodoc's API?
|
||||||
tmpl = env.get_template('module')
|
tmpl = env.get_template('module')
|
||||||
functions = [getattr(obj, item).__name__
|
|
||||||
for item in dir(obj)
|
def get_items(mod, typ):
|
||||||
if inspect.isfunction(getattr(obj, item))]
|
return [getattr(mod, name).__name__
|
||||||
classes = [getattr(obj, item).__name__
|
for name in dir(mod)
|
||||||
for item in dir(obj)
|
if get_documenter(getattr(mod,name)).objtype==typ]
|
||||||
if inspect.isclass(getattr(obj, item))
|
|
||||||
and not issubclass(getattr(obj, item), Exception)]
|
functions = get_items(obj, 'function')
|
||||||
exceptions = [getattr(obj, item).__name__
|
classes = get_items(obj, 'class')
|
||||||
for item in dir(obj)
|
exceptions = get_items(obj, 'exception')
|
||||||
if inspect.isclass(getattr(obj, item))
|
|
||||||
and issubclass(getattr(obj, item), Exception)]
|
|
||||||
rendered = tmpl.render(name=name,
|
rendered = tmpl.render(name=name,
|
||||||
underline='='*len(name),
|
underline='='*len(name),
|
||||||
functions=functions,
|
functions=functions,
|
||||||
@ -96,19 +118,11 @@ def generate_autosummary_docs(sources, output_dir=None, suffix=None,
|
|||||||
else:
|
else:
|
||||||
f.write('%s\n%s\n\n' % (name, '='*len(name)))
|
f.write('%s\n%s\n\n' % (name, '='*len(name)))
|
||||||
|
|
||||||
if inspect.isclass(obj):
|
doc = get_documenter(obj)
|
||||||
if issubclass(obj, Exception):
|
if doc.objtype in ('method', 'attribute'):
|
||||||
f.write(format_modulemember(name, 'autoexception'))
|
f.write(format_classmember(name, 'auto%s' % doc.objtype))
|
||||||
else:
|
|
||||||
f.write(format_modulemember(name, 'autoclass'))
|
|
||||||
elif inspect.ismethod(obj) or inspect.ismethoddescriptor(obj):
|
|
||||||
f.write(format_classmember(name, 'automethod'))
|
|
||||||
elif callable(obj):
|
|
||||||
f.write(format_modulemember(name, 'autofunction'))
|
|
||||||
elif hasattr(obj, '__get__'):
|
|
||||||
f.write(format_classmember(name, 'autoattribute'))
|
|
||||||
else:
|
else:
|
||||||
f.write(format_modulemember(name, 'autofunction'))
|
f.write(format_modulemember(name, 'auto%s' % doc.objtype))
|
||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
@ -125,114 +139,125 @@ def format_classmember(name, directive):
|
|||||||
return '.. currentmodule:: %s\n\n.. %s:: %s\n' % (mod, directive, name)
|
return '.. currentmodule:: %s\n\n.. %s:: %s\n' % (mod, directive, name)
|
||||||
|
|
||||||
|
|
||||||
title_underline_re = re.compile('^[-=*_^#]{3,}\s*$')
|
#------------------------------------------------------------------------------
|
||||||
autodoc_re = re.compile(r'.. auto(function|method|attribute|class|exception'
|
# Finding documented entries in files
|
||||||
'|module)::\s*([A-Za-z0-9_.]+)\s*$')
|
#------------------------------------------------------------------------------
|
||||||
autosummary_re = re.compile(r'^\.\.\s+autosummary::\s*')
|
|
||||||
module_re = re.compile(r'^\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
|
|
||||||
autosummary_item_re = re.compile(r'^\s+([_a-zA-Z][a-zA-Z0-9_.]*)\s*')
|
|
||||||
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
|
||||||
|
|
||||||
def get_documented(filenames):
|
def get_documented_in_files(filenames):
|
||||||
"""
|
"""
|
||||||
Find out what items are documented in the given filenames.
|
Find out what items are documented in source/*.rst
|
||||||
|
See `get_documented_in_lines`.
|
||||||
|
|
||||||
Returns a dict of list of (filename, title, keyword, toctree) Keys are
|
|
||||||
documented names of objects. The value is a list of locations where the
|
|
||||||
object was documented. Each location is a tuple of filename, the current
|
|
||||||
section title, the name of the directive, and the value of the :toctree:
|
|
||||||
argument (if present) of the directive.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
documented = {}
|
documented = {}
|
||||||
|
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
current_title = []
|
|
||||||
last_line = None
|
|
||||||
toctree = None
|
|
||||||
current_module = None
|
|
||||||
in_autosummary = False
|
|
||||||
|
|
||||||
f = open(filename, 'r')
|
f = open(filename, 'r')
|
||||||
for line in f:
|
lines = f.read().splitlines()
|
||||||
try:
|
documented.update(get_documented_in_lines(lines, filename=filename))
|
||||||
if in_autosummary:
|
f.close()
|
||||||
m = toctree_arg_re.match(line)
|
|
||||||
if m:
|
|
||||||
toctree = m.group(1)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if line.strip().startswith(':'):
|
|
||||||
continue # skip options
|
|
||||||
|
|
||||||
m = autosummary_item_re.match(line)
|
|
||||||
|
|
||||||
if m:
|
|
||||||
name = m.group(1).strip()
|
|
||||||
if current_module and \
|
|
||||||
not name.startswith(current_module + '.'):
|
|
||||||
name = '%s.%s' % (current_module, name)
|
|
||||||
documented.setdefault(name, []).append(
|
|
||||||
(filename, current_title, 'autosummary', toctree))
|
|
||||||
continue
|
|
||||||
if line.strip() == '':
|
|
||||||
continue
|
|
||||||
in_autosummary = False
|
|
||||||
|
|
||||||
m = autosummary_re.match(line)
|
|
||||||
if m:
|
|
||||||
in_autosummary = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = autodoc_re.search(line)
|
|
||||||
if m:
|
|
||||||
name = m.group(2).strip()
|
|
||||||
# XXX look in newer generate.py
|
|
||||||
if current_module and \
|
|
||||||
not name.startswith(current_module + '.'):
|
|
||||||
name = '%s.%s' % (current_module, name)
|
|
||||||
if m.group(1) == 'module':
|
|
||||||
current_module = name
|
|
||||||
documented.setdefault(name, []).append(
|
|
||||||
(filename, current_title, 'auto' + m.group(1), None))
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = title_underline_re.match(line)
|
|
||||||
if m and last_line:
|
|
||||||
current_title = last_line.strip()
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = module_re.match(line)
|
|
||||||
if m:
|
|
||||||
current_module = m.group(2)
|
|
||||||
continue
|
|
||||||
finally:
|
|
||||||
last_line = line
|
|
||||||
return documented
|
return documented
|
||||||
|
|
||||||
|
def get_documented_in_docstring(name, module=None, filename=None):
|
||||||
def main(argv):
|
"""
|
||||||
usage = 'usage: %s [-o output_dir] [-s suffix] sourcefile ...' % sys.argv[0]
|
Find out what items are documented in the given object's docstring.
|
||||||
|
See `get_documented_in_lines`.
|
||||||
|
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(argv[1:], 'o:s:')
|
obj, real_name = import_by_name(name)
|
||||||
except getopt.error:
|
lines = pydoc.getdoc(obj).splitlines()
|
||||||
print >>sys.stderr, usage
|
return get_documented_in_lines(lines, module=name, filename=filename)
|
||||||
return 1
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
except ImportError, e:
|
||||||
|
print "Failed to import '%s': %s" % (name, e)
|
||||||
|
return {}
|
||||||
|
|
||||||
output_dir = None
|
def get_documented_in_lines(lines, module=None, filename=None):
|
||||||
suffix = None
|
"""
|
||||||
for opt, val in opts:
|
Find out what items are documented in the given lines
|
||||||
if opt == '-o':
|
|
||||||
output_dir = val
|
Returns
|
||||||
elif opt == '-s':
|
-------
|
||||||
suffix = val
|
documented : dict of list of (filename, title, keyword, toctree)
|
||||||
|
Dictionary whose keys are documented names of objects.
|
||||||
|
The value is a list of locations where the object was documented.
|
||||||
|
Each location is a tuple of filename, the current section title,
|
||||||
|
the name of the directive, and the value of the :toctree: argument
|
||||||
|
(if present) of the directive.
|
||||||
|
|
||||||
if len(args) < 1:
|
"""
|
||||||
print >>sys.stderr, usage
|
title_underline_re = re.compile("^[-=*_^#]{3,}\s*$")
|
||||||
return 1
|
autodoc_re = re.compile(".. auto(function|method|attribute|class|exception|module)::\s*([A-Za-z0-9_.]+)\s*$")
|
||||||
|
autosummary_re = re.compile(r'^\.\.\s+autosummary::\s*')
|
||||||
|
module_re = re.compile(r'^\.\.\s+(current)?module::\s*([a-zA-Z0-9_.]+)\s*$')
|
||||||
|
autosummary_item_re = re.compile(r'^\s+([_a-zA-Z][a-zA-Z0-9_.]*)\s*.*?')
|
||||||
|
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
||||||
|
|
||||||
|
documented = {}
|
||||||
|
|
||||||
|
current_title = []
|
||||||
|
last_line = None
|
||||||
|
toctree = None
|
||||||
|
current_module = module
|
||||||
|
in_autosummary = False
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
try:
|
||||||
|
if in_autosummary:
|
||||||
|
m = toctree_arg_re.match(line)
|
||||||
|
if m:
|
||||||
|
toctree = m.group(1)
|
||||||
|
continue
|
||||||
|
|
||||||
generate_autosummary_docs(args, output_dir, suffix)
|
if line.strip().startswith(':'):
|
||||||
|
continue # skip options
|
||||||
|
|
||||||
|
m = autosummary_item_re.match(line)
|
||||||
|
if m:
|
||||||
|
name = m.group(1).strip()
|
||||||
|
if current_module and not name.startswith(current_module + '.'):
|
||||||
|
name = "%s.%s" % (current_module, name)
|
||||||
|
documented.setdefault(name, []).append(
|
||||||
|
(filename, current_title, 'autosummary', toctree))
|
||||||
|
continue
|
||||||
|
if line.strip() == '':
|
||||||
|
continue
|
||||||
|
in_autosummary = False
|
||||||
|
|
||||||
|
m = autosummary_re.match(line)
|
||||||
|
if m:
|
||||||
|
in_autosummary = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = autodoc_re.search(line)
|
||||||
|
if m:
|
||||||
|
name = m.group(2).strip()
|
||||||
|
if m.group(1) == "module":
|
||||||
|
current_module = name
|
||||||
|
documented.update(get_documented_in_docstring(
|
||||||
|
name, filename=filename))
|
||||||
|
elif current_module and not name.startswith(current_module+'.'):
|
||||||
|
name = "%s.%s" % (current_module, name)
|
||||||
|
documented.setdefault(name, []).append(
|
||||||
|
(filename, current_title, "auto" + m.group(1), None))
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = title_underline_re.match(line)
|
||||||
|
if m and last_line:
|
||||||
|
current_title = last_line.strip()
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = module_re.match(line)
|
||||||
|
if m:
|
||||||
|
current_module = m.group(2)
|
||||||
|
continue
|
||||||
|
finally:
|
||||||
|
last_line = line
|
||||||
|
|
||||||
|
return documented
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main(sys.argv)
|
main()
|
||||||
|
@ -30,6 +30,7 @@ from sphinx.util.smartypants import educateQuotesLatex
|
|||||||
HEADER = r'''%% Generated by Sphinx.
|
HEADER = r'''%% Generated by Sphinx.
|
||||||
\documentclass[%(papersize)s,%(pointsize)s%(classoptions)s]{%(docclass)s}
|
\documentclass[%(papersize)s,%(pointsize)s%(classoptions)s]{%(docclass)s}
|
||||||
%(inputenc)s
|
%(inputenc)s
|
||||||
|
%(utf8extra)s
|
||||||
%(fontenc)s
|
%(fontenc)s
|
||||||
%(babel)s
|
%(babel)s
|
||||||
%(fontpkg)s
|
%(fontpkg)s
|
||||||
@ -136,6 +137,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
'pointsize': '10pt',
|
'pointsize': '10pt',
|
||||||
'classoptions': '',
|
'classoptions': '',
|
||||||
'inputenc': '\\usepackage[utf8]{inputenc}',
|
'inputenc': '\\usepackage[utf8]{inputenc}',
|
||||||
|
'utf8extra': '\\DeclareUnicodeCharacter{00A0}{\\nobreakspace}',
|
||||||
'fontenc': '\\usepackage[T1]{fontenc}',
|
'fontenc': '\\usepackage[T1]{fontenc}',
|
||||||
'babel': '\\usepackage{babel}',
|
'babel': '\\usepackage{babel}',
|
||||||
'fontpkg': '\\usepackage{times}',
|
'fontpkg': '\\usepackage{times}',
|
||||||
|
32
tests/test_autosummary.py
Normal file
32
tests/test_autosummary.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
test_autosummary
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Test the autosummary extension.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
"""
|
||||||
|
import string
|
||||||
|
|
||||||
|
from util import *
|
||||||
|
|
||||||
|
from sphinx.ext.autosummary import mangle_signature
|
||||||
|
|
||||||
|
|
||||||
|
def test_mangle_signature():
|
||||||
|
TEST = """
|
||||||
|
() :: ()
|
||||||
|
(a, b, c, d, e) :: (a, b, c, d, e)
|
||||||
|
(a, b, c=1, d=2, e=3) :: (a, b[, c, d, e])
|
||||||
|
(a, b, aaa=1, bbb=1, ccc=1, eee=1, fff=1, ggg=1, hhh=1, iii=1, jjj=1) :: (a, b[, aaa, bbb, ccc, eee, fff, ...])
|
||||||
|
(a, b, c=(), d=<foo>) :: (a, b[, c, d])
|
||||||
|
(a, b, c='foobar()', d=123) :: (a, b[, c, d])
|
||||||
|
"""
|
||||||
|
|
||||||
|
TEST = [map(string.strip, x.split("::")) for x in TEST.split("\n")
|
||||||
|
if '::' in x]
|
||||||
|
for inp, outp in TEST:
|
||||||
|
res = mangle_signature(inp).strip().replace(u"\u00a0", " ")
|
||||||
|
assert res == outp, (u"'%s' -> '%s' != '%s'" % (inp, res, outp))
|
Loading…
Reference in New Issue
Block a user