quickstart: Rework how we collect extensions

This is a little more flexible than the existing set up and makes
maximum use of argparse capabilities.

This has the side-effect of no longer including configuration for the
'sphinx.ext.todo' extension when said extension is not enabled.

Signed-off-by: Stephen Finucane <stephen@that.guru>
This commit is contained in:
Stephen Finucane 2017-10-21 13:48:27 +01:00
parent 4c0f657ee6
commit d46273ca4a
4 changed files with 67 additions and 78 deletions

View File

@ -16,6 +16,7 @@ import os
import re import re
import sys import sys
import time import time
from collections import OrderedDict
from io import open from io import open
from os import path from os import path
@ -48,7 +49,22 @@ if False:
TERM_ENCODING = getattr(sys.stdin, 'encoding', None) TERM_ENCODING = getattr(sys.stdin, 'encoding', None)
DEFAULT_VALUE = { EXTENSIONS = OrderedDict([
('autodoc', 'automatically insert docstrings from modules'),
('doctest', 'automatically test code snippets in doctest blocks'),
('intersphinx', 'link between Sphinx documentation of different projects'),
('todo', 'write "todo" entries that can be shown or hidden on build'),
('coverage', 'checks for documentation coverage'),
('imgmath', 'include math, rendered as PNG or SVG images'),
('mathjax', 'include math, rendered in the browser by MathJax'),
('ifconfig', 'conditional inclusion of content based on config values'),
('viewcode',
'include links to the source code of documented Python objects'),
('githubpages',
'create .nojekyll file to publish the document on GitHub pages'),
])
DEFAULTS = {
'path': '.', 'path': '.',
'sep': False, 'sep': False,
'dot': '_', 'dot': '_',
@ -56,16 +72,10 @@ DEFAULT_VALUE = {
'suffix': '.rst', 'suffix': '.rst',
'master': 'index', 'master': 'index',
'epub': False, 'epub': False,
'ext_autodoc': False,
'ext_doctest': False,
'ext_todo': False,
'makefile': True, 'makefile': True,
'batchfile': True, 'batchfile': True,
} }
EXTENSIONS = ('autodoc', 'doctest', 'intersphinx', 'todo', 'coverage',
'imgmath', 'mathjax', 'ifconfig', 'viewcode', 'githubpages')
PROMPT_PREFIX = '> ' PROMPT_PREFIX = '> '
@ -235,7 +245,7 @@ def ask_user(d):
* suffix: source file suffix * suffix: source file suffix
* master: master document name * master: master document name
* epub: use epub (bool) * epub: use epub (bool)
* ext_*: extensions to use (bools) * extensions: extensions to use (list)
* makefile: make Makefile * makefile: make Makefile
* batchfile: make command file * batchfile: make command file
""" """
@ -341,46 +351,20 @@ Sphinx can also add configuration for epub output:''')
d['epub'] = do_prompt('Do you want to use the epub builder (y/n)', d['epub'] = do_prompt('Do you want to use the epub builder (y/n)',
'n', boolean) 'n', boolean)
if 'ext_autodoc' not in d: if 'extensions' not in d:
print(''' print('Indicate which of the following Sphinx extensions should be '
Please indicate if you want to use one of the following Sphinx extensions:''') 'enabled:')
d['ext_autodoc'] = do_prompt('autodoc: automatically insert docstrings ' d['extensions'] = []
'from modules (y/n)', 'n', boolean) for name, description in EXTENSIONS.items():
if 'ext_doctest' not in d: if do_prompt('%s: %s (y/n)' % (name, description), 'n', boolean):
d['ext_doctest'] = do_prompt('doctest: automatically test code snippets ' d['extensions'].append('sphinx.ext.%s' % name)
'in doctest blocks (y/n)', 'n', boolean)
if 'ext_intersphinx' not in d: # Handle conflicting options
d['ext_intersphinx'] = do_prompt('intersphinx: link between Sphinx ' if set(['sphinx.ext.imgmath', 'sphinx.ext.mathjax']).issubset(
'documentation of different projects (y/n)', d['extensions']):
'n', boolean) print('Note: imgmath and mathjax cannot be enabled at the same '
if 'ext_todo' not in d: 'time. imgmath has been deselected.')
d['ext_todo'] = do_prompt('todo: write "todo" entries that can be ' d['extensions'].remove('sphinx.ext.imgmath')
'shown or hidden on build (y/n)', 'n', boolean)
if 'ext_coverage' not in d:
d['ext_coverage'] = do_prompt('coverage: checks for documentation '
'coverage (y/n)', 'n', boolean)
if 'ext_imgmath' not in d:
d['ext_imgmath'] = do_prompt('imgmath: include math, rendered as PNG '
'or SVG images (y/n)', 'n', boolean)
if 'ext_mathjax' not in d:
d['ext_mathjax'] = do_prompt('mathjax: include math, rendered in the '
'browser by MathJax (y/n)', 'n', boolean)
if d['ext_imgmath'] and d['ext_mathjax']:
print('''Note: imgmath and mathjax cannot be enabled at the same time.
imgmath has been deselected.''')
d['ext_imgmath'] = False
if 'ext_ifconfig' not in d:
d['ext_ifconfig'] = do_prompt('ifconfig: conditional inclusion of '
'content based on config values (y/n)',
'n', boolean)
if 'ext_viewcode' not in d:
d['ext_viewcode'] = do_prompt('viewcode: include links to the source '
'code of documented Python objects (y/n)',
'n', boolean)
if 'ext_githubpages' not in d:
d['ext_githubpages'] = do_prompt('githubpages: create .nojekyll file '
'to publish the document on GitHub '
'pages (y/n)', 'n', boolean)
if 'makefile' not in d: if 'makefile' not in d:
print(''' print('''
@ -401,7 +385,6 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
template = QuickstartRenderer(templatedir=templatedir) template = QuickstartRenderer(templatedir=templatedir)
texescape.init() texescape.init()
indent = ' ' * 4
if 'mastertoctree' not in d: if 'mastertoctree' not in d:
d['mastertoctree'] = '' d['mastertoctree'] = ''
@ -415,10 +398,6 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
d['now'] = time.asctime() d['now'] = time.asctime()
d['project_underline'] = column_width(d['project']) * '=' d['project_underline'] = column_width(d['project']) * '='
d.setdefault('extensions', []) d.setdefault('extensions', [])
for name in EXTENSIONS:
if d.get('ext_' + name):
d['extensions'].append('sphinx.ext.' + name)
d['extensions'] = (',\n' + indent).join(repr(name) for name in d['extensions'])
d['copyright'] = time.strftime('%Y') + ', ' + d['author'] d['copyright'] = time.strftime('%Y') + ', ' + d['author']
d['author_texescaped'] = text_type(d['author']).\ d['author_texescaped'] = text_type(d['author']).\
translate(texescape.tex_escape_map) translate(texescape.tex_escape_map)
@ -588,11 +567,11 @@ Makefile to be used with sphinx-build.
group = parser.add_argument_group('Extension options') group = parser.add_argument_group('Extension options')
for ext in EXTENSIONS: for ext in EXTENSIONS:
group.add_argument('--ext-' + ext, action='store_true', group.add_argument('--ext-%s' % ext, action='append_const',
dest='ext_' + ext, default=False, const='sphinx.ext.%s' % ext, dest='extensions',
help='enable %s extension' % ext) help='enable %s extension' % ext)
group.add_argument('--extensions', metavar='EXTENSIONS', dest='extensions', group.add_argument('--extensions', metavar='EXTENSIONS', dest='extensions',
action='append', help='enable extensions') action='append', help='enable arbitrary extensions')
group = parser.add_argument_group('Makefile and Batchfile creation') group = parser.add_argument_group('Makefile and Batchfile creation')
group.add_argument('--makefile', action='store_true', dest='makefile', group.add_argument('--makefile', action='store_true', dest='makefile',
@ -649,8 +628,7 @@ def main(argv=sys.argv[1:]):
# quiet mode with all required params satisfied, use default # quiet mode with all required params satisfied, use default
d.setdefault('version', '') d.setdefault('version', '')
d.setdefault('release', d['version']) d.setdefault('release', d['version'])
d2 = DEFAULT_VALUE.copy() d2 = DEFAULTS.copy()
d2.update(dict(("ext_" + ext, False) for ext in EXTENSIONS))
d2.update(d) d2.update(d)
d = d2 d = d2
@ -673,13 +651,12 @@ def main(argv=sys.argv[1:]):
if isinstance(value, binary_type): if isinstance(value, binary_type):
d[key] = term_decode(value) d[key] = term_decode(value)
# parse extensions list # handle use of CSV-style extension values
d.setdefault('extensions', []) d.setdefault('extensions', [])
for ext in d['extensions'][:]: for ext in d['extensions'][:]:
if ',' in ext: if ',' in ext:
d['extensions'].remove(ext) d['extensions'].remove(ext)
for modname in ext.split(','): d['extensions'].extend(ext.split(','))
d['extensions'].append(modname)
for variable in d.get('variables', []): for variable in d.get('variables', []):
try: try:

View File

@ -358,8 +358,8 @@ Note: By default this script will not overwrite already created files.""")
group = parser.add_argument_group('extension options') group = parser.add_argument_group('extension options')
for ext in EXTENSIONS: for ext in EXTENSIONS:
group.add_argument('--ext-' + ext, action='store_true', group.add_argument('--ext-%s' % ext, action='append_const',
dest='ext_' + ext, default=False, const='sphinx.ext.%s' % ext, dest='extensions',
help='enable %s extension' % ext) help='enable %s extension' % ext)
return parser return parser
@ -408,9 +408,8 @@ def main(argv=sys.argv[1:]):
suffix = '.' + args.suffix, suffix = '.' + args.suffix,
master = 'index', master = 'index',
epub = True, epub = True,
ext_autodoc = True, extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode',
ext_viewcode = True, 'sphinx.ext.todo'],
ext_todo = True,
makefile = True, makefile = True,
batchfile = True, batchfile = True,
make_mode = True, make_mode = True,
@ -420,9 +419,8 @@ def main(argv=sys.argv[1:]):
module_path = rootpath, module_path = rootpath,
append_syspath = args.append_syspath, append_syspath = args.append_syspath,
) )
enabled_exts = {'ext_' + ext: getattr(args, 'ext_' + ext) if args.extensions:
for ext in EXTENSIONS if getattr(args, 'ext_' + ext)} d['extensions'].extend(args.extensions)
d.update(enabled_exts)
if isinstance(args.header, binary_type): if isinstance(args.header, binary_type):
d['project'] = d['project'].decode('utf-8') d['project'] = d['project'].decode('utf-8')

View File

@ -42,7 +42,11 @@ sys.path.insert(0, u'{{ module_path }}')
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [{{ extensions }}] extensions = [
{%- for ext in extensions %}
'{{ ext }}',
{%- endfor %}
]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['{{ dot }}templates'] templates_path = ['{{ dot }}templates']
@ -85,9 +89,6 @@ exclude_patterns = [{{ exclude_patterns }}]
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx' pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = {{ ext_todo }}
# -- Options for HTML output ---------------------------------------------- # -- Options for HTML output ----------------------------------------------
@ -173,8 +174,8 @@ texinfo_documents = [
author, '{{ project_fn }}', 'One line description of project.', author, '{{ project_fn }}', 'One line description of project.',
'Miscellaneous'), 'Miscellaneous'),
] ]
{%- if epub %}
{% if epub %}
# -- Options for Epub output ---------------------------------------------- # -- Options for Epub output ----------------------------------------------
@ -195,9 +196,23 @@ epub_copyright = copyright
# A list of files that should not be packed into the epub file. # A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html'] epub_exclude_files = ['search.html']
{% endif %} {%- endif %}
{%- if extensions %}
# -- Extension configuration ----------------------------------------------
{%- endif %}
{%- if 'sphinx.ext.intersphinx' in extensions %}
# -- Options for intersphinx extension ------------------------------------
{% if ext_intersphinx %}
# Example configuration for intersphinx: refer to the Python standard library. # Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None} intersphinx_mapping = {'https://docs.python.org/': None}
{% endif %} {%- endif %}
{%- if 'sphinx.ext.todo' in extensions %}
# -- Options for todo extension -------------------------------------------
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
{%- endif %}

View File

@ -134,7 +134,6 @@ def test_quickstart_defaults(tempdir):
assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y') assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y')
assert ns['version'] == '0.1' assert ns['version'] == '0.1'
assert ns['release'] == '0.1' assert ns['release'] == '0.1'
assert ns['todo_include_todos'] is False
assert ns['html_static_path'] == ['_static'] assert ns['html_static_path'] == ['_static']
assert ns['latex_documents'] == [ assert ns['latex_documents'] == [
('index', 'SphinxTest.tex', 'Sphinx Test Documentation', ('index', 'SphinxTest.tex', 'Sphinx Test Documentation',