mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge with '87998df9cbef2380345d436121e6bca43345d2bd' on stable
Conflicts: tests/test_build_latex.py
This commit is contained in:
commit
e5860fd75c
8
CHANGES
8
CHANGES
@ -68,6 +68,14 @@ Bugs fixed
|
||||
* #1237: Fix footnotes not working in definition list in LaTeX
|
||||
* #2168: Fix raw directive does not work for text writer
|
||||
* #2171: Fix cannot linkcheck url with unicode
|
||||
* #2182: LaTeX: support image file names with more than 1 dots
|
||||
* #2189: Fix previous sibling link for first file in subdirectory uses last file, not intended previous from root toctree
|
||||
* #2003: Fix decode error under python2 (only) when ``make linkcheck`` is run
|
||||
* #2186: Fix LaTeX output of \mathbb in math
|
||||
* #1480, #2188: LaTeX: Support math in section titles
|
||||
* #2071: Fix same footnote in more than two section titles => LaTeX/PDF Bug
|
||||
* #2040: Fix UnicodeDecodeError in sphinx-apidoc when author contains non-ascii characters
|
||||
* #2193: Fix shutil.SameFileError if source directory and destination directory are same
|
||||
|
||||
|
||||
Release 1.3.3 (released Dec 2, 2015)
|
||||
|
@ -15,11 +15,7 @@ a highlighted version of the source code, and a link will be added to all object
|
||||
descriptions that leads to the source code of the described object. A link back
|
||||
from the source to the description will also be inserted.
|
||||
|
||||
There are currently no configuration values for this extension; you just need to
|
||||
add ``'sphinx.ext.viewcode'`` to your :confval:`extensions` value for it to
|
||||
work.
|
||||
|
||||
There is also an additional config value:
|
||||
There is an additional config value:
|
||||
|
||||
.. confval:: viewcode_import
|
||||
|
||||
|
@ -20,6 +20,7 @@ import os
|
||||
import sys
|
||||
import optparse
|
||||
from os import path
|
||||
from six import binary_type
|
||||
|
||||
from sphinx.util.osutil import walk
|
||||
from sphinx import __display_version__
|
||||
@ -369,6 +370,15 @@ Note: By default this script will not overwrite already created files.""")
|
||||
mastertoctree = text,
|
||||
language = 'en',
|
||||
)
|
||||
if isinstance(opts.header, binary_type):
|
||||
d['project'] = d['project'].decode('utf-8')
|
||||
if isinstance(opts.author, binary_type):
|
||||
d['author'] = d['author'].decode('utf-8')
|
||||
if isinstance(opts.version, binary_type):
|
||||
d['version'] = d['version'].decode('utf-8')
|
||||
if isinstance(opts.release, binary_type):
|
||||
d['release'] = d['release'].decode('utf-8')
|
||||
|
||||
if not opts.dryrun:
|
||||
qs.generate(d, silent=True, overwrite=opts.force)
|
||||
elif not opts.notoc:
|
||||
|
@ -95,6 +95,17 @@ def check_anchor(f, hash):
|
||||
return parser.found
|
||||
|
||||
|
||||
def get_content_charset(f):
|
||||
content_type = f.headers.get('content-type')
|
||||
if content_type:
|
||||
params = (p.strip() for p in content_type.split(';')[1:])
|
||||
for param in params:
|
||||
if param.startswith('charset='):
|
||||
return param[8:]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class CheckExternalLinksBuilder(Builder):
|
||||
"""
|
||||
Checks for broken external links.
|
||||
@ -165,6 +176,8 @@ class CheckExternalLinksBuilder(Builder):
|
||||
encoding = 'utf-8'
|
||||
if hasattr(f.headers, 'get_content_charset'):
|
||||
encoding = f.headers.get_content_charset() or encoding
|
||||
else:
|
||||
encoding = get_content_charset(f) or encoding
|
||||
found = check_anchor(TextIOWrapper(f, encoding), unquote(hash))
|
||||
f.close()
|
||||
|
||||
|
@ -144,6 +144,10 @@ def main(argv):
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
outdir = abspath(args[1])
|
||||
if srcdir == outdir:
|
||||
print('Error: source directory and destination directory are same.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
except IndexError:
|
||||
parser.print_help()
|
||||
return 1
|
||||
|
@ -23,8 +23,8 @@ from os import path
|
||||
from glob import glob
|
||||
from itertools import groupby
|
||||
|
||||
from six import iteritems, itervalues, text_type, class_types, string_types
|
||||
from six.moves import cPickle as pickle, zip
|
||||
from six import iteritems, itervalues, text_type, class_types, string_types, next
|
||||
from six.moves import cPickle as pickle
|
||||
from docutils import nodes
|
||||
from docutils.io import FileInput, NullOutput
|
||||
from docutils.core import Publisher
|
||||
@ -1951,54 +1951,31 @@ class BuildEnvironment:
|
||||
for (key_, group) in groupby(newlist, keyfunc2)]
|
||||
|
||||
def collect_relations(self):
|
||||
relations = {}
|
||||
getinc = self.toctree_includes.get
|
||||
traversed = set()
|
||||
|
||||
def traverse_toctree(parent, docname):
|
||||
# traverse toctree by pre-order
|
||||
yield parent, docname
|
||||
traversed.add(docname)
|
||||
|
||||
for child in (self.toctree_includes.get(docname) or []):
|
||||
for subparent, subdocname in traverse_toctree(docname, child):
|
||||
if subdocname not in traversed:
|
||||
yield subparent, subdocname
|
||||
traversed.add(subdocname)
|
||||
|
||||
relations = {}
|
||||
docnames = traverse_toctree(None, self.config.master_doc)
|
||||
prevdoc = None
|
||||
parent, docname = next(docnames)
|
||||
for nextparent, nextdoc in docnames:
|
||||
relations[docname] = [parent, prevdoc, nextdoc]
|
||||
prevdoc = docname
|
||||
docname = nextdoc
|
||||
parent = nextparent
|
||||
|
||||
relations[docname] = [parent, prevdoc, None]
|
||||
|
||||
def collect(parents, parents_set, docname, previous, next):
|
||||
# circular relationship?
|
||||
if docname in parents_set:
|
||||
# we will warn about this in resolve_toctree()
|
||||
return
|
||||
includes = getinc(docname)
|
||||
# previous
|
||||
if not previous:
|
||||
# if no previous sibling, go to parent
|
||||
previous = parents[0][0]
|
||||
else:
|
||||
# else, go to previous sibling, or if it has children, to
|
||||
# the last of its children, or if that has children, to the
|
||||
# last of those, and so forth
|
||||
while 1:
|
||||
previncs = getinc(previous)
|
||||
if previncs:
|
||||
previous = previncs[-1]
|
||||
else:
|
||||
break
|
||||
# next
|
||||
if includes:
|
||||
# if it has children, go to first of them
|
||||
next = includes[0]
|
||||
elif next:
|
||||
# else, if next sibling, go to it
|
||||
pass
|
||||
else:
|
||||
# else, go to the next sibling of the parent, if present,
|
||||
# else the grandparent's sibling, if present, and so forth
|
||||
for parname, parindex in parents:
|
||||
parincs = getinc(parname)
|
||||
if parincs and parindex + 1 < len(parincs):
|
||||
next = parincs[parindex+1]
|
||||
break
|
||||
# else it will stay None
|
||||
# same for children
|
||||
if includes:
|
||||
for subindex, args in enumerate(zip(includes,
|
||||
[None] + includes,
|
||||
includes[1:] + [None])):
|
||||
collect([(docname, subindex)] + parents,
|
||||
parents_set.union([docname]), *args)
|
||||
relations[docname] = [parents[0][0], previous, next]
|
||||
collect([(None, 0)], set(), self.config.master_doc, None, None)
|
||||
return relations
|
||||
|
||||
def check_consistency(self):
|
||||
|
@ -56,6 +56,17 @@ def eq_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [node], []
|
||||
|
||||
|
||||
def is_in_section_title(node):
|
||||
"""Determine whether the node is in a section title"""
|
||||
from sphinx.util.nodes import traverse_parent
|
||||
|
||||
for ancestor in traverse_parent(node):
|
||||
if isinstance(ancestor, nodes.title) and \
|
||||
isinstance(ancestor.parent, nodes.section):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class MathDirective(Directive):
|
||||
|
||||
has_content = True
|
||||
@ -91,7 +102,12 @@ class MathDirective(Directive):
|
||||
|
||||
|
||||
def latex_visit_math(self, node):
|
||||
self.body.append('\\(' + node['latex'] + '\\)')
|
||||
if is_in_section_title(node):
|
||||
protect = r'\protect'
|
||||
else:
|
||||
protect = ''
|
||||
equation = protect + r'\(' + node['latex'] + protect + r'\)'
|
||||
self.body.append(equation)
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
@ -214,3 +230,4 @@ def setup_math(app, htmlinlinevisitors, htmldisplayvisitors):
|
||||
app.add_role('eq', eq_role)
|
||||
app.add_directive('math', MathDirective)
|
||||
app.connect('doctree-resolved', number_equations)
|
||||
app.add_latex_package('amsfonts')
|
||||
|
@ -1063,8 +1063,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.remember_multirowcol[self.table.col] = node.get('morecols')
|
||||
self.table.col += node.get('morecols')
|
||||
if isinstance(node.parent.parent, nodes.thead):
|
||||
self.body.append('\\textsf{\\relax ')
|
||||
context += '}'
|
||||
if len(node) == 1 and isinstance(node[0], nodes.paragraph) and node.astext() == '':
|
||||
pass
|
||||
else:
|
||||
self.body.append('\\textsf{\\relax ')
|
||||
context += '}'
|
||||
while self.remember_multirow.get(self.table.col + 1, 0):
|
||||
self.table.col += 1
|
||||
self.remember_multirow[self.table.col] -= 1
|
||||
@ -1661,7 +1664,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
# if a footnote has been inserted once, it shouldn't be repeated
|
||||
# by the next reference
|
||||
if used:
|
||||
if self.table or self.in_term:
|
||||
if self.table or self.in_term or self.in_title:
|
||||
self.body.append('\\protect\\footnotemark[%s]' % num)
|
||||
else:
|
||||
self.body.append('\\footnotemark[%s]' % num)
|
||||
|
@ -187,6 +187,15 @@ Tables
|
||||
| 2 | Empty cells: | |
|
||||
+----+----------------+----+
|
||||
|
||||
.. table:: empty cell in table header
|
||||
|
||||
===== ======
|
||||
\
|
||||
===== ======
|
||||
1 2
|
||||
3 4
|
||||
===== ======
|
||||
|
||||
Tables with multirow and multicol:
|
||||
|
||||
.. only:: latex
|
||||
|
@ -1,5 +1,5 @@
|
||||
Test math extensions
|
||||
====================
|
||||
Test math extensions :math:`E = m c^2`
|
||||
======================================
|
||||
|
||||
This is inline math: :math:`a^2 + b^2 = c^2`.
|
||||
|
||||
@ -19,4 +19,8 @@ This is inline math: :math:`a^2 + b^2 = c^2`.
|
||||
|
||||
e^{ix} = \cos x + i\sin x
|
||||
|
||||
.. math::
|
||||
|
||||
n \in \mathbb N
|
||||
|
||||
Referencing equation :eq:`foo`.
|
||||
|
@ -33,6 +33,9 @@ The section with a reference to [AuthorYear]_
|
||||
.. [1] Second
|
||||
.. [#] Third
|
||||
|
||||
The section with a reference to [1]_
|
||||
=====================================
|
||||
|
||||
`URL in term <http://sphinx-doc.org/>`_
|
||||
Description Description Description ...
|
||||
|
||||
|
4
tests/roots/test-toctree-glob/bar/bar_1.rst
Normal file
4
tests/roots/test-toctree-glob/bar/bar_1.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Bar-1
|
||||
=====
|
||||
|
||||
bar
|
4
tests/roots/test-toctree-glob/bar/bar_2.rst
Normal file
4
tests/roots/test-toctree-glob/bar/bar_2.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Bar-2
|
||||
=====
|
||||
|
||||
bar
|
4
tests/roots/test-toctree-glob/bar/bar_3.rst
Normal file
4
tests/roots/test-toctree-glob/bar/bar_3.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Bar-3
|
||||
=====
|
||||
|
||||
bar
|
4
tests/roots/test-toctree-glob/bar/bar_4/index.rst
Normal file
4
tests/roots/test-toctree-glob/bar/bar_4/index.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Bar-4
|
||||
=====
|
||||
|
||||
bar
|
8
tests/roots/test-toctree-glob/bar/index.rst
Normal file
8
tests/roots/test-toctree-glob/bar/index.rst
Normal file
@ -0,0 +1,8 @@
|
||||
Bar
|
||||
===
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
|
||||
*
|
||||
bar_4/index
|
4
tests/roots/test-toctree-glob/baz.rst
Normal file
4
tests/roots/test-toctree-glob/baz.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Baz
|
||||
===
|
||||
|
||||
baz
|
4
tests/roots/test-toctree-glob/conf.py
Normal file
4
tests/roots/test-toctree-glob/conf.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
master_doc = 'index'
|
||||
html_theme = 'classic'
|
4
tests/roots/test-toctree-glob/foo.rst
Normal file
4
tests/roots/test-toctree-glob/foo.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Foo
|
||||
===
|
||||
|
||||
foo
|
11
tests/roots/test-toctree-glob/index.rst
Normal file
11
tests/roots/test-toctree-glob/index.rst
Normal file
@ -0,0 +1,11 @@
|
||||
test-toctree-glob
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
|
||||
foo
|
||||
bar/index
|
||||
bar/*
|
||||
baz
|
||||
qux/index
|
4
tests/roots/test-toctree-glob/quux.rst
Normal file
4
tests/roots/test-toctree-glob/quux.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Quux
|
||||
====
|
||||
|
||||
quux
|
8
tests/roots/test-toctree-glob/qux/index.rst
Normal file
8
tests/roots/test-toctree-glob/qux/index.rst
Normal file
@ -0,0 +1,8 @@
|
||||
Qux
|
||||
===
|
||||
|
||||
.. toctree::
|
||||
:glob:
|
||||
:hidden:
|
||||
|
||||
*
|
4
tests/roots/test-toctree-glob/qux/qux_1.rst
Normal file
4
tests/roots/test-toctree-glob/qux/qux_1.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Qux-1
|
||||
=====
|
||||
|
||||
qux
|
4
tests/roots/test-toctree-glob/qux/qux_2.rst
Normal file
4
tests/roots/test-toctree-glob/qux/qux_2.rst
Normal file
@ -0,0 +1,4 @@
|
||||
Qux-1
|
||||
=====
|
||||
|
||||
qux
|
@ -12,6 +12,7 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from six import PY2
|
||||
|
||||
from sphinx import apidoc
|
||||
|
||||
@ -40,3 +41,43 @@ def test_simple(tempdir):
|
||||
assert_build()
|
||||
finally:
|
||||
sys.path.remove(codedir)
|
||||
|
||||
|
||||
@with_tempdir
|
||||
def test_multibyte_parameters(tempdir):
|
||||
codedir = rootdir / 'root'
|
||||
outdir = tempdir / 'out'
|
||||
args = ['sphinx-apidoc', '-o', outdir, '-F', codedir,
|
||||
'--doc-project', u'プロジェクト名'.encode('utf-8'),
|
||||
'--doc-author', u'著者名'.encode('utf-8'),
|
||||
'--doc-version', u'バージョン'.encode('utf-8'),
|
||||
'--doc-release', u'リリース'.encode('utf-8')]
|
||||
apidoc.main(args)
|
||||
|
||||
assert (outdir / 'conf.py').isfile()
|
||||
assert (outdir / 'autodoc_fodder.rst').isfile()
|
||||
assert (outdir / 'index.rst').isfile()
|
||||
|
||||
conf_py = (outdir / 'conf.py').text()
|
||||
if PY2:
|
||||
assert u"project = u'プロジェクト名'" in conf_py
|
||||
assert u"author = u'著者名'" in conf_py
|
||||
assert u"version = u'バージョン'" in conf_py
|
||||
assert u"release = u'リリース'" in conf_py
|
||||
else:
|
||||
assert u"project = 'プロジェクト名'" in conf_py
|
||||
assert u"author = '著者名'" in conf_py
|
||||
assert u"version = 'バージョン'" in conf_py
|
||||
assert u"release = 'リリース'" in conf_py
|
||||
|
||||
@with_app('text', srcdir=outdir)
|
||||
def assert_build(app, status, warning):
|
||||
app.build()
|
||||
print(status.getvalue())
|
||||
print(warning.getvalue())
|
||||
|
||||
sys.path.append(codedir)
|
||||
try:
|
||||
assert_build()
|
||||
finally:
|
||||
sys.path.remove(codedir)
|
||||
|
@ -90,7 +90,6 @@ def test_latex(app, status, warning):
|
||||
if p.returncode != 0:
|
||||
print(stdout)
|
||||
print(stderr)
|
||||
del app.cleanup_trees[:]
|
||||
assert False, 'latex exited with return code %s' % p.returncode
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
@ -335,6 +334,7 @@ def test_reference_in_caption(app, status, warning):
|
||||
assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result
|
||||
assert '\\caption{The table title with a reference to {[}AuthorYear{]}}' in result
|
||||
assert '\\paragraph{The rubric title with a reference to {[}AuthorYear{]}}' in result
|
||||
assert '\\chapter{The section with a reference to \\protect\\footnotemark[1]}' in result
|
||||
|
||||
|
||||
@with_app(buildername='latex', testroot='footnotes',
|
||||
|
@ -58,7 +58,6 @@ def test_texinfo(app, status, warning):
|
||||
if retcode != 0:
|
||||
print(stdout)
|
||||
print(stderr)
|
||||
del app.cleanup_trees[:]
|
||||
assert False, 'makeinfo exited with return code %s' % retcode
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
29
tests/test_toctree.py
Normal file
29
tests/test_toctree.py
Normal file
@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
test_toctree
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Test the HTML builder and check output against XPath.
|
||||
|
||||
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from util import with_app
|
||||
|
||||
|
||||
@with_app(testroot='toctree-glob')
|
||||
def test_relations(app, status, warning):
|
||||
app.builder.build_all()
|
||||
assert app.builder.relations['index'] == [None, None, 'foo']
|
||||
assert app.builder.relations['foo'] == ['index', 'index', 'bar/index']
|
||||
assert app.builder.relations['bar/index'] == ['index', 'foo', 'bar/bar_1']
|
||||
assert app.builder.relations['bar/bar_1'] == ['bar/index', 'bar/index', 'bar/bar_2']
|
||||
assert app.builder.relations['bar/bar_2'] == ['bar/index', 'bar/bar_1', 'bar/bar_3']
|
||||
assert app.builder.relations['bar/bar_3'] == ['bar/index', 'bar/bar_2', 'bar/bar_4/index']
|
||||
assert app.builder.relations['bar/bar_4/index'] == ['bar/index', 'bar/bar_3', 'baz']
|
||||
assert app.builder.relations['baz'] == ['index', 'bar/bar_4/index', 'qux/index']
|
||||
assert app.builder.relations['qux/index'] == ['index', 'baz', 'qux/qux_1']
|
||||
assert app.builder.relations['qux/qux_1'] == ['qux/index', 'qux/index', 'qux/qux_2']
|
||||
assert app.builder.relations['qux/qux_2'] == ['qux/index', 'qux/qux_1', None]
|
||||
assert 'quux' not in app.builder.relations
|
Loading…
Reference in New Issue
Block a user