Change extension setup() return value to a dictionary of metadata.

This makes it possible to introduce more metadata values later.
This commit is contained in:
Georg Brandl 2014-09-22 11:06:42 +02:00
parent 57e897669d
commit 71cd2f7e50
20 changed files with 43 additions and 31 deletions

View File

@ -18,15 +18,25 @@ imports this module and executes its ``setup()`` function, which in turn
notifies Sphinx of everything the extension offers -- see the extension tutorial notifies Sphinx of everything the extension offers -- see the extension tutorial
for examples. for examples.
.. versionadded:: 1.3
The ``setup()`` function can return a string, this is treated by Sphinx as
the version of the extension and used for informational purposes such as the
traceback file when an exception occurs.
The configuration file itself can be treated as an extension if it contains a The configuration file itself can be treated as an extension if it contains a
``setup()`` function. All other extensions to load must be listed in the ``setup()`` function. All other extensions to load must be listed in the
:confval:`extensions` configuration value. :confval:`extensions` configuration value.
Extension metadata
------------------
.. versionadded:: 1.3
The ``setup()`` function can return a dictionary. This is treated by Sphinx
as metadata of the extension. Metadata keys currently recognized are:
* ``'version'``: a string that identifies the extension version. It is used for
extension version requirement checking (see :confval:`needs_extensions`) and
informational purposes. If not given, ``"unknown version"`` is substituted.
APIs used for writing extensions
--------------------------------
.. toctree:: .. toctree::
tutorial tutorial

View File

@ -162,7 +162,7 @@ new Python module called :file:`todo.py` and add the setup function::
app.connect('doctree-resolved', process_todo_nodes) app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos) app.connect('env-purge-doc', purge_todos)
return '0.1' # identifies the version of our extension return {'version': '0.1'} # identifies the version of our extension
The calls in this function refer to classes and functions not yet written. What The calls in this function refer to classes and functions not yet written. What
the individual calls do is the following: the individual calls do is the following:

View File

