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
|
||||
# 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.
|
||||
templates_path = ['_templates']
|
||||
|
@ -6,4 +6,103 @@
|
||||
.. module:: sphinx.ext.autosummary
|
||||
: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:
|
||||
# try to introspect the signature
|
||||
args = self.format_args()
|
||||
if args is None:
|
||||
return ''
|
||||
|
||||
retann = self.retann
|
||||
|
||||
result = self.env.app.emit_firstresult(
|
||||
|
@ -108,6 +108,29 @@ def autosummary_toc_visit_latex(self, node):
|
||||
def autosummary_noop(self, node):
|
||||
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:: ----------------------------------------------------------
|
||||
|
||||
@ -127,33 +150,35 @@ class Autosummary(Directive):
|
||||
'nosignatures': directives.flag,
|
||||
}
|
||||
|
||||
def warn(self, msg):
|
||||
self.warnings.append(self.state.document.reporter.warning(
|
||||
msg, line=self.lineno))
|
||||
|
||||
def run(self):
|
||||
names = []
|
||||
names += [x.strip() for x in self.content if x.strip()]
|
||||
self.env = env = self.state.document.settings.env
|
||||
self.genopt = {}
|
||||
self.warnings = []
|
||||
|
||||
table, warnings, real_names = get_autosummary(
|
||||
names, self.state, 'nosignatures' in self.options)
|
||||
node = table
|
||||
|
||||
env = self.state.document.settings.env
|
||||
suffix = env.config.source_suffix
|
||||
all_docnames = env.found_docs.copy()
|
||||
dirname = posixpath.dirname(env.docname)
|
||||
names = [x.strip().split()[0] for x in self.content
|
||||
if x.strip() and re.search(r'^[a-zA-Z_]', x.strip()[0])]
|
||||
items = self.get_items(names)
|
||||
nodes = [self.get_table(items)]
|
||||
|
||||
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()
|
||||
docnames = []
|
||||
for name in names:
|
||||
name = real_names.get(name, name)
|
||||
|
||||
docname = posixpath.join(tree_prefix, name)
|
||||
for name, sig, summary, real_name in items:
|
||||
docname = posixpath.join(tree_prefix, real_name)
|
||||
if docname.endswith(suffix):
|
||||
docname = docname[:-len(suffix)]
|
||||
docname = posixpath.normpath(posixpath.join(dirname, docname))
|
||||
if docname not in env.found_docs:
|
||||
warnings.append(self.state.document.reporter.warning(
|
||||
'toctree references unknown document %r' % docname,
|
||||
line=self.lineno))
|
||||
self.warn('toctree references unknown document %r'
|
||||
% docname)
|
||||
docnames.append(docname)
|
||||
|
||||
tocnode = addnodes.toctree()
|
||||
@ -163,63 +188,146 @@ class Autosummary(Directive):
|
||||
tocnode['glob'] = None
|
||||
|
||||
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:
|
||||
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):
|
||||
"""
|
||||
Generate a proper table node for autosummary:: directive.
|
||||
if opts and args:
|
||||
sig = ", ".join(args) + "[, " + ", ".join(opts) + "]"
|
||||
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
|
||||
table. *document* is the Docutils document object.
|
||||
sig = unicode(sig).replace(u" ", u"\u00a0")
|
||||
return u"(%s)" % sig
|
||||
|
||||
"""
|
||||
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
|
||||
# -- Importing items -----------------------------------------------------------
|
||||
|
||||
def import_by_name(name, prefixes=[None]):
|
||||
"""
|
||||
|
@ -20,16 +20,31 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import getopt
|
||||
import optparse
|
||||
import inspect
|
||||
import pydoc
|
||||
|
||||
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
|
||||
|
||||
# create our own templating environment, for module template only
|
||||
env = Environment(loader=PackageLoader('sphinx.ext.autosummary', 'templates'))
|
||||
def main(argv):
|
||||
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):
|
||||
@ -38,14 +53,22 @@ def _simple_info(msg):
|
||||
def _simple_warn(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):
|
||||
info('generating autosummary for: %s' % ', '.join(sources))
|
||||
if output_dir:
|
||||
info('writing to %s' % output_dir)
|
||||
|
||||
# read
|
||||
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:
|
||||
if toctree is not None:
|
||||
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))
|
||||
continue
|
||||
|
||||
fn = os.path.join(path, name + (suffix or '.rst'))
|
||||
fn = os.path.join(path, name + suffix)
|
||||
# skip it if it exists
|
||||
if os.path.isfile(fn):
|
||||
continue
|
||||
@ -73,17 +96,16 @@ def generate_autosummary_docs(sources, output_dir=None, suffix=None,
|
||||
if inspect.ismodule(obj):
|
||||
# XXX replace this with autodoc's API?
|
||||
tmpl = env.get_template('module')
|
||||
functions = [getattr(obj, item).__name__
|
||||
for item in dir(obj)
|
||||
if inspect.isfunction(getattr(obj, item))]
|
||||
classes = [getattr(obj, item).__name__
|
||||
for item in dir(obj)
|
||||
if inspect.isclass(getattr(obj, item))
|
||||
and not issubclass(getattr(obj, item), Exception)]
|
||||
exceptions = [getattr(obj, item).__name__
|
||||
for item in dir(obj)
|
||||
if inspect.isclass(getattr(obj, item))
|
||||
and issubclass(getattr(obj, item), Exception)]
|
||||
|
||||
def get_items(mod, typ):
|
||||
return [getattr(mod, name).__name__
|
||||
for name in dir(mod)
|
||||
if get_documenter(getattr(mod,name)).objtype==typ]
|
||||
|
||||
functions = get_items(obj, 'function')
|
||||
classes = get_items(obj, 'class')
|
||||
exceptions = get_items(obj, 'exception')
|
||||
|
||||
rendered = tmpl.render(name=name,
|
||||
underline='='*len(name),
|
||||
functions=functions,
|
||||
@ -96,19 +118,11 @@ def generate_autosummary_docs(sources, output_dir=None, suffix=None,
|
||||
else:
|
||||
f.write('%s\n%s\n\n' % (name, '='*len(name)))
|
||||
|
||||
if inspect.isclass(obj):
|
||||
if issubclass(obj, Exception):
|
||||
f.write(format_modulemember(name, 'autoexception'))
|
||||
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'))
|
||||
doc = get_documenter(obj)
|
||||
if doc.objtype in ('method', 'attribute'):
|
||||
f.write(format_classmember(name, 'auto%s' % doc.objtype))
|
||||
else:
|
||||
f.write(format_modulemember(name, 'autofunction'))
|
||||
f.write(format_modulemember(name, 'auto%s' % doc.objtype))
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
@ -125,114 +139,125 @@ def format_classmember(name, directive):
|
||||
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'
|
||||
'|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*$')
|
||||
#------------------------------------------------------------------------------
|
||||
# Finding documented entries in files
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
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 = {}
|
||||
|
||||
for filename in filenames:
|
||||
current_title = []
|
||||
last_line = None
|
||||
toctree = None
|
||||
current_module = None
|
||||
in_autosummary = False
|
||||
|
||||
f = open(filename, 'r')
|
||||
for line in f:
|
||||
try:
|
||||
if in_autosummary:
|
||||
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
|
||||
lines = f.read().splitlines()
|
||||
documented.update(get_documented_in_lines(lines, filename=filename))
|
||||
f.close()
|
||||
return documented
|
||||
|
||||
|
||||
def main(argv):
|
||||
usage = 'usage: %s [-o output_dir] [-s suffix] sourcefile ...' % sys.argv[0]
|
||||
def get_documented_in_docstring(name, module=None, filename=None):
|
||||
"""
|
||||
Find out what items are documented in the given object's docstring.
|
||||
See `get_documented_in_lines`.
|
||||
|
||||
"""
|
||||
try:
|
||||
opts, args = getopt.getopt(argv[1:], 'o:s:')
|
||||
except getopt.error:
|
||||
print >>sys.stderr, usage
|
||||
return 1
|
||||
obj, real_name = import_by_name(name)
|
||||
lines = pydoc.getdoc(obj).splitlines()
|
||||
return get_documented_in_lines(lines, module=name, filename=filename)
|
||||
except AttributeError:
|
||||
pass
|
||||
except ImportError, e:
|
||||
print "Failed to import '%s': %s" % (name, e)
|
||||
return {}
|
||||
|
||||
output_dir = None
|
||||
suffix = None
|
||||
for opt, val in opts:
|
||||
if opt == '-o':
|
||||
output_dir = val
|
||||
elif opt == '-s':
|
||||
suffix = val
|
||||
def get_documented_in_lines(lines, module=None, filename=None):
|
||||
"""
|
||||
Find out what items are documented in the given lines
|
||||
|
||||
Returns
|
||||
-------
|
||||
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
|
||||
return 1
|
||||
"""
|
||||
title_underline_re = re.compile("^[-=*_^#]{3,}\s*$")
|
||||
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__':
|
||||
main(sys.argv)
|
||||
main()
|
||||
|
@ -30,6 +30,7 @@ from sphinx.util.smartypants import educateQuotesLatex
|
||||
HEADER = r'''%% Generated by Sphinx.
|
||||
\documentclass[%(papersize)s,%(pointsize)s%(classoptions)s]{%(docclass)s}
|
||||
%(inputenc)s
|
||||
%(utf8extra)s
|
||||
%(fontenc)s
|
||||
%(babel)s
|
||||
%(fontpkg)s
|
||||
@ -136,6 +137,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
'pointsize': '10pt',
|
||||
'classoptions': '',
|
||||
'inputenc': '\\usepackage[utf8]{inputenc}',
|
||||
'utf8extra': '\\DeclareUnicodeCharacter{00A0}{\\nobreakspace}',
|
||||
'fontenc': '\\usepackage[T1]{fontenc}',
|
||||
'babel': '\\usepackage{babel}',
|
||||
'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