2015-03-27 19:50:56 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
2015-06-10 20:13:34 +00:00
|
|
|
Sphinx Auto-API Top-level Extension.
|
|
|
|
|
|
|
|
This extension allows you to automagically generate API documentation from your project.
|
2015-03-27 19:50:56 +00:00
|
|
|
"""
|
2015-06-06 23:11:49 +00:00
|
|
|
import os
|
2015-04-07 20:35:50 +00:00
|
|
|
import shutil
|
2015-03-27 19:50:56 +00:00
|
|
|
|
2017-02-08 14:53:19 +00:00
|
|
|
import sphinx
|
2015-06-10 18:35:54 +00:00
|
|
|
from sphinx.util.console import darkgreen, bold
|
2015-07-07 22:30:16 +00:00
|
|
|
from sphinx.addnodes import toctree
|
2015-08-03 20:55:33 +00:00
|
|
|
from sphinx.errors import ExtensionError
|
2016-11-02 23:29:28 +00:00
|
|
|
from docutils.parsers.rst import directives
|
2015-06-10 18:35:54 +00:00
|
|
|
|
2015-08-03 20:12:34 +00:00
|
|
|
from .backends import default_file_mapping, default_ignore_patterns, default_backend_mapping
|
2017-08-31 23:42:47 +00:00
|
|
|
from .directives import AutoapiSummary, NestedParse
|
2015-10-28 18:04:23 +00:00
|
|
|
from .settings import API_ROOT
|
2016-11-03 19:54:26 +00:00
|
|
|
from .toctree import add_domain_to_toctree
|
2015-04-01 00:01:41 +00:00
|
|
|
|
2015-06-10 20:58:52 +00:00
|
|
|
default_options = ['members', 'undoc-members', 'private-members', 'special-members']
|
2015-06-10 20:13:34 +00:00
|
|
|
|
2015-04-01 00:01:41 +00:00
|
|
|
|
2015-06-10 18:35:54 +00:00
|
|
|
def run_autoapi(app):
|
2015-04-23 20:31:03 +00:00
|
|
|
"""
|
|
|
|
Load AutoAPI data from the filesystem.
|
|
|
|
"""
|
|
|
|
|
2015-09-23 23:00:43 +00:00
|
|
|
if not app.config.autoapi_dirs:
|
2015-10-12 17:50:46 +00:00
|
|
|
raise ExtensionError('You must configure an autoapi_dirs setting')
|
2015-06-10 18:35:54 +00:00
|
|
|
|
2015-07-07 23:19:25 +00:00
|
|
|
# Make sure the paths are full
|
2015-09-23 23:00:43 +00:00
|
|
|
normalized_dirs = []
|
2016-05-02 02:23:05 +00:00
|
|
|
autoapi_dirs = app.config.autoapi_dirs
|
2016-06-08 23:34:52 +00:00
|
|
|
if isinstance(autoapi_dirs, str):
|
2016-05-02 02:23:05 +00:00
|
|
|
autoapi_dirs = [autoapi_dirs]
|
|
|
|
for path in autoapi_dirs:
|
2015-09-23 23:00:43 +00:00
|
|
|
if os.path.isabs(path):
|
2016-02-03 05:14:28 +00:00
|
|
|
normalized_dirs.append(path)
|
2015-09-23 23:00:43 +00:00
|
|
|
else:
|
|
|
|
normalized_dirs.append(
|
|
|
|
os.path.normpath(os.path.join(app.confdir, path))
|
|
|
|
)
|
2015-07-07 23:19:25 +00:00
|
|
|
|
2015-09-23 23:00:43 +00:00
|
|
|
for _dir in normalized_dirs:
|
|
|
|
if not os.path.exists(_dir):
|
|
|
|
raise ExtensionError(
|
2015-09-23 23:04:45 +00:00
|
|
|
'AutoAPI Directory `{dir}` not found. '
|
|
|
|
'Please check your `autoapi_dirs` setting.'.format(
|
2015-09-23 23:00:43 +00:00
|
|
|
dir=_dir
|
|
|
|
)
|
|
|
|
)
|
2015-08-03 17:36:04 +00:00
|
|
|
|
2015-07-07 23:19:25 +00:00
|
|
|
normalized_root = os.path.normpath(os.path.join(app.confdir, app.config.autoapi_root))
|
2015-10-28 18:04:23 +00:00
|
|
|
url_root = os.path.join('/', app.config.autoapi_root)
|
2015-07-07 23:19:25 +00:00
|
|
|
|
2016-11-04 20:42:15 +00:00
|
|
|
sphinx_mapper = default_backend_mapping[app.config.autoapi_type]
|
|
|
|
sphinx_mapper_obj = sphinx_mapper(app, template_dir=app.config.autoapi_template_dir,
|
|
|
|
url_root=url_root)
|
2017-08-31 23:42:47 +00:00
|
|
|
app.env.autoapi_mapper = sphinx_mapper_obj
|
2015-06-10 18:35:54 +00:00
|
|
|
|
2015-07-07 23:32:38 +00:00
|
|
|
if app.config.autoapi_file_patterns:
|
2015-09-22 15:02:34 +00:00
|
|
|
file_patterns = app.config.autoapi_file_patterns
|
2015-07-07 23:19:25 +00:00
|
|
|
else:
|
2015-07-20 18:44:38 +00:00
|
|
|
file_patterns = default_file_mapping.get(app.config.autoapi_type, [])
|
2015-07-07 23:19:25 +00:00
|
|
|
|
2015-07-20 18:37:31 +00:00
|
|
|
if app.config.autoapi_ignore:
|
|
|
|
ignore_patterns = app.config.autoapi_ignore
|
|
|
|
else:
|
2015-07-20 18:44:38 +00:00
|
|
|
ignore_patterns = default_ignore_patterns.get(app.config.autoapi_type, [])
|
2015-07-20 18:37:31 +00:00
|
|
|
|
2016-08-25 17:58:06 +00:00
|
|
|
if '.rst' in app.config.source_suffix:
|
|
|
|
out_suffix = '.rst'
|
|
|
|
elif '.txt' in app.config.source_suffix:
|
|
|
|
out_suffix = '.txt'
|
|
|
|
else:
|
|
|
|
# Fallback to first suffix listed
|
|
|
|
out_suffix = app.config.source_suffix[0]
|
|
|
|
|
|
|
|
# Actual meat of the run.
|
2015-06-10 18:35:54 +00:00
|
|
|
app.info(bold('[AutoAPI] ') + darkgreen('Loading Data'))
|
2016-11-04 20:42:15 +00:00
|
|
|
sphinx_mapper_obj.load(
|
2015-07-07 23:19:25 +00:00
|
|
|
patterns=file_patterns,
|
2015-09-23 23:00:43 +00:00
|
|
|
dirs=normalized_dirs,
|
2015-07-20 18:37:31 +00:00
|
|
|
ignore=ignore_patterns,
|
2015-06-06 23:11:49 +00:00
|
|
|
)
|
2015-06-10 18:35:54 +00:00
|
|
|
|
|
|
|
app.info(bold('[AutoAPI] ') + darkgreen('Mapping Data'))
|
2016-11-04 20:42:15 +00:00
|
|
|
sphinx_mapper_obj.map(options=app.config.autoapi_options)
|
2015-06-10 18:35:54 +00:00
|
|
|
|
|
|
|
app.info(bold('[AutoAPI] ') + darkgreen('Rendering Data'))
|
2016-11-04 20:42:15 +00:00
|
|
|
sphinx_mapper_obj.output_rst(
|
2015-07-07 23:19:25 +00:00
|
|
|
root=normalized_root,
|
2016-08-25 17:58:06 +00:00
|
|
|
source_suffix=out_suffix,
|
2015-06-06 23:11:49 +00:00
|
|
|
)
|
2015-03-27 19:50:56 +00:00
|
|
|
|
|
|
|
|
2015-04-07 20:35:50 +00:00
|
|
|
def build_finished(app, exception):
|
|
|
|
if not app.config.autoapi_keep_files:
|
2015-07-07 23:19:25 +00:00
|
|
|
normalized_root = os.path.normpath(os.path.join(app.confdir, app.config.autoapi_root))
|
2015-04-07 20:35:50 +00:00
|
|
|
if app.verbosity > 1:
|
2015-06-10 18:35:54 +00:00
|
|
|
app.info(bold('[AutoAPI] ') + darkgreen('Cleaning generated .rst files'))
|
2015-07-07 23:19:25 +00:00
|
|
|
shutil.rmtree(normalized_root)
|
2015-04-07 20:35:50 +00:00
|
|
|
|
2016-11-04 20:42:15 +00:00
|
|
|
sphinx_mapper = default_backend_mapping[app.config.autoapi_type]
|
|
|
|
if hasattr(sphinx_mapper, 'build_finished'):
|
|
|
|
sphinx_mapper.build_finished(app, exception)
|
2015-08-03 17:36:04 +00:00
|
|
|
|
2015-04-07 20:35:50 +00:00
|
|
|
|
2015-07-07 22:30:16 +00:00
|
|
|
def doctree_read(app, doctree):
|
2016-11-03 19:54:26 +00:00
|
|
|
"""
|
|
|
|
Inject AutoAPI into the TOC Tree dynamically.
|
|
|
|
"""
|
2015-07-07 22:30:16 +00:00
|
|
|
if app.env.docname == 'index':
|
2017-06-28 00:12:47 +00:00
|
|
|
all_docs = set()
|
|
|
|
insert = True
|
2015-07-07 22:30:16 +00:00
|
|
|
nodes = doctree.traverse(toctree)
|
2016-11-03 20:24:22 +00:00
|
|
|
toc_entry = '%s/index' % app.config.autoapi_root
|
2015-07-07 22:30:16 +00:00
|
|
|
if not nodes:
|
|
|
|
return
|
2017-06-28 00:12:47 +00:00
|
|
|
# Capture all existing toctree entries
|
2017-06-29 22:10:06 +00:00
|
|
|
root = nodes[0]
|
2015-07-07 22:30:16 +00:00
|
|
|
for node in nodes:
|
|
|
|
for entry in node['entries']:
|
|
|
|
all_docs.add(entry[1])
|
2017-06-28 00:12:47 +00:00
|
|
|
# Don't insert autoapi it's already present
|
2015-07-07 22:30:16 +00:00
|
|
|
for doc in all_docs:
|
2015-07-07 22:48:00 +00:00
|
|
|
if doc.find(app.config.autoapi_root) != -1:
|
2015-07-07 22:30:16 +00:00
|
|
|
insert = False
|
|
|
|
if insert and app.config.autoapi_add_toctree_entry:
|
2017-06-28 00:12:47 +00:00
|
|
|
if app.config.autoapi_add_api_root_toctree:
|
|
|
|
# Insert full API TOC in root TOC
|
|
|
|
for path in app.env.autoapi_toc_entries:
|
|
|
|
nodes[-1]['entries'].append(
|
|
|
|
(None, path[1:])
|
|
|
|
)
|
|
|
|
nodes[-1]['includefiles'].append(path)
|
|
|
|
else:
|
|
|
|
# Insert AutoAPI index
|
|
|
|
nodes[-1]['entries'].append(
|
|
|
|
(None, u'%s/index' % app.config.autoapi_root)
|
|
|
|
)
|
|
|
|
nodes[-1]['includefiles'].append(u'%s/index' % app.config.autoapi_root)
|
|
|
|
app.info(bold('[AutoAPI] ') +
|
|
|
|
darkgreen('Adding AutoAPI TOCTree [%s] to index.rst' % toc_entry)
|
|
|
|
)
|
2015-07-07 22:30:16 +00:00
|
|
|
|
|
|
|
|
2017-08-31 23:42:47 +00:00
|
|
|
def clear_env(app, env):
|
|
|
|
"""Clears the environment of the unpicklable objects that we left behind."""
|
|
|
|
env.autoapi_mapper = None
|
|
|
|
|
|
|
|
|
2015-03-27 19:50:56 +00:00
|
|
|
def setup(app):
|
2015-06-10 18:35:54 +00:00
|
|
|
app.connect('builder-inited', run_autoapi)
|
2015-07-07 22:30:16 +00:00
|
|
|
app.connect('doctree-read', doctree_read)
|
2016-11-03 19:54:26 +00:00
|
|
|
app.connect('doctree-resolved', add_domain_to_toctree)
|
2017-06-28 00:12:47 +00:00
|
|
|
app.connect('build-finished', build_finished)
|
2017-08-31 23:42:47 +00:00
|
|
|
app.connect('env-updated', clear_env)
|
2015-06-01 18:29:19 +00:00
|
|
|
app.add_config_value('autoapi_type', 'python', 'html')
|
2015-10-28 18:04:23 +00:00
|
|
|
app.add_config_value('autoapi_root', API_ROOT, 'html')
|
2015-07-20 18:37:31 +00:00
|
|
|
app.add_config_value('autoapi_ignore', [], 'html')
|
2015-06-10 20:13:34 +00:00
|
|
|
app.add_config_value('autoapi_options', default_options, 'html')
|
2015-07-07 23:32:38 +00:00
|
|
|
app.add_config_value('autoapi_file_patterns', None, 'html')
|
2015-09-23 23:00:43 +00:00
|
|
|
app.add_config_value('autoapi_dirs', [], 'html')
|
2015-06-10 18:35:54 +00:00
|
|
|
app.add_config_value('autoapi_keep_files', False, 'html')
|
2015-07-07 22:30:16 +00:00
|
|
|
app.add_config_value('autoapi_add_toctree_entry', True, 'html')
|
2017-06-28 00:12:47 +00:00
|
|
|
app.add_config_value('autoapi_add_api_root_toctree', False, 'html')
|
2017-08-31 23:43:44 +00:00
|
|
|
app.add_config_value('autoapi_template_dir', None, 'html')
|
2017-11-08 19:29:51 +00:00
|
|
|
app.add_config_value('autoapi_include_summaries', False, 'html')
|
2015-04-21 05:54:32 +00:00
|
|
|
app.add_stylesheet('autoapi.css')
|
2016-11-02 23:29:28 +00:00
|
|
|
directives.register_directive('autoapi-nested-parse', NestedParse)
|
2017-08-31 23:42:47 +00:00
|
|
|
directives.register_directive('autoapisummary', AutoapiSummary)
|
2017-11-10 21:14:14 +00:00
|
|
|
app.setup_extension('sphinx.ext.autosummary')
|