mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Work a bit on coding style of autosummary.
This commit is contained in:
parent
ce4d9c3665
commit
c85d4c2db2
15
sphinx-autogen.py
Executable file
15
sphinx-autogen.py
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: 2007-2009 by Georg Brandl.
|
||||
:license: BSD.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
if __name__ == '__main__':
|
||||
from sphinx.ext.autosummary.generate import main
|
||||
sys.exit(main(sys.argv))
|
@ -1,80 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
===========
|
||||
autosummary
|
||||
===========
|
||||
sphinx.ext.autosummary
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sphinx extension that adds an autosummary:: directive, which can be
|
||||
used to generate function/method/attribute/etc. summary lists, similar
|
||||
to those output eg. by Epydoc and other API doc generation tools.
|
||||
Sphinx extension that adds an autosummary:: directive, which can be
|
||||
used to generate function/method/attribute/etc. summary lists, similar
|
||||
to those output eg. by Epydoc and other API doc generation tools.
|
||||
|
||||
An :autolink: role is also provided.
|
||||
An :autolink: role is also provided.
|
||||
|
||||
autosummary directive
|
||||
---------------------
|
||||
autosummary directive
|
||||
---------------------
|
||||
|
||||
The autosummary directive has the form::
|
||||
The autosummary directive has the form::
|
||||
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
:toctree: generated/
|
||||
|
||||
module.function_1
|
||||
module.function_2
|
||||
...
|
||||
.. autosummary::
|
||||
:nosignatures:
|
||||
:toctree: generated/
|
||||
|
||||
and it generates an output table (containing signatures, optionally)
|
||||
module.function_1
|
||||
module.function_2
|
||||
...
|
||||
|
||||
======================== =============================================
|
||||
module.function_1(args) Summary line from the docstring of function_1
|
||||
module.function_2(args) Summary line from the docstring
|
||||
...
|
||||
======================== =============================================
|
||||
and it generates an output table (containing signatures, optionally)
|
||||
|
||||
If the :toctree: option is specified, files matching the function names
|
||||
are inserted to the toctree with the given prefix:
|
||||
======================== =============================================
|
||||
module.function_1(args) Summary line from the docstring of function_1
|
||||
module.function_2(args) Summary line from the docstring
|
||||
...
|
||||
======================== =============================================
|
||||
|
||||
generated/module.function_1
|
||||
generated/module.function_2
|
||||
...
|
||||
If the :toctree: option is specified, files matching the function names
|
||||
are inserted to the toctree with the given prefix:
|
||||
|
||||
Note: The file names contain the module:: or currentmodule:: prefixes.
|
||||
generated/module.function_1
|
||||
generated/module.function_2
|
||||
...
|
||||
|
||||
.. seealso:: autosummary_generate.py
|
||||
Note: The file names contain the module:: or currentmodule:: prefixes.
|
||||
|
||||
.. seealso:: autosummary_generate.py
|
||||
|
||||
|
||||
autolink role
|
||||
-------------
|
||||
autolink role
|
||||
-------------
|
||||
|
||||
The autolink role functions as ``:obj:`` when the name referred can be
|
||||
resolved to a Python object, and otherwise it becomes simple emphasis.
|
||||
This can be used as the default role to make links 'smart'.
|
||||
The autolink role functions as ``:obj:`` when the name referred can be
|
||||
resolved to a Python object, and otherwise it becomes simple emphasis.
|
||||
This can be used as the default role to make links 'smart'.
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import sys, os, posixpath, re
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import inspect
|
||||
import posixpath
|
||||
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.statemachine import ViewList
|
||||
from docutils import nodes
|
||||
|
||||
import sphinx.addnodes, sphinx.roles, sphinx.builder
|
||||
from sphinx import addnodes, roles
|
||||
from sphinx.util import patfilter
|
||||
|
||||
import inspect
|
||||
|
||||
def setup(app):
|
||||
app.add_directive('autosummary', autosummary_directive, True, (0, 0, False),
|
||||
toctree=directives.unchanged,
|
||||
nosignatures=directives.flag)
|
||||
app.add_role('autolink', autolink_role)
|
||||
|
||||
app.add_node(autosummary_toc,
|
||||
html=(autosummary_toc_visit_html, autosummary_toc_depart_noop),
|
||||
latex=(autosummary_toc_visit_latex, autosummary_toc_depart_noop))
|
||||
app.connect('doctree-read', process_autosummary_toc)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# autosummary_toc node
|
||||
#------------------------------------------------------------------------------
|
||||
# -- autosummary_toc node ------------------------------------------------------
|
||||
|
||||
class autosummary_toc(nodes.comment):
|
||||
pass
|
||||
@ -83,7 +76,6 @@ def process_autosummary_toc(app, doctree):
|
||||
"""
|
||||
Insert items described in autosummary:: to the TOC tree, but do
|
||||
not generate the toctree:: list.
|
||||
|
||||
"""
|
||||
env = app.builder.env
|
||||
crawled = {}
|
||||
@ -92,7 +84,7 @@ def process_autosummary_toc(app, doctree):
|
||||
for j, subnode in enumerate(node):
|
||||
try:
|
||||
if (isinstance(subnode, autosummary_toc)
|
||||
and isinstance(subnode[0], sphinx.addnodes.toctree)):
|
||||
and isinstance(subnode[0], addnodes.toctree)):
|
||||
env.note_toctree(env.docname, subnode[0])
|
||||
continue
|
||||
except IndexError:
|
||||
@ -104,19 +96,18 @@ def process_autosummary_toc(app, doctree):
|
||||
crawl_toc(doctree)
|
||||
|
||||
def autosummary_toc_visit_html(self, node):
|
||||
"""Hide autosummary toctree list in HTML output"""
|
||||
"""Hide autosummary toctree list in HTML output."""
|
||||
raise nodes.SkipNode
|
||||
|
||||
def autosummary_toc_visit_latex(self, node):
|
||||
"""Show autosummary toctree (= put the referenced pages here) in Latex"""
|
||||
"""Show autosummary toctree (= put the referenced pages here) in Latex."""
|
||||
pass
|
||||
|
||||
def autosummary_toc_depart_noop(self, node):
|
||||
pass
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# .. autosummary::
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -- .. autosummary:: ----------------------------------------------------------
|
||||
|
||||
def autosummary_directive(dirname, arguments, options, content, lineno,
|
||||
content_offset, block_text, state, state_machine):
|
||||
@ -155,7 +146,7 @@ def autosummary_directive(dirname, arguments, options, content, lineno,
|
||||
line=lineno))
|
||||
docnames.append(docname)
|
||||
|
||||
tocnode = sphinx.addnodes.toctree()
|
||||
tocnode = addnodes.toctree()
|
||||
tocnode['includefiles'] = docnames
|
||||
tocnode['maxdepth'] = -1
|
||||
tocnode['glob'] = None
|
||||
@ -165,6 +156,7 @@ def autosummary_directive(dirname, arguments, options, content, lineno,
|
||||
else:
|
||||
return warnings + [node]
|
||||
|
||||
|
||||
def get_autosummary(names, state, no_signatures=False):
|
||||
"""
|
||||
Generate a proper table node for autosummary:: directive.
|
||||
@ -175,10 +167,10 @@ def get_autosummary(names, state, no_signatures=False):
|
||||
Names of Python objects to be imported and added to the table.
|
||||
document : document
|
||||
Docutils document object
|
||||
|
||||
|
||||
"""
|
||||
document = state.document
|
||||
|
||||
|
||||
real_names = {}
|
||||
warnings = []
|
||||
|
||||
@ -209,14 +201,14 @@ def get_autosummary(names, state, no_signatures=False):
|
||||
except ImportError:
|
||||
warnings.append(document.reporter.warning(
|
||||
'failed to import %s' % name))
|
||||
append_row(":obj:`%s`" % name, "")
|
||||
append_row(':obj:`%s`' % name, '')
|
||||
continue
|
||||
|
||||
real_names[name] = real_name
|
||||
|
||||
title = ""
|
||||
title = ''
|
||||
qualifier = 'obj'
|
||||
col1 = ":"+qualifier+":`%s <%s>`" % (name, real_name)
|
||||
col1 = ':'+qualifier+':`%s <%s>`' % (name, real_name)
|
||||
col2 = title
|
||||
append_row(col1, col2)
|
||||
|
||||
@ -240,7 +232,7 @@ def import_by_name(name, prefixes=[None]):
|
||||
The imported object
|
||||
name
|
||||
Name of the imported object (useful if `prefixes` was used)
|
||||
|
||||
|
||||
"""
|
||||
for prefix in prefixes:
|
||||
try:
|
||||
@ -254,9 +246,18 @@ def import_by_name(name, prefixes=[None]):
|
||||
raise ImportError
|
||||
|
||||
def _import_by_name(name):
|
||||
"""Import a Python object given its full name"""
|
||||
"""Import a Python object given its full name."""
|
||||
try:
|
||||
# try first interpret `name` as MODNAME.OBJ
|
||||
name_parts = name.split('.')
|
||||
try:
|
||||
modname = '.'.join(name_parts[:-1])
|
||||
__import__(modname)
|
||||
return getattr(sys.modules[modname], name_parts[-1])
|
||||
except (ImportError, IndexError, AttributeError):
|
||||
pass
|
||||
|
||||
# ... then as MODNAME, MODNAME.OBJ1, MODNAME.OBJ1.OBJ2, ...
|
||||
last_j = 0
|
||||
modname = None
|
||||
for j in reversed(range(1, len(name_parts)+1)):
|
||||
@ -279,20 +280,19 @@ def _import_by_name(name):
|
||||
except (ValueError, ImportError, AttributeError, KeyError), e:
|
||||
raise ImportError(e)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# :autolink: (smart default role)
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
# -- :autolink: (smart default role) -------------------------------------------
|
||||
|
||||
def autolink_role(typ, rawtext, etext, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
"""
|
||||
Smart linking role.
|
||||
|
||||
Expands to ":obj:`text`" if `text` is an object that can be imported;
|
||||
otherwise expands to "*text*".
|
||||
Expands to ':obj:`text`' if `text` is an object that can be imported;
|
||||
otherwise expands to '*text*'.
|
||||
"""
|
||||
r = sphinx.roles.xfileref_role('obj', rawtext, etext, lineno, inliner,
|
||||
options, content)
|
||||
r = roles.xfileref_role('obj', rawtext, etext, lineno, inliner,
|
||||
options, content)
|
||||
pnode = r[0][0]
|
||||
|
||||
prefixes = [None]
|
||||
@ -304,3 +304,15 @@ def autolink_role(typ, rawtext, etext, lineno, inliner,
|
||||
r[0][0] = nodes.emphasis(rawtext, content[0].astext(),
|
||||
classes=content['classes'])
|
||||
return r
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.add_directive('autosummary', autosummary_directive, True, (0, 0, False),
|
||||
toctree=directives.unchanged,
|
||||
nosignatures=directives.flag)
|
||||
app.add_role('autolink', autolink_role)
|
||||
|
||||
app.add_node(autosummary_toc,
|
||||
html=(autosummary_toc_visit_html, autosummary_toc_depart_noop),
|
||||
latex=(autosummary_toc_visit_latex, autosummary_toc_depart_noop))
|
||||
app.connect('doctree-read', process_autosummary_toc)
|
||||
|
@ -1,85 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
autosummary_generate.py OPTIONS FILES
|
||||
sphinx.ext.autosummary.generate
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Generate automatic RST source files for items referred to in
|
||||
autosummary:: directives.
|
||||
Usable as a library or script to generate automatic RST source files for
|
||||
items referred to in autosummary:: directives.
|
||||
|
||||
Each generated RST file contains a single auto*:: directive which
|
||||
extracts the docstring of the referred item.
|
||||
Each generated RST file contains a single auto*:: directive which
|
||||
extracts the docstring of the referred item.
|
||||
|
||||
Example Makefile rule::
|
||||
Example Makefile rule::
|
||||
|
||||
generate:
|
||||
sphinx-autogen source/*.rst source/generated
|
||||
generate:
|
||||
sphinx-autogen source/*.rst source/generated
|
||||
|
||||
:copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import glob, re, inspect, os, optparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import glob
|
||||
import inspect
|
||||
|
||||
from jinja2 import Environment, PackageLoader
|
||||
|
||||
from sphinx.ext.autosummary import import_by_name
|
||||
from sphinx.util import ensuredir
|
||||
|
||||
from jinja import Environment, PackageLoader
|
||||
env = Environment(loader=PackageLoader('sphinx.ext.autosummary', 'templates'))
|
||||
# create our own templating environment, for module template only
|
||||
env = Environment(loader=PackageLoader('sphinx.ext.autosummary', 'templates'))
|
||||
|
||||
def main():
|
||||
p = optparse.OptionParser(__doc__.strip())
|
||||
options, args = p.parse_args()
|
||||
|
||||
if len(args) <2:
|
||||
p.error("wrong number of arguments")
|
||||
|
||||
print 'generating docs from:', args[:-1]
|
||||
generate_autosummary_docs(args[:-1], args[-1])
|
||||
|
||||
def generate_autosummary_docs(source_dir, output_dir):
|
||||
def generate_autosummary_docs(sources, output_dir=None):
|
||||
# read
|
||||
names = {}
|
||||
for name, loc in get_documented(source_dir).items():
|
||||
for name, loc in get_documented(sources).items():
|
||||
for (filename, sec_title, keyword, toctree) in loc:
|
||||
if toctree is not None:
|
||||
path = os.path.join(os.path.dirname(filename), toctree)
|
||||
names[name] = os.path.abspath(path)
|
||||
|
||||
|
||||
# write
|
||||
for name, path in sorted(names.items()):
|
||||
path = output_dir
|
||||
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path)
|
||||
if output_dir is not None:
|
||||
path = output_dir
|
||||
|
||||
ensuredir(path)
|
||||
|
||||
try:
|
||||
obj, name = import_by_name(name)
|
||||
except ImportError, e:
|
||||
print "Failed to import '%s': %s" % (name, e)
|
||||
print >>sys.stderr, 'Failed to import %r: %s' % (name, e)
|
||||
continue
|
||||
|
||||
fn = os.path.join(path, '%s.rst' % name)
|
||||
|
||||
if os.path.exists(fn):
|
||||
# skip
|
||||
# skip it if it exists
|
||||
if os.path.isfile(fn):
|
||||
continue
|
||||
|
||||
f = open(fn, 'w')
|
||||
|
||||
|
||||
try:
|
||||
|
||||
if inspect.ismodule(obj):
|
||||
tmpl = env.get_template('module.html')
|
||||
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)]
|
||||
rendered = tmpl.render(name=name,
|
||||
functions=functions,
|
||||
classes=classes,
|
||||
exceptions=exceptions,
|
||||
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)]
|
||||
rendered = tmpl.render(name=name,
|
||||
functions=functions,
|
||||
classes=classes,
|
||||
exceptions=exceptions,
|
||||
len_functions=len(functions),
|
||||
len_classes=len(classes),
|
||||
len_exceptions=len(exceptions)
|
||||
|
||||
)
|
||||
len_exceptions=len(exceptions))
|
||||
f.write(rendered)
|
||||
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'))
|
||||
@ -96,40 +102,40 @@ def generate_autosummary_docs(source_dir, output_dir):
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
|
||||
def format_modulemember(name, directive):
|
||||
parts = name.split('.')
|
||||
mod, name = '.'.join(parts[:-1]), parts[-1]
|
||||
return ".. currentmodule:: %s\n\n.. %s:: %s\n" % (mod, directive, name)
|
||||
return '.. currentmodule:: %s\n\n.. %s:: %s\n' % (mod, directive, name)
|
||||
|
||||
|
||||
def format_classmember(name, directive):
|
||||
parts = name.split('.')
|
||||
mod, name = '.'.join(parts[:-2]), '.'.join(parts[-2:])
|
||||
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'
|
||||
'|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):
|
||||
"""
|
||||
Find out what items are documented in source/*.rst
|
||||
|
||||
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.
|
||||
Find out what items are documented in the given filenames.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
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 = {}
|
||||
|
||||
|
||||
for filename in filenames:
|
||||
current_title = []
|
||||
last_line = None
|
||||
@ -150,32 +156,34 @@ def get_documented(filenames):
|
||||
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)
|
||||
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 current_module and not name.startswith(current_module + '.'):
|
||||
name = "%s.%s" % (current_module, name)
|
||||
if m.group(1) == "module":
|
||||
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))
|
||||
(filename, current_title, 'auto' + m.group(1), None))
|
||||
continue
|
||||
|
||||
m = title_underline_re.match(line)
|
||||
@ -191,5 +199,17 @@ def get_documented(filenames):
|
||||
last_line = line
|
||||
return documented
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
def main(args=None):
|
||||
if args is None:
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len(args) < 2:
|
||||
print >>sys.stderr, 'usage: %s sourcefile ... outputdir' % sys.argv[0]
|
||||
|
||||
print 'generating docs from:', ', '.join(args[:-1])
|
||||
generate_autosummary_docs(args[:-1], args[-1])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user