@ -73,7 +73,7 @@ class Sphinx(object):
self.verbosity = verbosity self.verbosity = verbosity
self.next_listener_id = 0 self.next_listener_id = 0
self._extensions = {} self._extensions = {}
self._extension_versions = {} self._extension_metadata = {}
self._listeners = {} self._listeners = {}
self.domains = BUILTIN_DOMAINS.copy() self.domains = BUILTIN_DOMAINS.copy()
self.builderclasses = BUILTIN_BUILDERS.copy() self.builderclasses = BUILTIN_BUILDERS.copy()
@ -129,7 +129,7 @@ class Sphinx(object):
self.setup_extension(extension) self.setup_extension(extension)
# the config file itself can be an extension # the config file itself can be an extension
if self.config.setup: if self.config.setup:
# py31 doesn't have 'callable' function for bellow check # py31 doesn't have 'callable' function for below check
if hasattr(self.config.setup, '__call__'): if hasattr(self.config.setup, '__call__'):
self.config.setup(self) self.config.setup(self)
else: else:
@ -157,7 +157,7 @@ class Sphinx(object):
'version requirement for extension %s, but it is ' 'version requirement for extension %s, but it is '
'not loaded' % extname) 'not loaded' % extname)
continue continue
has_ver = self._extension_versions[extname] has_ver = self._extension_metadata[extname]['version']
if has_ver == 'unknown version' or needs_ver > has_ver: if has_ver == 'unknown version' or needs_ver > has_ver:
raise VersionRequirementError( raise VersionRequirementError(
'This project needs the extension %s at least in ' 'This project needs the extension %s at least in '
@ -367,20 +367,22 @@ class Sphinx(object):
if not hasattr(mod, 'setup'): if not hasattr(mod, 'setup'):
self.warn('extension %r has no setup() function; is it really ' self.warn('extension %r has no setup() function; is it really '
'a Sphinx extension module?' % extension) 'a Sphinx extension module?' % extension)
version = None ext_meta = None
else: else:
try: try:
version = mod.setup(self) ext_meta = mod.setup(self)
except VersionRequirementError as err: except VersionRequirementError as err:
# add the extension name to the version required # add the extension name to the version required
raise VersionRequirementError( raise VersionRequirementError(
'The %s extension used by this project needs at least ' 'The %s extension used by this project needs at least '
'Sphinx v%s; it therefore cannot be built with this ' 'Sphinx v%s; it therefore cannot be built with this '
'version.' % (extension, err)) 'version.' % (extension, err))
if version is None: if ext_meta is None:
version = 'unknown version' ext_meta = {}
if not ext_meta.get('version'):
ext_meta['version'] = 'unknown version'
self._extensions[extension] = mod self._extensions[extension] = mod
self._extension_versions[extension] = version self._extension_metadata[extension] = ext_meta
def require_sphinx(self, version): def require_sphinx(self, version):
# check the Sphinx version if requested # check the Sphinx version if requested

View File

@ -1515,7 +1515,7 @@ def setup(app):
app.add_event('autodoc-process-signature') app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member') app.add_event('autodoc-skip-member')
return sphinx.__version__ return {'version': sphinx.__version__}
class testcls: class testcls:

View File

@ -570,4 +570,4 @@ def setup(app):
app.connect('doctree-read', process_autosummary_toc) app.connect('doctree-read', process_autosummary_toc)
app.connect('builder-inited', process_generate_options) app.connect('builder-inited', process_generate_options)
app.add_config_value('autosummary_generate', [], True) app.add_config_value('autosummary_generate', [], True)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -265,4 +265,4 @@ def setup(app):
app.add_config_value('coverage_ignore_c_items', {}, False) app.add_config_value('coverage_ignore_c_items', {}, False)
app.add_config_value('coverage_write_headline', True, False) app.add_config_value('coverage_write_headline', True, False)
app.add_config_value('coverage_skip_undoc_in_source', False, False) app.add_config_value('coverage_skip_undoc_in_source', False, False)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -443,4 +443,4 @@ def setup(app):
app.add_config_value('doctest_test_doctest_blocks', 'default', False) app.add_config_value('doctest_test_doctest_blocks', 'default', False)
app.add_config_value('doctest_global_setup', '', False) app.add_config_value('doctest_global_setup', '', False)
app.add_config_value('doctest_global_cleanup', '', False) app.add_config_value('doctest_global_cleanup', '', False)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -59,4 +59,4 @@ def setup_link_roles(app):
def setup(app): def setup(app):
app.add_config_value('extlinks', {}, 'env') app.add_config_value('extlinks', {}, 'env')
app.connect('builder-inited', setup_link_roles) app.connect('builder-inited', setup_link_roles)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -323,4 +323,4 @@ def setup(app):
app.add_config_value('graphviz_dot', 'dot', 'html') app.add_config_value('graphviz_dot', 'dot', 'html')
app.add_config_value('graphviz_dot_args', [], 'html') app.add_config_value('graphviz_dot_args', [], 'html')
app.add_config_value('graphviz_output_format', 'png', 'html') app.add_config_value('graphviz_output_format', 'png', 'html')
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -73,4 +73,4 @@ def setup(app):
app.add_node(ifconfig) app.add_node(ifconfig)
app.add_directive('ifconfig', IfConfig) app.add_directive('ifconfig', IfConfig)
app.connect('doctree-resolved', process_ifconfig_nodes) app.connect('doctree-resolved', process_ifconfig_nodes)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -408,4 +408,4 @@ def setup(app):
app.add_config_value('inheritance_graph_attrs', {}, False), app.add_config_value('inheritance_graph_attrs', {}, False),
app.add_config_value('inheritance_node_attrs', {}, False), app.add_config_value('inheritance_node_attrs', {}, False),
app.add_config_value('inheritance_edge_attrs', {}, False), app.add_config_value('inheritance_edge_attrs', {}, False),
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -282,4 +282,4 @@ def setup(app):
app.add_config_value('intersphinx_cache_limit', 5, False) app.add_config_value('intersphinx_cache_limit', 5, False)
app.connect('missing-reference', missing_reference) app.connect('missing-reference', missing_reference)
app.connect('builder-inited', load_mappings) app.connect('builder-inited', load_mappings)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -57,4 +57,4 @@ def setup(app):
mathbase_setup(app, (html_visit_math, None), (html_visit_displaymath, None)) mathbase_setup(app, (html_visit_math, None), (html_visit_displaymath, None))
app.add_config_value('jsmath_path', '', False) app.add_config_value('jsmath_path', '', False)
app.connect('builder-inited', builder_inited) app.connect('builder-inited', builder_inited)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -71,4 +71,4 @@ def doctree_read(app, doctree):
def setup(app): def setup(app):
app.connect('doctree-read', doctree_read) app.connect('doctree-read', doctree_read)
app.add_config_value('linkcode_resolve', None, '') app.add_config_value('linkcode_resolve', None, '')
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -69,4 +69,4 @@ def setup(app):
app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html') app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html') app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
app.connect('builder-inited', builder_inited) app.connect('builder-inited', builder_inited)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -256,7 +256,7 @@ def setup(app):
for name, (default, rebuild) in iteritems(Config._config_values): for name, (default, rebuild) in iteritems(Config._config_values):
app.add_config_value(name, default, rebuild) app.add_config_value(name, default, rebuild)
return sphinx.__version__ return {'version': sphinx.__version__}
def _process_docstring(app, what, name, obj, options, lines): def _process_docstring(app, what, name, obj, options, lines):

View File

@ -246,4 +246,4 @@ def setup(app):
app.add_config_value('pngmath_latex_preamble', '', 'html') app.add_config_value('pngmath_latex_preamble', '', 'html')
app.add_config_value('pngmath_add_tooltips', True, 'html') app.add_config_value('pngmath_add_tooltips', True, 'html')
app.connect('build-finished', cleanup_tempdir) app.connect('build-finished', cleanup_tempdir)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -172,4 +172,4 @@ def setup(app):
app.connect('doctree-read', process_todos) app.connect('doctree-read', process_todos)
app.connect('doctree-resolved', process_todo_nodes) app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos) app.connect('env-purge-doc', purge_todos)
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -204,4 +204,4 @@ def setup(app):
app.connect('missing-reference', missing_reference) app.connect('missing-reference', missing_reference)
#app.add_config_value('viewcode_include_modules', [], 'env') #app.add_config_value('viewcode_include_modules', [], 'env')
#app.add_config_value('viewcode_exclude_modules', [], 'env') #app.add_config_value('viewcode_exclude_modules', [], 'env')
return sphinx.__version__ return {'version': sphinx.__version__}

View File

@ -205,7 +205,7 @@ def save_traceback(app):
if isinstance(modfile, bytes): if isinstance(modfile, bytes):
modfile = modfile.decode(fs_encoding, 'replace') modfile = modfile.decode(fs_encoding, 'replace')
os.write(fd, ('# %s (%s) from %s\n' % ( os.write(fd, ('# %s (%s) from %s\n' % (
extname, app._extension_versions[extname], extname, app._extension_metadata[extname]['version'],
modfile)).encode('utf-8')) modfile)).encode('utf-8'))
os.write(fd, exc.encode('utf-8')) os.write(fd, exc.encode('utf-8'))
os.close(fd) os.close(fd)