Merge branch '2.0' into 5602_apidoc_templating

This commit is contained in:
Takeshi KOMIYA 2019-06-18 21:42:11 +09:00 committed by GitHub
commit 45027677d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 23 deletions

View File

@ -27,12 +27,16 @@ Features added
--------------
* #5124: graphviz: ``:graphviz_dot:`` option is renamed to ``:layout:``
* #1464: html: emit a warning if :confval:`html_static_path` and
:confval:`html_extra_path` directories are inside output directory
* #5602: apidoc: Add ``--templatedir`` option
Bugs fixed
----------
* py domain: duplicated warning does not point the location of source code
* #6499: html: Sphinx never updates a copy of :confval:`html_logo` even if
original file has changed
* #1125: html theme: scrollbar is hard to see on classic theme and macOS
* #5502: linkcheck: Consider HTTP 503 response as not an error
* #6439: Make generated download links reproducible

View File

@ -783,29 +783,15 @@ class StandaloneHTMLBuilder(Builder):
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
for static_path in self.config.html_static_path:
entry = path.join(self.confdir, static_path)
if not path.exists(entry):
logger.warning(__('html_static_path entry %r does not exist'), entry)
continue
copy_asset(entry, path.join(self.outdir, '_static'), excluded,
context=ctx, renderer=self.templates)
# copy logo and favicon files if not already in static path
if self.config.html_logo:
logobase = path.basename(self.config.html_logo)
logotarget = path.join(self.outdir, '_static', logobase)
if not path.isfile(path.join(self.confdir, self.config.html_logo)):
logger.warning(__('logo file %r does not exist'), self.config.html_logo)
elif not path.isfile(logotarget):
copyfile(path.join(self.confdir, self.config.html_logo),
logotarget)
entry = path.join(self.confdir, self.config.html_logo)
copy_asset(entry, path.join(self.outdir, '_static'))
if self.config.html_favicon:
iconbase = path.basename(self.config.html_favicon)
icontarget = path.join(self.outdir, '_static', iconbase)
if not path.isfile(path.join(self.confdir, self.config.html_favicon)):
logger.warning(__('favicon file %r does not exist'),
self.config.html_favicon)
elif not path.isfile(icontarget):
copyfile(path.join(self.confdir, self.config.html_favicon),
icontarget)
entry = path.join(self.confdir, self.config.html_favicon)
copy_asset(entry, path.join(self.outdir, '_static'))
logger.info(__('done'))
except OSError as err:
logger.warning(__('cannot copy static file %r'), err)
@ -818,10 +804,6 @@ class StandaloneHTMLBuilder(Builder):
for extra_path in self.config.html_extra_path:
entry = path.join(self.confdir, extra_path)
if not path.exists(entry):
logger.warning(__('html_extra_path entry %r does not exist'), entry)
continue
copy_asset(entry, self.outdir, excluded)
logger.info(__('done'))
except OSError as err:
@ -1166,6 +1148,44 @@ def validate_math_renderer(app: Sphinx) -> None:
raise ConfigError(__('Unknown math_renderer %r is given.') % name)
def validate_html_extra_path(app: Sphinx, config: Config) -> None:
"""Check html_extra_paths setting."""
for entry in config.html_extra_path[:]:
extra_path = path.normpath(path.join(app.confdir, entry))
if not path.exists(extra_path):
logger.warning(__('html_extra_path entry %r does not exist'), entry)
config.html_extra_path.remove(entry)
elif path.commonpath([app.outdir, extra_path]) == app.outdir:
logger.warning(__('html_extra_path entry %r is placed inside outdir'), entry)
config.html_extra_path.remove(entry)
def validate_html_static_path(app: Sphinx, config: Config) -> None:
"""Check html_static_paths setting."""
for entry in config.html_static_path[:]:
static_path = path.normpath(path.join(app.confdir, entry))
if not path.exists(static_path):
logger.warning(__('html_static_path entry %r does not exist'), entry)
config.html_static_path.remove(entry)
elif path.commonpath([app.outdir, static_path]) == app.outdir:
logger.warning(__('html_static_path entry %r is placed inside outdir'), entry)
config.html_static_path.remove(entry)
def validate_html_logo(app: Sphinx, config: Config) -> None:
"""Check html_logo setting."""
if config.html_logo and not path.isfile(path.join(app.confdir, config.html_logo)):
logger.warning(__('logo file %r does not exist'), config.html_logo)
config.html_logo = None # type: ignore
def validate_html_favicon(app: Sphinx, config: Config) -> None:
"""Check html_favicon setting."""
if config.html_favicon and not path.isfile(path.join(app.confdir, config.html_favicon)):
logger.warning(__('favicon file %r does not exist'), config.html_favicon)
config.html_favicon = None # type: ignore
# for compatibility
import sphinx.builders.dirhtml # NOQA
import sphinx.builders.singlehtml # NOQA
@ -1221,6 +1241,10 @@ def setup(app: Sphinx) -> Dict[str, Any]:
# event handlers
app.connect('config-inited', convert_html_css_files)
app.connect('config-inited', convert_html_js_files)
app.connect('config-inited', validate_html_extra_path)
app.connect('config-inited', validate_html_static_path)
app.connect('config-inited', validate_html_logo)
app.connect('config-inited', validate_html_favicon)
app.connect('builder-inited', validate_math_renderer)
app.connect('html-page-context', setup_js_tag_helper)

