mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0'
This commit is contained in:
commit
01f46111c5
10
CHANGES
10
CHANGES
@ -48,6 +48,13 @@ Features added
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #6096: html: Anchor links are not added to figures
|
||||
* #3620: html: Defer searchindex.js rather than loading it via ajax
|
||||
* #6113: html: Table cells and list items have large margins
|
||||
* #5508: ``linenothreshold`` option for ``highlight`` directive was ignored
|
||||
* texinfo: ``make install-info`` causes syntax error
|
||||
* texinfo: ``make install-info`` fails on macOS
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
@ -312,9 +319,12 @@ Bugs fixed
|
||||
* LaTeX: Remove extraneous space after author names on PDF title page (refs: #6004)
|
||||
* #6026: LaTeX: A cross reference to definition list does not work
|
||||
* #6046: LaTeX: ``TypeError`` is raised when invalid latex_elements given
|
||||
* #6067: LaTeX: images having a target are concatenated to next line
|
||||
* #6067: LaTeX: images having a target are not aligned even if specified
|
||||
* #6019: imgconverter: Including multipage PDF fails
|
||||
* #6047: autodoc: ``autofunction`` emits a warning for method objects
|
||||
* #6028: graphviz: Ensure the graphviz filenames are reproducible
|
||||
* #6068: doctest: ``skipif`` option may remove the code block from documentation
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -315,7 +315,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
There are also new config values that you can set:
|
||||
There are also config values that you can set:
|
||||
|
||||
.. confval:: autoclass_content
|
||||
|
||||
|
@ -131,7 +131,7 @@ Generating stub pages automatically
|
||||
-----------------------------------
|
||||
|
||||
If you do not want to create stub pages with :program:`sphinx-autogen`, you can
|
||||
also use this new config value:
|
||||
also use these config values:
|
||||
|
||||
.. confval:: autosummary_generate
|
||||
|
||||
|
@ -13,7 +13,7 @@ This extension features one additional builder, the :class:`CoverageBuilder`.
|
||||
|
||||
.. todo:: Write this section.
|
||||
|
||||
Several new configuration values can be used to specify what the builder
|
||||
Several configuration values can be used to specify what the builder
|
||||
should check:
|
||||
|
||||
.. confval:: coverage_ignore_modules
|
||||
|
@ -18,7 +18,7 @@ tracker, at :samp:`https://github.com/sphinx-doc/sphinx/issues/{num}`. Typing
|
||||
this URL again and again is tedious, so you can use :mod:`~sphinx.ext.extlinks`
|
||||
to avoid repeating yourself.
|
||||
|
||||
The extension adds one new config value:
|
||||
The extension adds a config value:
|
||||
|
||||
.. confval:: extlinks
|
||||
|
||||
|
@ -90,7 +90,7 @@ It adds these directives:
|
||||
.. versionadded:: 1.6
|
||||
All three directives support a ``name`` option to set the label to graph.
|
||||
|
||||
There are also these new config values:
|
||||
There are also these config values:
|
||||
|
||||
.. confval:: graphviz_dot
|
||||
|
||||
|
@ -43,7 +43,7 @@ Configuration
|
||||
-------------
|
||||
|
||||
To use Intersphinx linking, add ``'sphinx.ext.intersphinx'`` to your
|
||||
:confval:`extensions` config value, and use these new config values to activate
|
||||
:confval:`extensions` config value, and use these config values to activate
|
||||
linking:
|
||||
|
||||
.. confval:: intersphinx_mapping
|
||||
|
@ -154,8 +154,8 @@ class CodeBlock(SphinxDirective):
|
||||
code = '\n'.join(lines)
|
||||
|
||||
literal = nodes.literal_block(code, code) # type: nodes.Element
|
||||
literal['linenos'] = 'linenos' in self.options or \
|
||||
'lineno-start' in self.options
|
||||
if 'linenos' in self.options or 'lineno-start' in self.options:
|
||||
literal['linenos'] = True
|
||||
literal['classes'] += self.options.get('class', [])
|
||||
if self.arguments:
|
||||
# highlight language specified
|
||||
@ -451,9 +451,9 @@ class LiteralInclude(SphinxDirective):
|
||||
retnode['language'] = 'udiff'
|
||||
elif 'language' in self.options:
|
||||
retnode['language'] = self.options['language']
|
||||
retnode['linenos'] = ('linenos' in self.options or
|
||||
'lineno-start' in self.options or
|
||||
'lineno-match' in self.options)
|
||||
if ('linenos' in self.options or 'lineno-start' in self.options or
|
||||
'lineno-match' in self.options):
|
||||
retnode['linenos'] = True
|
||||
retnode['classes'] += self.options.get('class', [])
|
||||
extra_args = retnode['highlight_args'] = {}
|
||||
if 'emphasize-lines' in self.options:
|
||||
|
@ -83,16 +83,6 @@ class TestDirective(SphinxDirective):
|
||||
|
||||
def run(self):
|
||||
# type: () -> List[nodes.Node]
|
||||
if 'skipif' in self.options:
|
||||
condition = self.options['skipif']
|
||||
context = {} # type: Dict[str, Any]
|
||||
if self.config.doctest_global_setup:
|
||||
exec(self.config.doctest_global_setup, context)
|
||||
should_skip = eval(condition, context)
|
||||
if self.config.doctest_global_cleanup:
|
||||
exec(self.config.doctest_global_cleanup, context)
|
||||
if should_skip:
|
||||
return []
|
||||
# use ordinary docutils nodes for test code: they get special attributes
|
||||
# so that our builder recognizes them, and the other builders are happy.
|
||||
code = '\n'.join(self.content)
|
||||
@ -160,6 +150,8 @@ class TestDirective(SphinxDirective):
|
||||
self.state.document.reporter.warning(
|
||||
__("'%s' is not a valid pyversion option") % spec,
|
||||
line=self.lineno)
|
||||
if 'skipif' in self.options:
|
||||
node['skipif'] = self.options['skipif']
|
||||
return [node]
|
||||
|
||||
|
||||
@ -404,6 +396,20 @@ Doctest summary
|
||||
return node.line - 1
|
||||
return None
|
||||
|
||||
def skipped(self, node):
|
||||
# type: (nodes.Element) -> bool
|
||||
if 'skipif' not in node:
|
||||
return False
|
||||
else:
|
||||
condition = node['skipif']
|
||||
context = {} # type: Dict[str, Any]
|
||||
if self.config.doctest_global_setup:
|
||||
exec(self.config.doctest_global_setup, context)
|
||||
should_skip = eval(condition, context)
|
||||
if self.config.doctest_global_cleanup:
|
||||
exec(self.config.doctest_global_cleanup, context)
|
||||
return should_skip
|
||||
|
||||
def test_doc(self, docname, doctree):
|
||||
# type: (str, nodes.Node) -> None
|
||||
groups = {} # type: Dict[str, TestGroup]
|
||||
@ -429,8 +435,10 @@ Doctest summary
|
||||
# type: (nodes.Node) -> bool
|
||||
return isinstance(node, (nodes.literal_block, nodes.comment)) \
|
||||
and 'testnodetype' in node
|
||||
|
||||
for node in doctree.traverse(condition): # type: nodes.Element
|
||||
if self.skipped(node):
|
||||
continue
|
||||
|
||||
source = node['test'] if 'test' in node else node.astext()
|
||||
filename = self.get_filename_for_node(node, docname)
|
||||
line_number = self.get_line_number(node)
|
||||
|
@ -17,15 +17,16 @@ html: $(addsuffix .html,$(ALLDOCS))
|
||||
pdf: $(addsuffix .pdf,$(ALLDOCS))
|
||||
|
||||
install-info: info
|
||||
for f in *.info; do \\
|
||||
cp -t $(infodir) "$$f" && \\
|
||||
$(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \\
|
||||
for f in *.info; do \
|
||||
mkdir -p $(infodir) && \
|
||||
cp "$$f" $(infodir) && \
|
||||
$(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \
|
||||
done
|
||||
|
||||
uninstall-info: info
|
||||
for f in *.info; do \\
|
||||
rm -f "$(infodir)/$$f" ; \\
|
||||
$(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \\
|
||||
for f in *.info; do \
|
||||
rm -f "$(infodir)/$$f" ; \
|
||||
$(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \
|
||||
done
|
||||
|
||||
%.info: %.texi
|
||||
|
@ -14,12 +14,7 @@
|
||||
<script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script>
|
||||
{%- endblock %}
|
||||
{% block extrahead %}
|
||||
<script type="text/javascript">
|
||||
jQuery(function() { Search.loadIndex("{{ pathto('searchindex.js', 1) }}"); });
|
||||
</script>
|
||||
{# this is used when loading the search index using $.ajax fails,
|
||||
such as on Chrome for documents on localhost #}
|
||||
<script type="text/javascript" id="searchindexloader"></script>
|
||||
<script type="text/javascript" src="{{ pathto('searchindex.js', 1) }}" defer></script>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
|
@ -401,11 +401,13 @@ table.citation td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
th > p:first-child,
|
||||
td > p:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
td > p:only-child {
|
||||
th > p:last-child,
|
||||
td > p:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
@ -482,7 +484,7 @@ li > p:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
li > p:only-child {
|
||||
li > p:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
|
@ -75,16 +75,6 @@ var Search = {
|
||||
}
|
||||
},
|
||||
|
||||
loadIndex : function(url) {
|
||||
$.ajax({type: "GET", url: url, data: null,
|
||||
dataType: "script", cache: true,
|
||||
complete: function(jqxhr, textstatus) {
|
||||
if (textstatus != "success") {
|
||||
document.getElementById("searchindexloader").src = url;
|
||||
}
|
||||
}});
|
||||
},
|
||||
|
||||
setIndex : function(index) {
|
||||
var q;
|
||||
this._index = index;
|
||||
|
@ -509,9 +509,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
|
||||
self.add_permalink_ref(node.parent, _('Permalink to this code'))
|
||||
elif isinstance(node.parent, nodes.figure):
|
||||
image_nodes = node.parent.traverse(nodes.image)
|
||||
target_node = image_nodes and image_nodes[0] or node.parent
|
||||
self.add_permalink_ref(target_node, _('Permalink to this image'))
|
||||
self.add_permalink_ref(node.parent, _('Permalink to this image'))
|
||||
elif node.parent.get('toctree'):
|
||||
self.add_permalink_ref(node.parent.parent, _('Permalink to this toctree'))
|
||||
|
||||
|
@ -455,9 +455,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
||||
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
|
||||
self.add_permalink_ref(node.parent, _('Permalink to this code'))
|
||||
elif isinstance(node.parent, nodes.figure):
|
||||
image_nodes = node.parent.traverse(nodes.image)
|
||||
target_node = image_nodes and image_nodes[0] or node.parent
|
||||
self.add_permalink_ref(target_node, _('Permalink to this image'))
|
||||
self.add_permalink_ref(node.parent, _('Permalink to this image'))
|
||||
elif node.parent.get('toctree'):
|
||||
self.add_permalink_ref(node.parent.parent, _('Permalink to this toctree'))
|
||||
|
||||
|
@ -1533,7 +1533,11 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
# in reverse order
|
||||
post = [] # type: List[str]
|
||||
include_graphics_options = []
|
||||
is_inline = self.is_inline(node)
|
||||
has_hyperlink = isinstance(node.parent, nodes.reference)
|
||||
if has_hyperlink:
|
||||
is_inline = self.is_inline(node.parent)
|
||||
else:
|
||||
is_inline = self.is_inline(node)
|
||||
if 'width' in attrs:
|
||||
if 'scale' in attrs:
|
||||
w = self.latex_image_length(attrs['width'], attrs['scale'])
|
||||
@ -1575,7 +1579,7 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
if self.in_parsed_literal:
|
||||
pre.append('{\\sphinxunactivateextrasandspace ')
|
||||
post.append('}')
|
||||
if not is_inline:
|
||||
if not is_inline and not has_hyperlink:
|
||||
pre.append('\n\\noindent')
|
||||
post.append('\n')
|
||||
pre.reverse()
|
||||
@ -1863,6 +1867,8 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
for id in node.get('ids'):
|
||||
anchor = not self.in_caption
|
||||
self.body += self.hypertarget(id, anchor=anchor)
|
||||
if not self.is_inline(node):
|
||||
self.body.append('\n')
|
||||
uri = node.get('refuri', '')
|
||||
if not uri and node.get('refid'):
|
||||
uri = '%' + self.curfilestack[-1] + '#' + node['refid']
|
||||
@ -1916,6 +1922,8 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
def depart_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
self.body.append(self.context.pop())
|
||||
if not self.is_inline(node):
|
||||
self.body.append('\n')
|
||||
|
||||
def visit_number_reference(self, node):
|
||||
# type: (nodes.Element) -> None
|
||||
|
23
tests/roots/test-directive-code/linenothreshold.rst
Normal file
23
tests/roots/test-directive-code/linenothreshold.rst
Normal file
@ -0,0 +1,23 @@
|
||||
Code Blocks and Literal Includes with Line Numbers via linenothreshold
|
||||
======================================================================
|
||||
|
||||
.. highlight:: python
|
||||
:linenothreshold: 5
|
||||
|
||||
.. code-block::
|
||||
|
||||
class Foo:
|
||||
pass
|
||||
|
||||
class Bar:
|
||||
def baz():
|
||||
pass
|
||||
|
||||
.. code-block::
|
||||
|
||||
# comment
|
||||
value = True
|
||||
|
||||
.. literalinclude:: literal.inc
|
||||
|
||||
.. literalinclude:: literal-short.inc
|
3
tests/roots/test-directive-code/literal-short.inc
Normal file
3
tests/roots/test-directive-code/literal-short.inc
Normal file
@ -0,0 +1,3 @@
|
||||
# Very small literal include (linenothreshold check)
|
||||
|
||||
value = True
|
@ -15,6 +15,13 @@ test-image
|
||||
|
||||
.. image:: testimäge.png
|
||||
|
||||
.. image:: rimg.png
|
||||
:target: https://www.sphinx-doc.org/
|
||||
|
||||
.. image:: rimg.png
|
||||
:align: center
|
||||
:target: https://www.python.org/
|
||||
|
||||
.. a remote image
|
||||
.. image:: https://www.python.org/static/img/python-logo.png
|
||||
|
||||
|
@ -1254,6 +1254,15 @@ def test_html_inventory(app):
|
||||
'The basic Sphinx documentation for testing')
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='images', confoverrides={'html_sourcelink_suffix': ''})
|
||||
def test_html_anchor_for_figure(app):
|
||||
app.builder.build_all()
|
||||
content = (app.outdir / 'index.html').text()
|
||||
assert ('<p class="caption"><span class="caption-text">The caption of pic</span>'
|
||||
'<a class="headerlink" href="#id1" title="Permalink to this image">¶</a></p>'
|
||||
in content)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='directives-raw')
|
||||
def test_html_raw_directive(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
@ -1220,16 +1220,28 @@ def test_latex_raw_directive(app, status, warning):
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='images')
|
||||
def test_latex_remote_images(app, status, warning):
|
||||
def test_latex_images(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
result = (app.outdir / 'python.tex').text(encoding='utf8')
|
||||
|
||||
# images are copied
|
||||
assert '\\sphinxincludegraphics{{python-logo}.png}' in result
|
||||
assert (app.outdir / 'python-logo.png').exists()
|
||||
|
||||
# not found images
|
||||
assert '\\sphinxincludegraphics{{NOT_EXIST}.PNG}' not in result
|
||||
assert ('WARNING: Could not fetch remote image: '
|
||||
'http://example.com/NOT_EXIST.PNG [404]' in warning.getvalue())
|
||||
|
||||
# an image having target
|
||||
assert ('\\sphinxhref{https://www.sphinx-doc.org/}'
|
||||
'{\\sphinxincludegraphics{{rimg}.png}}\n\n' in result)
|
||||
|
||||
# a centerized image having target
|
||||
assert ('\\sphinxhref{https://www.python.org/}{{\\hspace*{\\fill}'
|
||||
'\\sphinxincludegraphics{{rimg}.png}\\hspace*{\\fill}}}\n\n' in result)
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='latex-index')
|
||||
def test_latex_index(app, status, warning):
|
||||
|
@ -565,3 +565,52 @@ def test_code_block_highlighted(app, status, warning):
|
||||
assert codeblocks[1]['language'] == 'python2'
|
||||
assert codeblocks[2]['language'] == 'python3'
|
||||
assert codeblocks[3]['language'] == 'python2'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='directive-code')
|
||||
def test_linenothreshold(app, status, warning):
|
||||
app.builder.build(['linenothreshold'])
|
||||
html = (app.outdir / 'linenothreshold.html').text()
|
||||
|
||||
lineos_head = '<td class="linenos"><div class="linenodiv"><pre>'
|
||||
lineos_tail = '</pre></div></td>'
|
||||
|
||||
# code-block using linenothreshold
|
||||
_, matched, html = html.partition(lineos_head +
|
||||
'1\n'
|
||||
'2\n'
|
||||
'3\n'
|
||||
'4\n'
|
||||
'5\n'
|
||||
'6' + lineos_tail)
|
||||
assert matched
|
||||
|
||||
# code-block not using linenothreshold
|
||||
html, matched, _ = html.partition(lineos_head +
|
||||
'1\n'
|
||||
'2' + lineos_tail)
|
||||
assert not matched
|
||||
|
||||
# literal include using linenothreshold
|
||||
_, matched, html = html.partition(lineos_head +
|
||||
' 1\n'
|
||||
' 2\n'
|
||||
' 3\n'
|
||||
' 4\n'
|
||||
' 5\n'
|
||||
' 6\n'
|
||||
' 7\n'
|
||||
' 8\n'
|
||||
' 9\n'
|
||||
'10\n'
|
||||
'11\n'
|
||||
'12\n'
|
||||
'13' + lineos_tail)
|
||||
assert matched
|
||||
|
||||
# literal include not using linenothreshold
|
||||
html, matched, _ = html.partition(lineos_head +
|
||||
'1\n'
|
||||
'2\n'
|
||||
'3' + lineos_tail)
|
||||
assert not matched
|
||||
|
@ -9,7 +9,6 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
@ -152,9 +151,8 @@ def test_expressions():
|
||||
exprCheck(p + "'\\x0A'", t + "10")
|
||||
exprCheck(p + "'\\u0a42'", t + "2626")
|
||||
exprCheck(p + "'\\u0A42'", t + "2626")
|
||||
if sys.maxunicode > 65535:
|
||||
exprCheck(p + "'\\U0001f34c'", t + "127820")
|
||||
exprCheck(p + "'\\U0001F34C'", t + "127820")
|
||||
exprCheck(p + "'\\U0001f34c'", t + "127820")
|
||||
exprCheck(p + "'\\U0001F34C'", t + "127820")
|
||||
|
||||
# TODO: user-defined lit
|
||||
exprCheck('(... + Ns)', '(... + Ns)', id4='flpl2Ns')
|
||||
|
Loading…
Reference in New Issue
Block a user