summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES8
-rw-r--r--doc/ext/viewcode.rst6
-rw-r--r--sphinx/apidoc.py10
-rw-r--r--sphinx/builders/linkcheck.py13
-rw-r--r--sphinx/cmdline.py4
-rw-r--r--sphinx/environment.py73
-rw-r--r--sphinx/ext/mathbase.py19
-rw-r--r--sphinx/writers/latex.py9
-rw-r--r--tests/root/markup.txt9
-rw-r--r--tests/root/math.txt8
-rw-r--r--tests/roots/test-footnotes/index.rst3
-rw-r--r--tests/roots/test-toctree-glob/bar/bar_1.rst4
-rw-r--r--tests/roots/test-toctree-glob/bar/bar_2.rst4
-rw-r--r--tests/roots/test-toctree-glob/bar/bar_3.rst4
-rw-r--r--tests/roots/test-toctree-glob/bar/bar_4/index.rst4
-rw-r--r--tests/roots/test-toctree-glob/bar/index.rst8
-rw-r--r--tests/roots/test-toctree-glob/baz.rst4
-rw-r--r--tests/roots/test-toctree-glob/conf.py4
-rw-r--r--tests/roots/test-toctree-glob/foo.rst4
-rw-r--r--tests/roots/test-toctree-glob/index.rst11
-rw-r--r--tests/roots/test-toctree-glob/quux.rst4
-rw-r--r--tests/roots/test-toctree-glob/qux/index.rst8
-rw-r--r--tests/roots/test-toctree-glob/qux/qux_1.rst4
-rw-r--r--tests/roots/test-toctree-glob/qux/qux_2.rst4
-rw-r--r--tests/test_apidoc.py41
-rw-r--r--tests/test_build_latex.py2
-rw-r--r--tests/test_build_texinfo.py1
-rw-r--r--tests/test_toctree.py29
28 files changed, 241 insertions, 61 deletions
diff --git a/CHANGES b/CHANGES
index 319547ce1..169bf5b50 100644
--- a/CHANGES
+++ b/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)
diff --git a/doc/ext/viewcode.rst b/doc/ext/viewcode.rst
index f2b6c9283..5bf8eb033 100644
--- a/doc/ext/viewcode.rst
+++ b/doc/ext/viewcode.rst
@@ -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
diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py
index 805e862c9..8e2d88ef7 100644
--- a/sphinx/apidoc.py
+++ b/sphinx/apidoc.py
@@ -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:
diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py
index 15b22d9e1..5dac89e2f 100644
--- a/sphinx/builders/linkcheck.py
+++ b/sphinx/builders/linkcheck.py
@@ -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()
diff --git a/sphinx/cmdline.py b/sphinx/cmdline.py
index 7fa2fbfbd..ac3de5fc2 100644
--- a/sphinx/cmdline.py
+++ b/sphinx/cmdline.py
@@ -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
diff --git a/sphinx/environment.py b/sphinx/environment.py
index 58463cae8..399e51e5e 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -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):
+ 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 = {}
- getinc = self.toctree_includes.get
+ 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):
diff --git a/sphinx/ext/mathbase.py b/sphinx/ext/mathbase.py
index 4327fba1c..3510d5006 100644
--- a/sphinx/ext/mathbase.py
+++ b/sphinx/ext/mathbase.py
@@ -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')
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 28410257e..a54175a2c 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -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)
diff --git a/tests/root/markup.txt b/tests/root/markup.txt
index 9e8c6bc86..b322b39fa 100644
--- a/tests/root/markup.txt
+++ b/tests/root/markup.txt
@@ -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
diff --git a/tests/root/math.txt b/tests/root/math.txt
index 36b244943..aeba85f24 100644
--- a/tests/root/math.txt
+++ b/tests/root/math.txt
@@ -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`.
diff --git a/tests/roots/test-footnotes/index.rst b/tests/roots/test-footnotes/index.rst
index c7fe38ff9..e8137da71 100644
--- a/tests/roots/test-footnotes/index.rst
+++ b/tests/roots/test-footnotes/index.rst
@@ -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 ...
diff --git a/tests/roots/test-toctree-glob/bar/bar_1.rst b/tests/roots/test-toctree-glob/bar/bar_1.rst
new file mode 100644
index 000000000..6229a1561
--- /dev/null
+++ b/tests/roots/test-toctree-glob/bar/bar_1.rst
@@ -0,0 +1,4 @@
+Bar-1
+=====
+
+bar
diff --git a/tests/roots/test-toctree-glob/bar/bar_2.rst b/tests/roots/test-toctree-glob/bar/bar_2.rst
new file mode 100644
index 000000000..ed7862100
--- /dev/null
+++ b/tests/roots/test-toctree-glob/bar/bar_2.rst
@@ -0,0 +1,4 @@
+Bar-2
+=====
+
+bar
diff --git a/tests/roots/test-toctree-glob/bar/bar_3.rst b/tests/roots/test-toctree-glob/bar/bar_3.rst
new file mode 100644
index 000000000..93c58d41f
--- /dev/null
+++ b/tests/roots/test-toctree-glob/bar/bar_3.rst
@@ -0,0 +1,4 @@
+Bar-3
+=====
+
+bar
diff --git a/tests/roots/test-toctree-glob/bar/bar_4/index.rst b/tests/roots/test-toctree-glob/bar/bar_4/index.rst
new file mode 100644
index 000000000..4fae623ce
--- /dev/null
+++ b/tests/roots/test-toctree-glob/bar/bar_4/index.rst
@@ -0,0 +1,4 @@
+Bar-4
+=====
+
+bar
diff --git a/tests/roots/test-toctree-glob/bar/index.rst b/tests/roots/test-toctree-glob/bar/index.rst
new file mode 100644
index 000000000..74a9ba942
--- /dev/null
+++ b/tests/roots/test-toctree-glob/bar/index.rst
@@ -0,0 +1,8 @@
+Bar
+===
+
+.. toctree::
+ :glob:
+
+ *
+ bar_4/index
diff --git a/tests/roots/test-toctree-glob/baz.rst b/tests/roots/test-toctree-glob/baz.rst
new file mode 100644
index 000000000..2c1bbbc72
--- /dev/null
+++ b/tests/roots/test-toctree-glob/baz.rst
@@ -0,0 +1,4 @@
+Baz
+===
+
+baz
diff --git a/tests/roots/test-toctree-glob/conf.py b/tests/roots/test-toctree-glob/conf.py
new file mode 100644
index 000000000..cf05c9b5c
--- /dev/null
+++ b/tests/roots/test-toctree-glob/conf.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+
+master_doc = 'index'
+html_theme = 'classic'
diff --git a/tests/roots/test-toctree-glob/foo.rst b/tests/roots/test-toctree-glob/foo.rst
new file mode 100644
index 000000000..83f952239
--- /dev/null
+++ b/tests/roots/test-toctree-glob/foo.rst
@@ -0,0 +1,4 @@
+Foo
+===
+
+foo
diff --git a/tests/roots/test-toctree-glob/index.rst b/tests/roots/test-toctree-glob/index.rst
new file mode 100644
index 000000000..079cd6027
--- /dev/null
+++ b/tests/roots/test-toctree-glob/index.rst
@@ -0,0 +1,11 @@
+test-toctree-glob
+=================
+
+.. toctree::
+ :glob:
+
+ foo
+ bar/index
+ bar/*
+ baz
+ qux/index
diff --git a/tests/roots/test-toctree-glob/quux.rst b/tests/roots/test-toctree-glob/quux.rst
new file mode 100644
index 000000000..340389d0a
--- /dev/null
+++ b/tests/roots/test-toctree-glob/quux.rst
@@ -0,0 +1,4 @@
+Quux
+====
+
+quux
diff --git a/tests/roots/test-toctree-glob/qux/index.rst b/tests/roots/test-toctree-glob/qux/index.rst
new file mode 100644
index 000000000..ad0bee51f
--- /dev/null
+++ b/tests/roots/test-toctree-glob/qux/index.rst
@@ -0,0 +1,8 @@
+Qux
+===
+
+.. toctree::
+ :glob:
+ :hidden:
+
+ *
diff --git a/tests/roots/test-toctree-glob/qux/qux_1.rst b/tests/roots/test-toctree-glob/qux/qux_1.rst
new file mode 100644
index 000000000..bac227b42
--- /dev/null
+++ b/tests/roots/test-toctree-glob/qux/qux_1.rst
@@ -0,0 +1,4 @@
+Qux-1
+=====
+
+qux
diff --git a/tests/roots/test-toctree-glob/qux/qux_2.rst b/tests/roots/test-toctree-glob/qux/qux_2.rst
new file mode 100644
index 000000000..bac227b42
--- /dev/null
+++ b/tests/roots/test-toctree-glob/qux/qux_2.rst
@@ -0,0 +1,4 @@
+Qux-1
+=====
+
+qux
diff --git a/tests/test_apidoc.py b/tests/test_apidoc.py
index 215b2e571..794b1a293 100644
--- a/tests/test_apidoc.py
+++ b/tests/test_apidoc.py
@@ -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)
diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py
index 5cdd3f592..774ed4273 100644
--- a/tests/test_build_latex.py
+++ b/tests/test_build_latex.py
@@ -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',
diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py
index 8050695d9..618d79015 100644
--- a/tests/test_build_texinfo.py
+++ b/tests/test_build_texinfo.py
@@ -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)
diff --git a/tests/test_toctree.py b/tests/test_toctree.py
new file mode 100644
index 000000000..d91d92389
--- /dev/null
+++ b/tests/test_toctree.py
@@ -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