View File

@ -16,6 +16,7 @@ from itertools import cycle, chain
import pytest
from html5lib import HTMLParser
from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
from sphinx.errors import ConfigError
from sphinx.testing.util import strip_escseq
from sphinx.util import docutils
@ -1496,3 +1497,29 @@ def test_html_pygments_style_manually(app):
def test_html_pygments_for_classic_theme(app):
style = app.builder.highlighter.formatter_args.get('style')
assert style.__name__ == 'SphinxStyle'
@pytest.mark.sphinx(testroot='basic', srcdir='validate_html_extra_path')
def test_validate_html_extra_path(app):
(app.confdir / '_static').makedirs()
app.config.html_extra_path = [
'/path/to/not_found', # not found
'_static',
app.outdir, # outdir
app.outdir / '_static', # inside outdir
]
validate_html_extra_path(app, app.config)
assert app.config.html_extra_path == ['_static']
@pytest.mark.sphinx(testroot='basic', srcdir='validate_html_static_path')
def test_validate_html_static_path(app):
(app.confdir / '_static').makedirs()
app.config.html_static_path = [
'/path/to/not_found', # not found
'_static',
app.outdir, # outdir
app.outdir / '_static', # inside outdir
]
validate_html_static_path(app, app.config)
assert app.config.html_static_path == ['_static']

View File

@ -13,7 +13,10 @@ from unittest import mock
from docutils import nodes
from docutils.nodes import definition, definition_list, definition_list_item, term
from sphinx.addnodes import glossary, index
from sphinx import addnodes
from sphinx.addnodes import (
desc, desc_addname, desc_content, desc_name, desc_signature, glossary, index
)
from sphinx.domains.std import StandardDomain
from sphinx.testing import restructuredtext
from sphinx.testing.util import assert_node
@ -239,3 +242,41 @@ def test_glossary_sorted(app):
[nodes.definition, nodes.paragraph, "description"])
assert_node(doctree[0][0][1][1],
[nodes.definition, nodes.paragraph, "description"])
def test_cmdoption(app):
text = (".. program:: ls\n"
"\n"
".. option:: -l\n")
domain = app.env.get_domain('std')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, (addnodes.index,
[desc, ([desc_signature, ([desc_name, "-l"],
[desc_addname, ()])],
[desc_content, ()])]))
assert_node(doctree[0], addnodes.index,
entries=[('pair', 'ls command line option; -l', 'cmdoption-ls-l', '', None)])
assert ('ls', '-l') in domain.progoptions
assert domain.progoptions[('ls', '-l')] == ('index', 'cmdoption-ls-l')
def test_multiple_cmdoptions(app):
text = (".. program:: ls\n"
"\n"
".. option:: -h, --help\n")
domain = app.env.get_domain('std')
doctree = restructuredtext.parse(app, text)
assert_node(doctree, (addnodes.index,
[desc, ([desc_signature, ([desc_name, "-h"],
[desc_addname, ()],
[desc_addname, ", "],
[desc_name, "--help"],
[desc_addname, ()])],
[desc_content, ()])]))
assert_node(doctree[0], addnodes.index,
entries=[('pair', 'ls command line option; -h, --help',
'cmdoption-ls-h', '', None)])
assert ('ls', '-h') in domain.progoptions
assert ('ls', '--help') in domain.progoptions
assert domain.progoptions[('ls', '-h')] == ('index', 'cmdoption-ls-h')
assert domain.progoptions[('ls', '--help')] == ('index', 'cmdoption-ls-h')