mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0' into 5602_apidoc_templating
This commit is contained in:
commit
45027677d1
4
CHANGES
4
CHANGES
@ -27,12 +27,16 @@ Features added
|
|||||||
--------------
|
--------------
|
||||||
|
|
||||||
* #5124: graphviz: ``:graphviz_dot:`` option is renamed to ``:layout:``
|
* #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
|
* #5602: apidoc: Add ``--templatedir`` option
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* py domain: duplicated warning does not point the location of source code
|
* 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
|
* #1125: html theme: scrollbar is hard to see on classic theme and macOS
|
||||||
* #5502: linkcheck: Consider HTTP 503 response as not an error
|
* #5502: linkcheck: Consider HTTP 503 response as not an error
|
||||||
* #6439: Make generated download links reproducible
|
* #6439: Make generated download links reproducible
|
||||||
|
@ -783,29 +783,15 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
|
excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
|
||||||
for static_path in self.config.html_static_path:
|
for static_path in self.config.html_static_path:
|
||||||
entry = path.join(self.confdir, 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,
|
copy_asset(entry, path.join(self.outdir, '_static'), excluded,
|
||||||
context=ctx, renderer=self.templates)
|
context=ctx, renderer=self.templates)
|
||||||
# copy logo and favicon files if not already in static path
|
# copy logo and favicon files if not already in static path
|
||||||
if self.config.html_logo:
|
if self.config.html_logo:
|
||||||
logobase = path.basename(self.config.html_logo)
|
entry = path.join(self.confdir, self.config.html_logo)
|
||||||
logotarget = path.join(self.outdir, '_static', logobase)
|
copy_asset(entry, path.join(self.outdir, '_static'))
|
||||||
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)
|
|
||||||
if self.config.html_favicon:
|
if self.config.html_favicon:
|
||||||
iconbase = path.basename(self.config.html_favicon)
|
entry = path.join(self.confdir, self.config.html_favicon)
|
||||||
icontarget = path.join(self.outdir, '_static', iconbase)
|
copy_asset(entry, path.join(self.outdir, '_static'))
|
||||||
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)
|
|
||||||
logger.info(__('done'))
|
logger.info(__('done'))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
logger.warning(__('cannot copy static file %r'), 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:
|
for extra_path in self.config.html_extra_path:
|
||||||
entry = path.join(self.confdir, 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)
|
copy_asset(entry, self.outdir, excluded)
|
||||||
logger.info(__('done'))
|
logger.info(__('done'))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
@ -1166,6 +1148,44 @@ def validate_math_renderer(app: Sphinx) -> None:
|
|||||||
raise ConfigError(__('Unknown math_renderer %r is given.') % name)
|
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
|
# for compatibility
|
||||||
import sphinx.builders.dirhtml # NOQA
|
import sphinx.builders.dirhtml # NOQA
|
||||||
import sphinx.builders.singlehtml # NOQA
|
import sphinx.builders.singlehtml # NOQA
|
||||||
@ -1221,6 +1241,10 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
|||||||
# event handlers
|
# event handlers
|
||||||
app.connect('config-inited', convert_html_css_files)
|
app.connect('config-inited', convert_html_css_files)
|
||||||
app.connect('config-inited', convert_html_js_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('builder-inited', validate_math_renderer)
|
||||||
app.connect('html-page-context', setup_js_tag_helper)
|
app.connect('html-page-context', setup_js_tag_helper)
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ from itertools import cycle, chain
|
|||||||
import pytest
|
import pytest
|
||||||
from html5lib import HTMLParser
|
from html5lib import HTMLParser
|
||||||
|
|
||||||
|
from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
|
||||||
from sphinx.errors import ConfigError
|
from sphinx.errors import ConfigError
|
||||||
from sphinx.testing.util import strip_escseq
|
from sphinx.testing.util import strip_escseq
|
||||||
from sphinx.util import docutils
|
from sphinx.util import docutils
|
||||||
@ -1496,3 +1497,29 @@ def test_html_pygments_style_manually(app):
|
|||||||
def test_html_pygments_for_classic_theme(app):
|
def test_html_pygments_for_classic_theme(app):
|
||||||
style = app.builder.highlighter.formatter_args.get('style')
|
style = app.builder.highlighter.formatter_args.get('style')
|
||||||
assert style.__name__ == 'SphinxStyle'
|
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']
|
||||||
|
@ -13,7 +13,10 @@ from unittest import mock
|
|||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.nodes import definition, definition_list, definition_list_item, term
|
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.domains.std import StandardDomain
|
||||||
from sphinx.testing import restructuredtext
|
from sphinx.testing import restructuredtext
|
||||||
from sphinx.testing.util import assert_node
|
from sphinx.testing.util import assert_node
|
||||||
@ -239,3 +242,41 @@ def test_glossary_sorted(app):
|
|||||||
[nodes.definition, nodes.paragraph, "description"])
|
[nodes.definition, nodes.paragraph, "description"])
|
||||||
assert_node(doctree[0][0][1][1],
|
assert_node(doctree[0][0][1][1],
|
||||||
[nodes.definition, nodes.paragraph, "description"])
|
[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')
|
||||||
|
Loading…
Reference in New Issue
Block a user