Merge branch 'stable'

This commit is contained in:
Takeshi KOMIYA 2016-01-11 00:27:26 +09:00
commit e4b9eb51f6
70 changed files with 777 additions and 147 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
*.pyc *.pyc
*.egg *.egg
*.so *.so
*.swp
.dir-locals.el .dir-locals.el
.ropeproject/ .ropeproject/

29
CHANGES
View File

@ -69,14 +69,39 @@ Bugs fixed
* #2168: Fix raw directive does not work for text writer * #2168: Fix raw directive does not work for text writer
* #2171: Fix cannot linkcheck url with unicode * #2171: Fix cannot linkcheck url with unicode
* #2182: LaTeX: support image file names with more than 1 dots * #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 * #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 * #2003: Fix decode error under python2 (only) when ``make linkcheck`` is run
* #2186: Fix LaTeX output of \mathbb in math * #2186: Fix LaTeX output of \mathbb in math
* #1480, #2188: LaTeX: Support math in section titles * #1480, #2188: LaTeX: Support math in section titles
* #2071: Fix same footnote in more than two section titles => LaTeX/PDF Bug * #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 * #2040: Fix UnicodeDecodeError in sphinx-apidoc when author contains non-ascii characters
* #2193: Fix shutil.SameFileError if source directory and destination directory are same * #2193: Fix shutil.SameFileError if source directory and destination directory are same
* #2178: Fix unparseable C++ cross-reference when referencing a function with :cpp:any:
* #2206: Fix Sphinx latex doc build failed due to a footnotes
* #2201: Fix wrong table caption for tables with over 30 rows
* #2213: Set <blockquote> in the classic theme to fit with <p>
* #1815: Fix linkcheck does not raise an exception if warniserror set to true and link is
broken
* #2197: Fix slightly cryptic error message for missing index.rst file
* #1894: Unlisted phony targets in quickstart Makefile
* #2125: Fix unifies behavior of collapsed fields (``GroupedField`` and ``TypedField``)
* #1408: Check latex_logo validity before copying
* #771: Fix latex output doesn't set tocdepth
* #1820: On Windows, console coloring is broken with colorama version 0.3.3.
Now sphinx use colorama>=0.3.5 to avoid this problem.
* #2072: Fix footnotes in chapter-titles do not appear in PDF output
* #1580: Fix paragraphs in longtable don't work in Latex output
* #1366: Fix centered image not centered in latex
* #1860: Fix man page using ``:samp:`` with braces - font doesn't reset
* #1610: Sphinx crashes in japanese indexing in some systems
* Fix Sphinx crashes if mecab initialization failed
* #2160: Fix broken TOC of PDFs if section includes an image
* #2172: Fix dysfunctional admonition \py@lightbox in sphinx.sty. Thanks to jfbu.
* #2198,#2205: ``make gettext`` generate broken msgid for definition lists.
* #2062: Escape characters in doctests are treated incorrectly with Python 2.
* #2225: Fix if the option does not begin with dash, linking is not performed
* #2226: Fix math is not HTML-encoded when :nowrap: is given (jsmath, mathjax)
Release 1.3.3 (released Dec 2, 2015) Release 1.3.3 (released Dec 2, 2015)
==================================== ====================================

View File

@ -62,11 +62,11 @@
</table> </table>
<p>{%trans%} <p>{%trans%}
You can also download PDF versions of the Sphinx documentation: You can also download PDF/EPUB versions of the Sphinx documentation:
a <a href="http://sphinx-doc.org/sphinx.pdf">version</a> generated from a <a href="http://readthedocs.org/projects/sphinx/downloads/pdf/stable/">PDF version</a> generated from
the LaTeX Sphinx produces, and the LaTeX Sphinx produces, and
a <a href="http://sphinx-doc.org/sphinx-rst2pdf.pdf">version</a> generated a <a href="http://readthedocs.org/projects/sphinx/downloads/epub/stable/">EPUB version</a>.
by rst2pdf.{%endtrans%} {%endtrans%}
</p> </p>
<h2>{%trans%}Examples{%endtrans%}</h2> <h2>{%trans%}Examples{%endtrans%}</h2>

View File

@ -14,15 +14,7 @@
<p>{%trans%}Current version: <b>{{ version }}</b>{%endtrans%}</p> <p>{%trans%}Current version: <b>{{ version }}</b>{%endtrans%}</p>
<p>{%trans%}Get Sphinx from the <a href="https://pypi.python.org/pypi/Sphinx">Python Package <p>{%trans%}Get Sphinx from the <a href="https://pypi.python.org/pypi/Sphinx">Python Package
Index</a>, or install it with:{%endtrans%}</p> Index</a>, or install it with:{%endtrans%}</p>
{% if version.split('b')|length > 1 %}
<pre>pip install Sphinx=={{ version }}</pre>
<p>{%trans%}<a href="http://sphinx-doc.org/">Stable version docs</a>
are also available.{%endtrans%}</p>
{% else %}
<pre>pip install -U Sphinx</pre> <pre>pip install -U Sphinx</pre>
<p>{%trans%}Latest <a href="http://sphinx-doc.org/latest/">development version docs</a>
are also available.{%endtrans%}</p>
{% endif %}
{% endif %} {% endif %}
<h3>{%trans%}Questions? Suggestions?{%endtrans%}</h3> <h3>{%trans%}Questions? Suggestions?{%endtrans%}</h3>

View File

@ -17,7 +17,11 @@ Build environment API
.. attribute:: srcdir .. attribute:: srcdir
Source directory (the directory containing ``conf.py``). Source directory.
.. attribute:: confdir
Directory containing ``conf.py``.
.. attribute:: doctreedir .. attribute:: doctreedir

View File

@ -242,9 +242,8 @@ objects:
.. rst:role:: option .. rst:role:: option
A command-line option to an executable program. The leading hyphen(s) must A command-line option to an executable program. This generates a link to
be included. This generates a link to a :rst:dir:`option` directive, if it a :rst:dir:`option` directive, if it exists.
exists.
The following role creates a cross-reference to a term in a The following role creates a cross-reference to a term in a

View File

@ -58,7 +58,7 @@ requires = [
extras_require = { extras_require = {
# Environment Marker works for wheel 0.24 or later # Environment Marker works for wheel 0.24 or later
':sys_platform=="win32"': [ ':sys_platform=="win32"': [
'colorama', 'colorama>=0.3.5',
], ],
'websupport': [ 'websupport': [
'sqlalchemy>=0.9', 'sqlalchemy>=0.9',
@ -73,7 +73,7 @@ extras_require = {
# for sdist installation with pip-1.5.6 # for sdist installation with pip-1.5.6
if sys.platform == 'win32': if sys.platform == 'win32':
requires.append('colorama') requires.append('colorama>=0.3.5')
# Provide a "compile_catalog" command that also creates the translated # Provide a "compile_catalog" command that also creates the translated
# JavaScript files if Babel is available. # JavaScript files if Babel is available.

View File

@ -20,6 +20,7 @@ from docutils.frontend import OptionParser
from sphinx import package_dir, addnodes from sphinx import package_dir, addnodes
from sphinx.util import texescape from sphinx.util import texescape
from sphinx.errors import SphinxError
from sphinx.locale import _ from sphinx.locale import _
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.environment import NoUri from sphinx.environment import NoUri
@ -94,9 +95,18 @@ class LaTeXBuilder(Builder):
destination_path=path.join(self.outdir, targetname), destination_path=path.join(self.outdir, targetname),
encoding='utf-8') encoding='utf-8')
self.info("processing " + targetname + "... ", nonl=1) self.info("processing " + targetname + "... ", nonl=1)
toctrees = self.env.get_doctree(docname).traverse(addnodes.toctree)
if toctrees:
if toctrees[0].get('maxdepth'):
tocdepth = int(toctrees[0].get('maxdepth'))
else:
tocdepth = None
else:
tocdepth = None
doctree = self.assemble_doctree( doctree = self.assemble_doctree(
docname, toctree_only, docname, toctree_only,
appendices=((docclass != 'howto') and self.config.latex_appendices or [])) appendices=((docclass != 'howto') and self.config.latex_appendices or []))
doctree['tocdepth'] = tocdepth
self.post_process_images(doctree) self.post_process_images(doctree)
self.info("writing... ", nonl=1) self.info("writing... ", nonl=1)
doctree.settings = docsettings doctree.settings = docsettings
@ -191,6 +201,9 @@ class LaTeXBuilder(Builder):
# the logo is handled differently # the logo is handled differently
if self.config.latex_logo: if self.config.latex_logo:
logobase = path.basename(self.config.latex_logo) logobase = path.basename(self.config.latex_logo)
copyfile(path.join(self.confdir, self.config.latex_logo), logotarget = path.join(self.outdir, logobase)
path.join(self.outdir, logobase)) if not path.isfile(path.join(self.confdir, self.config.latex_logo)):
raise SphinxError('logo file %r does not exist' % self.config.latex_logo)
elif not path.isfile(logotarget):
copyfile(path.join(self.confdir, self.config.latex_logo), logotarget)
self.info('done') self.info('done')

View File

@ -243,11 +243,12 @@ class CheckExternalLinksBuilder(Builder):
elif status == 'working': elif status == 'working':
self.info(darkgreen('ok ') + uri + info) self.info(darkgreen('ok ') + uri + info)
elif status == 'broken': elif status == 'broken':
self.info(red('broken ') + uri + red(' - ' + info))
self.write_entry('broken', docname, lineno, uri + ': ' + info) self.write_entry('broken', docname, lineno, uri + ': ' + info)
if self.app.quiet: if self.app.quiet or self.app.warningiserror:
self.warn('broken link: %s' % uri, self.warn('broken link: %s' % uri,
'%s:%s' % (self.env.doc2path(docname), lineno)) '%s:%s' % (self.env.doc2path(docname), lineno))
else:
self.info(red('broken ') + uri + red(' - ' + info))
elif status == 'redirected': elif status == 'redirected':
text, color = { text, color = {
301: ('permanently', darkred), 301: ('permanently', darkred),

View File

@ -3924,6 +3924,9 @@ class CPPXRefRole(XRefRole):
parent = env.ref_context.get('cpp:parentSymbol', None) parent = env.ref_context.get('cpp:parentSymbol', None)
if parent: if parent:
refnode['cpp:parentKey'] = parent.get_lookup_key() refnode['cpp:parentKey'] = parent.get_lookup_key()
if refnode['reftype'] == 'any':
# Remove parentheses from the target (not from title)
title, target = self._fix_parens(env, True, title, target)
# TODO: should this really be here? # TODO: should this really be here?
if not has_explicit_title: if not has_explicit_title:
target = target.lstrip('~') # only has a meaning for the title target = target.lstrip('~') # only has a meaning for the title
@ -4048,6 +4051,14 @@ class CPPDomain(Domain):
name = text_type(fullNestedName).lstrip(':') name = text_type(fullNestedName).lstrip(':')
docname = s.docname docname = s.docname
assert docname assert docname
if declaration.objectType == 'function':
title = name
if title.endswith('()'):
title = title[:-2] # remove parentheses
if env.config.add_function_parentheses:
title += '()'
contnode.pop(0)
contnode.insert(0, nodes.Text(title))
return make_refnode(builder, fromdocname, docname, return make_refnode(builder, fromdocname, docname,
declaration.get_newest_id(), contnode, name declaration.get_newest_id(), contnode, name
), declaration.objectType ), declaration.objectType

View File

@ -210,10 +210,6 @@ class Program(Directive):
class OptionXRefRole(XRefRole): class OptionXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target): def process_link(self, env, refnode, has_explicit_title, title, target):
# validate content
if not re.match(r'(.+ )?[-/+\w]', target):
env.warn_node('Malformed :option: %r, does not contain option '
'marker - or -- or / or +' % target, refnode)
refnode['std:program'] = env.ref_context.get('std:program') refnode['std:program'] = env.ref_context.get('std:program')
return title, target return title, target
@ -666,22 +662,23 @@ class StandardDomain(Domain):
return make_refnode(builder, fromdocname, docname, return make_refnode(builder, fromdocname, docname,
labelid, contnode) labelid, contnode)
elif typ == 'option': elif typ == 'option':
progname = node.get('std:program')
target = target.strip() target = target.strip()
# most obvious thing: we are a flag option without program docname, labelid = self.data['progoptions'].get((progname, target), ('', ''))
if target.startswith(('-', '/', '+')):
progname = node.get('std:program')
elif re.search(r'[-/+]', target):
try:
progname, target = re.split(r' (?=-|--|/|\+)', target, 1)
except ValueError:
return None
progname = ws_re.sub('-', progname.strip())
else:
progname = None
docname, labelid = self.data['progoptions'].get((progname, target),
('', ''))
if not docname: if not docname:
return None commands = []
while ws_re.search(target):
subcommand, target = ws_re.split(target, 1)
commands.append(subcommand)
progname = "-".join(commands)
docname, labelid = self.data['progoptions'].get((progname, target),
('', ''))
if docname:
break
else:
return None
return make_refnode(builder, fromdocname, docname, return make_refnode(builder, fromdocname, docname,
labelid, contnode) labelid, contnode)
else: else:

View File

@ -618,8 +618,8 @@ class BuildEnvironment:
self._read_serial(docnames, app) self._read_serial(docnames, app)
if config.master_doc not in self.all_docs: if config.master_doc not in self.all_docs:
self.warn(None, 'master file %s not found' % raise SphinxError('master file %s not found' %
self.doc2path(config.master_doc)) self.doc2path(config.master_doc))
self.app = None self.app = None

View File

@ -45,14 +45,6 @@ else:
return text return text
class _SpoofOutSphinx(doctest._SpoofOut):
# override: convert console encoding to unicode
if PY2:
def getvalue(self):
result = doctest._SpoofOut.getvalue(self)
return result.decode('string_escape')
# set up the necessary directives # set up the necessary directives
class TestDirective(Directive): class TestDirective(Directive):
@ -184,11 +176,6 @@ class TestCode(object):
class SphinxDocTestRunner(doctest.DocTestRunner): class SphinxDocTestRunner(doctest.DocTestRunner):
def __init__(self, *args, **kw):
doctest.DocTestRunner.__init__(self, *args, **kw)
# Override a fake output target for capturing doctest output.
self._fakeout = _SpoofOutSphinx()
def summarize(self, out, verbose=None): def summarize(self, out, verbose=None):
string_io = StringIO() string_io = StringIO()
old_stdout = sys.stdout old_stdout = sys.stdout
@ -262,9 +249,10 @@ Results of doctest builder run on %s
self.outfile.write(text) self.outfile.write(text)
def _warn_out(self, text): def _warn_out(self, text):
self.info(text, nonl=True) if self.app.quiet or self.app.warningiserror:
if self.app.quiet:
self.warn(text) self.warn(text)
else:
self.info(text, nonl=True)
if isinstance(text, binary_type): if isinstance(text, binary_type):
text = force_decode(text, None) text = force_decode(text, None)
self.outfile.write(text) self.outfile.write(text)

View File

@ -26,7 +26,7 @@ def html_visit_math(self, node):
def html_visit_displaymath(self, node): def html_visit_displaymath(self, node):
if node['nowrap']: if node['nowrap']:
self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append(self.starttag(node, 'div', CLASS='math'))
self.body.append(node['latex']) self.body.append(self.encode(node['latex']))
self.body.append('</div>') self.body.append('</div>')
raise nodes.SkipNode raise nodes.SkipNode
for i, part in enumerate(node['latex'].split('\n\n')): for i, part in enumerate(node['latex'].split('\n\n')):

View File

@ -30,7 +30,7 @@ def html_visit_displaymath(self, node):
self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append(self.starttag(node, 'div', CLASS='math'))
if node['nowrap']: if node['nowrap']:
self.body.append(self.builder.config.mathjax_display[0] + self.body.append(self.builder.config.mathjax_display[0] +
node['latex'] + self.encode(node['latex']) +
self.builder.config.mathjax_display[1]) self.builder.config.mathjax_display[1])
self.body.append('</div>') self.body.append('</div>')
raise nodes.SkipNode raise nodes.SkipNode

View File

@ -296,8 +296,8 @@ latex_elements = {
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
latex_documents = [ latex_documents = [
(master_doc, '%(project_fn)s.tex', u'%(project_doc_texescaped_str)s', (master_doc, '%(project_fn)s.tex', u'%(project_doc_texescaped_str)s',
u'%(author_texescaped_str)s', 'manual'), u'%(author_texescaped_str)s', 'manual'),
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
@ -340,9 +340,9 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
(master_doc, '%(project_fn)s', u'%(project_doc_str)s', (master_doc, '%(project_fn)s', u'%(project_doc_str)s',
author, '%(project_fn)s', 'One line description of project.', author, '%(project_fn)s', 'One line description of project.',
'Miscellaneous'), 'Miscellaneous'),
] ]
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
@ -371,10 +371,10 @@ epub_copyright = copyright
# The basename for the epub file. It defaults to the project name. # The basename for the epub file. It defaults to the project name.
#epub_basename = project #epub_basename = project
# The HTML theme for the epub output. Since the default themes are not optimized # The HTML theme for the epub output. Since the default themes are not
# for small screen space, using the same theme for HTML and epub output is # optimized for small screen space, using the same theme for HTML and epub
# usually not wise. This defaults to 'epub', a theme designed to save visual # output is usually not wise. This defaults to 'epub', a theme designed to save
# space. # visual space.
#epub_theme = 'epub' #epub_theme = 'epub'
# The language of the text. It defaults to the language option # The language of the text. It defaults to the language option
@ -489,9 +489,7 @@ $(SPHINXOPTS) %(rsrcdir)s
# the i18n builder cannot share the environment and doctrees with the others # the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) %(rsrcdir)s I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) %(rsrcdir)s
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp \ .PHONY: help
epub latex latexpdf text man changes linkcheck doctest coverage gettext
help: help:
\t@echo "Please use \\`make <target>' where <target> is one of" \t@echo "Please use \\`make <target>' where <target> is one of"
\t@echo " html to make standalone HTML files" \t@echo " html to make standalone HTML files"
@ -520,40 +518,48 @@ help:
(if enabled)" (if enabled)"
\t@echo " coverage to run coverage check of the documentation (if enabled)" \t@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean: clean:
\trm -rf $(BUILDDIR)/* \trm -rf $(BUILDDIR)/*
.PHONY: html
html: html:
\t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html \t$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
\t@echo \t@echo
\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html." \t@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml: dirhtml:
\t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml \t$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
\t@echo \t@echo
\t@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." \t@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml: singlehtml:
\t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml \t$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
\t@echo \t@echo
\t@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." \t@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle: pickle:
\t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle \t$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
\t@echo \t@echo
\t@echo "Build finished; now you can process the pickle files." \t@echo "Build finished; now you can process the pickle files."
.PHONY: json
json: json:
\t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json \t$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
\t@echo \t@echo
\t@echo "Build finished; now you can process the JSON files." \t@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp: htmlhelp:
\t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp \t$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
\t@echo \t@echo
\t@echo "Build finished; now you can run HTML Help Workshop with the" \\ \t@echo "Build finished; now you can run HTML Help Workshop with the" \\
\t ".hhp project file in $(BUILDDIR)/htmlhelp." \t ".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp: qthelp:
\t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp \t$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
\t@echo \t@echo
@ -563,6 +569,7 @@ qthelp:
\t@echo "To view the help file:" \t@echo "To view the help file:"
\t@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/%(project_fn)s.qhc" \t@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/%(project_fn)s.qhc"
.PHONY: applehelp
applehelp: applehelp:
\t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp \t$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
\t@echo \t@echo
@ -571,6 +578,7 @@ applehelp:
\t "~/Library/Documentation/Help or install it in your application" \\ \t "~/Library/Documentation/Help or install it in your application" \\
\t "bundle." \t "bundle."
.PHONY: devhelp
devhelp: devhelp:
\t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp \t$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
\t@echo \t@echo
@ -581,11 +589,13 @@ devhelp:
$$HOME/.local/share/devhelp/%(project_fn)s" $$HOME/.local/share/devhelp/%(project_fn)s"
\t@echo "# devhelp" \t@echo "# devhelp"
.PHONY: epub
epub: epub:
\t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub \t$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
\t@echo \t@echo
\t@echo "Build finished. The epub file is in $(BUILDDIR)/epub." \t@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex: latex:
\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex \t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
\t@echo \t@echo
@ -593,28 +603,33 @@ latex:
\t@echo "Run \\`make' in that directory to run these through (pdf)latex" \\ \t@echo "Run \\`make' in that directory to run these through (pdf)latex" \\
\t "(use \\`make latexpdf' here to do that automatically)." \t "(use \\`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf: latexpdf:
\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex \t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
\t@echo "Running LaTeX files through pdflatex..." \t@echo "Running LaTeX files through pdflatex..."
\t$(MAKE) -C $(BUILDDIR)/latex all-pdf \t$(MAKE) -C $(BUILDDIR)/latex all-pdf
\t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." \t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja: latexpdfja:
\t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex \t$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
\t@echo "Running LaTeX files through platex and dvipdfmx..." \t@echo "Running LaTeX files through platex and dvipdfmx..."
\t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja \t$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
\t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." \t@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text: text:
\t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text \t$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
\t@echo \t@echo
\t@echo "Build finished. The text files are in $(BUILDDIR)/text." \t@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man: man:
\t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man \t$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
\t@echo \t@echo
\t@echo "Build finished. The manual pages are in $(BUILDDIR)/man." \t@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo: texinfo:
\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo \t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
\t@echo \t@echo
@ -622,43 +637,51 @@ texinfo:
\t@echo "Run \\`make' in that directory to run these through makeinfo" \\ \t@echo "Run \\`make' in that directory to run these through makeinfo" \\
\t "(use \\`make info' here to do that automatically)." \t "(use \\`make info' here to do that automatically)."
.PHONY: info
info: info:
\t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo \t$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
\t@echo "Running Texinfo files through makeinfo..." \t@echo "Running Texinfo files through makeinfo..."
\tmake -C $(BUILDDIR)/texinfo info \tmake -C $(BUILDDIR)/texinfo info
\t@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." \t@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext: gettext:
\t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale \t$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
\t@echo \t@echo
\t@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." \t@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes: changes:
\t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes \t$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
\t@echo \t@echo
\t@echo "The overview file is in $(BUILDDIR)/changes." \t@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck: linkcheck:
\t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck \t$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
\t@echo \t@echo
\t@echo "Link check complete; look for any errors in the above output " \\ \t@echo "Link check complete; look for any errors in the above output " \\
\t "or in $(BUILDDIR)/linkcheck/output.txt." \t "or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest: doctest:
\t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest \t$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
\t@echo "Testing of doctests in the sources finished, look at the " \\ \t@echo "Testing of doctests in the sources finished, look at the " \\
\t "results in $(BUILDDIR)/doctest/output.txt." \t "results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage: coverage:
\t$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage \t$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
\t@echo "Testing of coverage in the sources finished, look at the " \\ \t@echo "Testing of coverage in the sources finished, look at the " \\
\t "results in $(BUILDDIR)/coverage/python.txt." \t "results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml: xml:
\t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml \t$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
\t@echo \t@echo
\t@echo "Build finished. The XML files are in $(BUILDDIR)/xml." \t@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml: pseudoxml:
\t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml \t$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
\t@echo \t@echo

View File

@ -29,6 +29,7 @@ try:
except ImportError: except ImportError:
native_module = False native_module = False
from sphinx.errors import SphinxError
from sphinx.search import SearchLanguage from sphinx.search import SearchLanguage
@ -86,9 +87,16 @@ class MecabBinder(object):
if dict: if dict:
param += ' -d %s' % dict param += ' -d %s' % dict
fs_enc = sys.getfilesystemencoding() or sys.getdefaultencoding()
self.ctypes_libmecab = ctypes.CDLL(libpath) self.ctypes_libmecab = ctypes.CDLL(libpath)
self.ctypes_libmecab.mecab_new2.argtypes = (ctypes.c_char_p,)
self.ctypes_libmecab.mecab_new2.restype = ctypes.c_void_p
self.ctypes_libmecab.mecab_sparse_tostr.argtypes = (ctypes.c_void_p, ctypes.c_char_p)
self.ctypes_libmecab.mecab_sparse_tostr.restype = ctypes.c_char_p self.ctypes_libmecab.mecab_sparse_tostr.restype = ctypes.c_char_p
self.ctypes_mecab = self.ctypes_libmecab.mecab_new2(param) self.ctypes_mecab = self.ctypes_libmecab.mecab_new2(param.encode(fs_enc))
if self.ctypes_mecab is None:
raise SphinxError('mecab initialization failed')
def __del__(self): def __del__(self):
if self.ctypes_libmecab: if self.ctypes_libmecab:

View File

@ -270,16 +270,15 @@
\fbox{\TheSbox} \fbox{\TheSbox}
} }
\newcommand{\py@lightbox}{{% \newcommand{\py@lightbox}{%
\setlength\parskip{0pt}\par \par\allowbreak
\noindent\rule[0ex]{\linewidth}{0.5pt}% \noindent\rule{\linewidth}{0.5pt}\par\nobreak
\par\noindent\vspace{-0.5ex}% {\parskip\z@skip\noindent}%
}} }
\newcommand{\py@endlightbox}{{% \newcommand{\py@endlightbox}{%
\setlength{\parskip}{0pt}% \par\nobreak
\par\noindent\rule[0.5ex]{\linewidth}{0.5pt}% {\parskip\z@skip\noindent\rule[.4\baselineskip]{\linewidth}{0.5pt}}\par
\par\vspace{-0.5ex}% }
}}
% Some are quite plain: % Some are quite plain:
\newcommand{\py@noticestart@note}{\py@lightbox} \newcommand{\py@noticestart@note}{\py@lightbox}

View File

@ -223,7 +223,7 @@ a.headerlink:hover {
color: white; color: white;
} }
div.body p, div.body dd, div.body li { div.body p, div.body dd, div.body li, div.body blockquote {
text-align: justify; text-align: justify;
line-height: 130%; line-height: 130%;
} }

View File

@ -106,8 +106,6 @@ class GroupedField(Field):
def make_field(self, types, domain, items): def make_field(self, types, domain, items):
fieldname = nodes.field_name('', self.label) fieldname = nodes.field_name('', self.label)
listnode = self.list_type() listnode = self.list_type()
if len(items) == 1 and self.can_collapse:
return Field.make_field(self, types, domain, items[0])
for fieldarg, content in items: for fieldarg, content in items:
par = nodes.paragraph() par = nodes.paragraph()
par += self.make_xref(self.rolename, domain, fieldarg, par += self.make_xref(self.rolename, domain, fieldarg,
@ -115,6 +113,9 @@ class GroupedField(Field):
par += nodes.Text(' -- ') par += nodes.Text(' -- ')
par += content par += content
listnode += nodes.list_item('', par) listnode += nodes.list_item('', par)
if len(items) == 1 and self.can_collapse:
fieldbody = nodes.field_body('', listnode[0][0])
return nodes.field('', fieldname, fieldbody)
fieldbody = nodes.field_body('', listnode) fieldbody = nodes.field_body('', listnode)
return nodes.field('', fieldname, fieldbody) return nodes.field('', fieldname, fieldbody)

View File

@ -47,8 +47,10 @@ def apply_source_workaround(node):
node.line = definition_list_item.line - 1 node.line = definition_list_item.line - 1
node.rawsource = node.astext() # set 'classifier1' (or 'classifier2') node.rawsource = node.astext() # set 'classifier1' (or 'classifier2')
if isinstance(node, nodes.term): if isinstance(node, nodes.term):
# overwrite: ``term : classifier1 : classifier2`` -> ``term text`` # strip classifier from rawsource of term
node.rawsource = node.astext() for classifier in reversed(node.parent.traverse(nodes.classifier)):
node.rawsource = re.sub(
'\s*:\s*%s' % classifier.astext(), '', node.rawsource)
# workaround: recommonmark-0.2.0 doesn't set rawsource attribute # workaround: recommonmark-0.2.0 doesn't set rawsource attribute
if not node.rawsource: if not node.rawsource:

View File

@ -25,6 +25,7 @@ from sphinx import highlighting
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _ from sphinx.locale import admonitionlabels, _
from sphinx.util import split_into from sphinx.util import split_into
from sphinx.util.nodes import clean_astext
from sphinx.util.osutil import ustrftime from sphinx.util.osutil import ustrftime
from sphinx.util.texescape import tex_escape_map, tex_replace_map from sphinx.util.texescape import tex_escape_map, tex_replace_map
from sphinx.util.smartypants import educate_quotes_latex from sphinx.util.smartypants import educate_quotes_latex
@ -53,6 +54,7 @@ HEADER = r'''%% Generated by Sphinx.
\author{%(author)s} \author{%(author)s}
\newcommand{\sphinxlogo}{%(logo)s} \newcommand{\sphinxlogo}{%(logo)s}
\renewcommand{\releasename}{%(releasename)s} \renewcommand{\releasename}{%(releasename)s}
%(tocdepth)s
%(makeindex)s %(makeindex)s
''' '''
@ -234,7 +236,6 @@ class Table(object):
self.has_verbatim = False self.has_verbatim = False
self.caption = None self.caption = None
self.longtable = False self.longtable = False
self.footnotes = []
class LaTeXTranslator(nodes.NodeVisitor): class LaTeXTranslator(nodes.NodeVisitor):
@ -276,6 +277,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'printindex': '\\printindex', 'printindex': '\\printindex',
'transition': '\n\n\\bigskip\\hrule{}\\bigskip\n\n', 'transition': '\n\n\\bigskip\\hrule{}\\bigskip\n\n',
'figure_align': 'htbp', 'figure_align': 'htbp',
'tocdepth': '',
} }
# sphinx specific document classes # sphinx specific document classes
@ -360,6 +362,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
if self.elements['extraclassoptions']: if self.elements['extraclassoptions']:
self.elements['classoptions'] += ',' + \ self.elements['classoptions'] += ',' + \
self.elements['extraclassoptions'] self.elements['extraclassoptions']
if document.get('tocdepth'):
if document.settings.docclass == 'howto':
self.elements['tocdepth'] = ('\\setcounter{tocdepth}{%d}' %
document['tocdepth'])
else:
self.elements['tocdepth'] = ('\\setcounter{tocdepth}{%d}' %
(document['tocdepth'] - 1))
self.highlighter = highlighting.PygmentsBridge( self.highlighter = highlighting.PygmentsBridge(
'latex', 'latex',
@ -377,7 +386,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
sys.maxsize]] sys.maxsize]]
self.bodystack = [] self.bodystack = []
self.footnotestack = [] self.footnotestack = []
self.termfootnotestack = [] self.footnote_restricted = False
self.pending_footnotes = []
self.curfilestack = [] self.curfilestack = []
self.handled_abbrs = set() self.handled_abbrs = set()
if document.settings.docclass == 'howto': if document.settings.docclass == 'howto':
@ -416,6 +426,19 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body = self.bodystack.pop() self.body = self.bodystack.pop()
return body return body
def restrict_footnote(self, node):
if self.footnote_restricted is False:
self.footnote_restricted = node
self.pending_footnotes = []
def unrestrict_footnote(self, node):
if self.footnote_restricted == node:
self.footnote_restricted = False
for footnode in self.pending_footnotes:
footnode['footnotetext'] = True
footnode.walkabout(self)
self.pending_footnotes = []
def format_docclass(self, docclass): def format_docclass(self, docclass):
""" prepends prefix to sphinx document classes """ prepends prefix to sphinx document classes
""" """
@ -697,13 +720,18 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.this_is_the_title = 0 self.this_is_the_title = 0
raise nodes.SkipNode raise nodes.SkipNode
elif isinstance(parent, nodes.section): elif isinstance(parent, nodes.section):
short = ''
if node.traverse(nodes.image):
short = '[%s]' % ' '.join(clean_astext(node).split()).translate(tex_escape_map)
try: try:
self.body.append(r'\%s{' % self.sectionnames[self.sectionlevel]) self.body.append(r'\%s%s{' % (self.sectionnames[self.sectionlevel], short))
except IndexError: except IndexError:
# just use "subparagraph", it's not numbered anyway # just use "subparagraph", it's not numbered anyway
self.body.append(r'\%s{' % self.sectionnames[-1]) self.body.append(r'\%s%s{' % (self.sectionnames[-1], short))
self.context.append('}\n') self.context.append('}\n')
self.restrict_footnote(node)
if self.next_section_ids: if self.next_section_ids:
for id in self.next_section_ids: for id in self.next_section_ids:
self.context[-1] += self.hypertarget(id, anchor=False) self.context[-1] += self.hypertarget(id, anchor=False)
@ -733,6 +761,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table.caption = self.popbody() self.table.caption = self.popbody()
else: else:
self.body.append(self.context.pop()) self.body.append(self.context.pop())
self.unrestrict_footnote(node)
def visit_subtitle(self, node): def visit_subtitle(self, node):
if isinstance(node.parent, nodes.sidebar): if isinstance(node.parent, nodes.sidebar):
@ -893,6 +922,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.tableheaders = [] self.tableheaders = []
# Redirect body output until table is finished. # Redirect body output until table is finished.
self.pushbody(self.tablebody) self.pushbody(self.tablebody)
self.restrict_footnote(node)
def depart_table(self, node): def depart_table(self, node):
if self.table.rowcount > 30: if self.table.rowcount > 30:
@ -936,7 +966,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
else: else:
self.body.append('{|' + ('L|' * self.table.colcount) + '}\n') self.body.append('{|' + ('L|' * self.table.colcount) + '}\n')
if self.table.longtable and self.table.caption is not None: if self.table.longtable and self.table.caption is not None:
self.body.append(u'\\caption{%s}' % self.table.caption) self.body.append(u'\\caption{')
for caption in self.table.caption:
self.body.append(caption)
self.body.append('}')
for id in self.next_table_ids: for id in self.next_table_ids:
self.body.append(self.hypertarget(id, anchor=False)) self.body.append(self.hypertarget(id, anchor=False))
self.next_table_ids.clear() self.next_table_ids.clear()
@ -963,10 +996,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(endmacro) self.body.append(endmacro)
if not self.table.longtable and self.table.caption is not None: if not self.table.longtable and self.table.caption is not None:
self.body.append('\\end{threeparttable}\n\n') self.body.append('\\end{threeparttable}\n\n')
if self.table.footnotes: self.unrestrict_footnote(node)
for footnode in self.table.footnotes:
footnode['footnotetext'] = True
footnode.walkabout(self)
self.table = None self.table = None
self.tablebody = None self.tablebody = None
@ -1078,6 +1108,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
context += str(extracols + 1) context += str(extracols + 1)
context += '}{l|}{}' context += '}{l|}{}'
self.table.col += extracols self.table.col += extracols
if len(node.traverse(nodes.paragraph)) >= 2:
self.table.has_problematic = True
self.context.append(context) self.context.append(context)
def depart_entry(self, node): def depart_entry(self, node):
@ -1140,16 +1172,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
if node.get('ids'): if node.get('ids'):
ctx += self.hypertarget(node['ids'][0]) ctx += self.hypertarget(node['ids'][0])
self.body.append('\\item[{') self.body.append('\\item[{')
self.termfootnotestack.append([]) self.restrict_footnote(node)
self.context.append(ctx) self.context.append(ctx)
def depart_term(self, node): def depart_term(self, node):
self.body.append(self.context.pop()) self.body.append(self.context.pop())
footnotes = self.termfootnotestack.pop() self.unrestrict_footnote(node)
for footnode in footnotes:
footnode['footnotetext'] = True
footnode.walkabout(self)
self.in_term -= 1 self.in_term -= 1
def visit_termsep(self, node): def visit_termsep(self, node):
@ -1264,12 +1292,12 @@ class LaTeXTranslator(nodes.NodeVisitor):
(1, 'top'): ('', ''), (1, 'top'): ('', ''),
(1, 'middle'): ('\\raisebox{-0.5\\height}{', '}'), (1, 'middle'): ('\\raisebox{-0.5\\height}{', '}'),
(1, 'bottom'): ('\\raisebox{-\\height}{', '}'), (1, 'bottom'): ('\\raisebox{-\\height}{', '}'),
(0, 'center'): ('{\\hfill', '\\hfill}'), (0, 'center'): ('{\\hspace*{\\fill}', '\\hspace*{\\fill}}'),
# These 2 don't exactly do the right thing. The image should # These 2 don't exactly do the right thing. The image should
# be floated alongside the paragraph. See # be floated alongside the paragraph. See
# http://www.w3.org/TR/html4/struct/objects.html#adef-align-IMG # http://www.w3.org/TR/html4/struct/objects.html#adef-align-IMG
(0, 'left'): ('{', '\\hfill}'), (0, 'left'): ('{', '\\hspace*{\\fill}}'),
(0, 'right'): ('{\\hfill', '}'), (0, 'right'): ('{\\hspace*{\\fill}', '}'),
} }
try: try:
pre.append(align_prepost[is_inline, attrs['align']][0]) pre.append(align_prepost[is_inline, attrs['align']][0])
@ -1306,6 +1334,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
for id in self.next_figure_ids: for id in self.next_figure_ids:
ids += self.hypertarget(id, anchor=False) ids += self.hypertarget(id, anchor=False)
self.next_figure_ids.clear() self.next_figure_ids.clear()
self.restrict_footnote(node)
if (len(node.children) and if (len(node.children) and
isinstance(node.children[0], nodes.image) and isinstance(node.children[0], nodes.image) and
node.children[0]['ids']): node.children[0]['ids']):
@ -1333,6 +1362,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def depart_figure(self, node): def depart_figure(self, node):
self.body.append(self.context.pop()) self.body.append(self.context.pop())
self.unrestrict_footnote(node)
def visit_caption(self, node): def visit_caption(self, node):
self.in_caption += 1 self.in_caption += 1
@ -1668,18 +1698,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\\protect\\footnotemark[%s]' % num) self.body.append('\\protect\\footnotemark[%s]' % num)
else: else:
self.body.append('\\footnotemark[%s]' % num) self.body.append('\\footnotemark[%s]' % num)
elif self.table: elif self.footnote_restricted:
self.footnotestack[-1][num][1] = True self.footnotestack[-1][num][1] = True
self.body.append('\\protect\\footnotemark[%s]' % num) self.body.append('\\protect\\footnotemark[%s]' % num)
self.table.footnotes.append(footnode) self.pending_footnotes.append(footnode)
elif self.in_term:
self.body.append('\\footnotemark[%s]' % num)
self.termfootnotestack[-1].append(footnode)
else: else:
if self.in_caption:
raise UnsupportedError('%s:%s: footnotes in float captions '
'are not supported by LaTeX' %
(self.curfilestack[-1], node.line))
self.footnotestack[-1][num][1] = True self.footnotestack[-1][num][1] = True
footnode.walkabout(self) footnode.walkabout(self)
raise nodes.SkipChildren raise nodes.SkipChildren

View File

@ -30,12 +30,42 @@ class ManualPageWriter(Writer):
self.builder.translator_class or ManualPageTranslator) self.builder.translator_class or ManualPageTranslator)
def translate(self): def translate(self):
transform = NestedInlineTransform(self.document)
transform.apply()
visitor = self.translator_class(self.builder, self.document) visitor = self.translator_class(self.builder, self.document)
self.visitor = visitor self.visitor = visitor
self.document.walkabout(visitor) self.document.walkabout(visitor)
self.output = visitor.astext() self.output = visitor.astext()
class NestedInlineTransform(object):
"""
Flatten nested inline nodes:
Before:
<strong>foo=<emphasis>1</emphasis>&bar=<emphasis>2</emphasis></strong>
After:
<strong>foo=</strong><emphasis>var</emphasis><strong>&bar=</strong><emphasis>2</emphasis>
"""
def __init__(self, document):
self.document = document
def apply(self):
def is_inline(node):
return isinstance(node, (nodes.literal, nodes.emphasis, nodes.strong))
for node in self.document.traverse(is_inline):
if any(is_inline(subnode) for subnode in node):
pos = node.parent.index(node)
for subnode in reversed(node[1:]):
node.remove(subnode)
if is_inline(subnode):
node.parent.insert(pos + 1, subnode)
else:
newnode = node.__class__('', subnode, **node.attributes)
node.parent.insert(pos + 1, newnode)
class ManualPageTranslator(BaseTranslator): class ManualPageTranslator(BaseTranslator):
""" """
Custom translator. Custom translator.

View File

@ -7,7 +7,7 @@ This is inline math: :math:`a^2 + b^2 = c^2`.
.. math:: .. math::
a^2 + b^2 = c^2 a + 1 < b
.. math:: .. math::
:label: foo :label: foo
@ -23,4 +23,9 @@ This is inline math: :math:`a^2 + b^2 = c^2`.
n \in \mathbb N n \in \mathbb N
.. math::
:nowrap:
a + 1 < b
Referencing equation :eq:`foo`. Referencing equation :eq:`foo`.

View File

@ -174,7 +174,17 @@ Others
.. option:: arg .. option:: arg
Link to :option:`perl +p` and :option:`arg`. Link to :option:`perl +p` and :option:`arg`
.. program:: hg
.. option:: commit
.. program:: git commit
.. option:: -p
Link to :option:`hg commit` and :option:`git commit -p`.
User markup User markup

View File

@ -7,3 +7,5 @@ extensions = ['sphinx.ext.autosummary']
# The suffix of source filenames. # The suffix of source filenames.
source_suffix = '.rst' source_suffix = '.rst'
autosummary_generate = True autosummary_generate = True
exclude_patterns = ['_build']

View File

@ -1,2 +1,3 @@
master_doc = 'contents' master_doc = 'contents'
source_suffix = '.txt' source_suffix = '.txt'
exclude_patterns = ['_build']

View File

@ -0,0 +1 @@
exclude_patterns = ['_build']

View File

@ -2,3 +2,4 @@
master_doc = 'index' master_doc = 'index'
html_theme = 'classic' html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
master_doc = 'index' master_doc = 'index'
exclude_patterns = ['_build']

View File

@ -1,2 +1,3 @@
project = 'test-directive-only' project = 'test-directive-only'
exclude_patterns = ['_build']

View File

@ -1,5 +1,6 @@
extensions = ['sphinx.ext.doctest'] extensions = ['sphinx.ext.doctest']
project = 'test project for doctest' project = 'test project for doctest'
master_doc = 'doctest.txt' master_doc = 'doctest'
source_suffix = '.txt' source_suffix = '.txt'
exclude_patterns = ['_build']

View File

@ -136,3 +136,14 @@ umlauts: äöü.
>>> print('Japanese: 日本語') >>> print('Japanese: 日本語')
Japanese: 日本語 Japanese: 日本語
keep control char in raw string
-------------------------------
.. doctest::
>>> print('one\ntwo')
one
two
>>> print(r'one\ntwo')
one\ntwo

View File

@ -3,3 +3,4 @@
project = 'Sphinx docutils conf <Tests>' project = 'Sphinx docutils conf <Tests>'
source_suffix = '.txt' source_suffix = '.txt'
keep_warnings = True keep_warnings = True
exclude_patterns = ['_build']

View File

@ -0,0 +1,10 @@
any role
--------
* :cpp:any:`Sphinx`
* ref function without parens :cpp:any:`hello`.
* ref function with parens :cpp:any:`hello()`.
* :cpp:any:`Sphinx::version`
* :cpp:any:`version`
* :cpp:any:`List`
* :cpp:any:`MyEnum`

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -0,0 +1,37 @@
test-domain-cpp
===============
directives
----------
.. cpp:class:: public Sphinx
The description of Sphinx class.
.. cpp:function:: int hello(char *name)
The description of hello function.
.. cpp:member:: float Sphinx::version
The description of Sphinx::version.
.. cpp:var:: int version
The description of version.
.. cpp:type:: std::vector<int> List
The description of List type.
.. cpp:enum:: MyEnum
An unscoped enum.
.. cpp:enum-class:: MyScopedEnum
A scoped enum.
.. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type<MySpecificEnum>::type
A scoped enum with non-default visibility, and with a specified underlying type.

View File

@ -0,0 +1,10 @@
roles
-----
* :cpp:class:`Sphinx`
* ref function without parens :cpp:func:`hello`.
* ref function with parens :cpp:func:`hello()`.
* :cpp:member:`Sphinx::version`
* :cpp:var:`version`
* :cpp:type:`List`
* :cpp:enum:`MyEnum`

View File

@ -5,3 +5,4 @@ import sys, os
templates_path = ['_templates'] templates_path = ['_templates']
master_doc = 'index' master_doc = 'index'
html_theme = 'base_theme2' html_theme = 'base_theme2'
exclude_patterns = ['_build']

View File

@ -2,3 +2,4 @@
extensions = ['sphinx.ext.graphviz'] extensions = ['sphinx.ext.graphviz']
master_doc = 'index' master_doc = 'index'
exclude_patterns = ['_build']

View File

@ -2,6 +2,7 @@
extensions = ['sphinx.ext.ifconfig'] extensions = ['sphinx.ext.ifconfig']
master_doc = 'index' master_doc = 'index'
exclude_patterns = ['_build']
confval1 = True confval1 = True

View File

@ -6,6 +6,7 @@ import os
sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('.'))
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
master_doc = 'index' master_doc = 'index'
exclude_patterns = ['_build']
if 'test_linkcode' in tags: if 'test_linkcode' in tags:

View File

@ -2,3 +2,4 @@
master_doc = 'index' master_doc = 'index'
html_theme = 'classic' html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -33,9 +33,11 @@ The section with a reference to [AuthorYear]_
.. [1] Second .. [1] Second
.. [#] Third .. [#] Third
The section with a reference to [1]_ The section with a reference to [#]_
===================================== =====================================
.. [#] Footnote in section
`URL in term <http://sphinx-doc.org/>`_ `URL in term <http://sphinx-doc.org/>`_
Description Description Description ... Description Description Description ...
@ -46,3 +48,95 @@ Footnote in term [#]_
Description2 Description2
.. [#] Footnote in term .. [#] Footnote in term
.. figure:: rimg.png
This is the figure caption with a footnote to [#]_.
.. [#] Footnote in caption
.. list-table:: footnote [#]_ in caption of normal table
:widths: 1 1
:header-rows: 1
* - name
- desc
* - a
- b
* - a
- b
.. [#] Foot note in table
.. list-table:: footnote [#]_ in caption of longtable
:widths: 1 1
:header-rows: 1
* - name
- desc
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
* - a
- b
.. [#] Foot note in longtable

View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
exclude_patterns = ['_build']
rst_epilog = '''
.. |picture| image:: pic.png
:width: 15pt
:height: 15pt
:alt: alternative_text
'''

View File

@ -0,0 +1,18 @@
test-image-in-section
=====================
this is dummy content
|picture| Test section
----------------------
blah blah blah
Another section
---------------
another blah
Other [blah] |picture| section
------------------------------
other blah

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -7,3 +7,4 @@ templates_path = ['_templates']
html_additional_pages = {'index': 'index.html'} html_additional_pages = {'index': 'index.html'}
release = version = '2013.120' release = version = '2013.120'
gettext_additional_targets = ['index'] gettext_additional_targets = ['index']
exclude_patterns = ['_build']

View File

@ -25,14 +25,14 @@ msgstr "SOME TERM"
msgid "The corresponding definition" msgid "The corresponding definition"
msgstr "THE CORRESPONDING DEFINITION" msgstr "THE CORRESPONDING DEFINITION"
msgid "Some other term" msgid "Some *term* `with link <http://sphinx-doc.org/>`__"
msgstr "SOME OTHER TERM" msgstr "SOME *TERM* `WITH LINK <http://sphinx-doc.org/>`__"
msgid "The corresponding definition #2" msgid "The corresponding definition #2"
msgstr "THE CORRESPONDING DEFINITION #2" msgstr "THE CORRESPONDING DEFINITION #2"
msgid "Some term with" msgid "Some **term** with"
msgstr "SOME TERM WITH" msgstr "SOME **TERM** WITH"
msgid "classifier1" msgid "classifier1"
msgstr "CLASSIFIER1" msgstr "CLASSIFIER1"

View File

@ -6,9 +6,9 @@ i18n with definition terms
Some term Some term
The corresponding definition The corresponding definition
Some other term Some *term* `with link <http://sphinx-doc.org/>`__
The corresponding definition #2 The corresponding definition #2
Some term with : classifier1 : classifier2 Some **term** with : classifier1 : classifier2
The corresponding definition The corresponding definition

View File

@ -0,0 +1 @@
exclude_patterns = ['_build']

View File

@ -2,3 +2,4 @@
master_doc = 'index' master_doc = 'index'
html_theme = 'classic' html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -3,3 +3,4 @@
project = 'Sphinx smallest project' project = 'Sphinx smallest project'
source_suffix = '.txt' source_suffix = '.txt'
keep_warnings = True keep_warnings = True
exclude_patterns = ['_build']

View File

@ -5,6 +5,7 @@ source_suffix = '.txt'
keep_warnings = True keep_warnings = True
templates_path = ['_templates'] templates_path = ['_templates']
release = version = '2013.120' release = version = '2013.120'
exclude_patterns = ['_build']
extensions = ['sphinx.ext.autosummary'] extensions = ['sphinx.ext.autosummary']
autosummary_generate = ['autosummary_templating'] autosummary_generate = ['autosummary_templating']

View File

@ -2,4 +2,5 @@
html_theme = 'test-theme' html_theme = 'test-theme'
master_doc = 'index' master_doc = 'index'
exclude_patterns = ['_build']

View File

@ -2,3 +2,4 @@
master_doc = 'index' master_doc = 'index'
html_theme = 'classic' html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -2,3 +2,4 @@
master_doc = 'index' master_doc = 'index'
html_theme = 'classic' html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -0,0 +1,27 @@
:tocdepth: 2
===
Bar
===
should be 2
Bar A
=====
should be 2.1
.. toctree::
baz
Bar B
=====
should be 2.2
Bar B1
------
should be 2.2.1

View File

@ -0,0 +1,5 @@
Baz A
-----
should be 2.1.1

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
html_theme = 'classic'
exclude_patterns = ['_build']

View File

@ -0,0 +1,26 @@
===
Foo
===
should be 1
Foo A
=====
should be 1.1
Foo A1
------
should be 1.1.1
Foo B
=====
should be 1.2
Foo B1
------
should be 1.2.1

View File

@ -0,0 +1,9 @@
test-toctree-max-depth
======================
.. toctree::
:numbered:
:maxdepth: 2
foo
bar

View File

@ -1,3 +1,4 @@
project = 'versioning test root' project = 'versioning test root'
master_doc = 'index' master_doc = 'index'
source_suffix = '.txt' source_suffix = '.txt'
exclude_patterns = ['_build']

View File

@ -12,6 +12,7 @@
from six import BytesIO from six import BytesIO
from textwrap import dedent from textwrap import dedent
from sphinx.errors import SphinxError
from util import with_app, rootdir, tempdir, SkipTest, TestApp from util import with_app, rootdir, tempdir, SkipTest, TestApp
@ -73,6 +74,18 @@ def test_build_all():
yield verify_build, buildername, srcdir yield verify_build, buildername, srcdir
@with_app(buildername='text')
def test_master_doc_not_found(app, status, warning):
(app.srcdir / 'contents.txt').move(app.srcdir / 'contents.txt.bak')
try:
app.builder.build_all()
assert False # SphinxError not raised
except Exception as exc:
assert isinstance(exc, SphinxError)
finally:
(app.srcdir / 'contents.txt.bak').move(app.srcdir / 'contents.txt')
@with_app(buildername='text', testroot='circular') @with_app(buildername='text', testroot='circular')
def test_circular_toctree(app, status, warning): def test_circular_toctree(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -16,7 +16,7 @@ from six import PY3, iteritems
from six.moves import html_entities from six.moves import html_entities
from sphinx import __display_version__ from sphinx import __display_version__
from util import remove_unicode_literals, gen_with_app from util import remove_unicode_literals, gen_with_app, with_app
from etree13 import ElementTree as ET from etree13 import ElementTree as ET
@ -31,9 +31,7 @@ http://www.python.org/logo.png
reading included file u'.*?wrongenc.inc' seems to be wrong, try giving an \ reading included file u'.*?wrongenc.inc' seems to be wrong, try giving an \
:encoding: option\\n? :encoding: option\\n?
%(root)s/includes.txt:4: WARNING: download file not readable: .*?nonexisting.png %(root)s/includes.txt:4: WARNING: download file not readable: .*?nonexisting.png
(%(root)s/markup.txt:\\d+: WARNING: Malformed :option: u'&option', does \ (%(root)s/undecodable.txt:3: WARNING: undecodable source characters, replacing \
not contain option marker - or -- or / or \\+
%(root)s/undecodable.txt:3: WARNING: undecodable source characters, replacing \
with "\\?": b?'here: >>>(\\\\|/)xbb<<<' with "\\?": b?'here: >>>(\\\\|/)xbb<<<'
)?""" )?"""
@ -234,6 +232,23 @@ HTML_XPATH = {
(".//td[@class='field-body']/ul/li/strong", '^hour$'), (".//td[@class='field-body']/ul/li/strong", '^hour$'),
(".//td[@class='field-body']/ul/li/em", '^DuplicateType$'), (".//td[@class='field-body']/ul/li/em", '^DuplicateType$'),
(".//td[@class='field-body']/ul/li/em", tail_check(r'.* Some parameter')), (".//td[@class='field-body']/ul/li/em", tail_check(r'.* Some parameter')),
# others
(".//a[@class='reference internal'][@href='#cmdoption-perl-arg-+p']/code/span",
'perl'),
(".//a[@class='reference internal'][@href='#cmdoption-perl-arg-+p']/code/span",
'\+p'),
(".//a[@class='reference internal'][@href='#cmdoption-perl-arg-arg']/code/span",
'arg'),
(".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
'hg'),
(".//a[@class='reference internal'][@href='#cmdoption-hg-arg-commit']/code/span",
'commit'),
(".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'git'),
(".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'commit'),
(".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'-p'),
], ],
'contents.html': [ 'contents.html': [
(".//meta[@name='hc'][@content='hcval']", ''), (".//meta[@name='hc'][@content='hcval']", ''),
@ -914,3 +929,18 @@ def test_numfig_with_secnum_depth(app, status, warning):
for xpath, check, be_found in paths: for xpath, check, be_found in paths:
yield check_xpath, etree, fname, xpath, check, be_found yield check_xpath, etree, fname, xpath, check, be_found
@with_app(buildername='html')
def test_jsmath(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'math.html').text()
assert '<div class="math">\na^2 + b^2 = c^2</div>' in content
assert '<div class="math">\n\\begin{split}a + 1 &lt; b\\end{split}</div>' in content
assert ('<span class="eqno">(1)</span><div class="math" id="equation-foo">\n'
'e^{i\\pi} = 1</div>' in content)
assert ('<span class="eqno">(2)</span><div class="math">\n'
'e^{ix} = \\cos x + i\\sin x</div>' in content)
assert '<div class="math">\nn \\in \\mathbb N</div>' in content
assert '<div class="math">\na + 1 &lt; b</div>' in content

View File

@ -16,6 +16,7 @@ from subprocess import Popen, PIPE
from six import PY3 from six import PY3
from sphinx.errors import SphinxError
from sphinx.writers.latex import LaTeXTranslator from sphinx.writers.latex import LaTeXTranslator
from util import SkipTest, remove_unicode_literals, with_app from util import SkipTest, remove_unicode_literals, with_app
@ -334,7 +335,17 @@ def test_reference_in_caption(app, status, warning):
assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result assert '\\chapter{The section with a reference to {[}AuthorYear{]}}' in result
assert '\\caption{The table title 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 '\\paragraph{The rubric title with a reference to {[}AuthorYear{]}}' in result
assert '\\chapter{The section with a reference to \\protect\\footnotemark[1]}' in result assert ('\\chapter{The section with a reference to \\protect\\footnotemark[4]}\n'
'\\label{index:the-section-with-a-reference-to}'
'\\footnotetext[4]{\nFootnote in section\n}' in result)
assert ('\\caption{This is the figure caption with a footnote to '
'\\protect\\footnotemark[6].}\end{figure}\n'
'\\footnotetext[6]{\nFootnote in caption\n}')in result
assert ('\\caption{footnote \\protect\\footnotemark[7] '
'in caption of normal table}') in result
assert '\\end{threeparttable}\n\n\\footnotetext[7]{\nFoot note in table\n}' in result
assert '\\caption{footnote \\protect\\footnotemark[8] in caption of longtable}' in result
assert '\end{longtable}\n\n\\footnotetext[8]{\nFoot note in longtable\n}' in result
@with_app(buildername='latex', testroot='footnotes', @with_app(buildername='latex', testroot='footnotes',
@ -353,8 +364,8 @@ def test_latex_show_urls_is_inline(app, status, warning):
'(http://sphinx-doc.org/\\textasciitilde{}test/)' in result) '(http://sphinx-doc.org/\\textasciitilde{}test/)' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term} (http://sphinx-doc.org/)}] ' assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term} (http://sphinx-doc.org/)}] '
'\\leavevmode\nDescription' in result) '\\leavevmode\nDescription' in result)
assert ('\\item[{Footnote in term \\footnotemark[4]}] ' assert ('\\item[{Footnote in term \\protect\\footnotemark[5]}] '
'\\leavevmode\\footnotetext[4]{\nFootnote in term\n}\nDescription' in result) '\\leavevmode\\footnotetext[5]{\nFootnote in term\n}\nDescription' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist} ' assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist} '
'(http://sphinx-doc.org/)}] \\leavevmode\nDescription' in result) '(http://sphinx-doc.org/)}] \\leavevmode\nDescription' in result)
assert ('\\href{https://github.com/sphinx-doc/sphinx}' assert ('\\href{https://github.com/sphinx-doc/sphinx}'
@ -378,12 +389,12 @@ def test_latex_show_urls_is_footnote(app, status, warning):
assert 'Third footnote: \\footnote[5]{\nThird\n}' in result assert 'Third footnote: \\footnote[5]{\nThird\n}' in result
assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde}' assert ('\\href{http://sphinx-doc.org/~test/}{URL including tilde}'
'\\footnote[4]{\nhttp://sphinx-doc.org/\\textasciitilde{}test/\n}' in result) '\\footnote[4]{\nhttp://sphinx-doc.org/\\textasciitilde{}test/\n}' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\footnotemark[6]}] ' assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}\\protect\\footnotemark[7]}] '
'\\leavevmode\\footnotetext[6]{\nhttp://sphinx-doc.org/\n}\nDescription' in result)
assert ('\\item[{Footnote in term \\footnotemark[8]}] '
'\\leavevmode\\footnotetext[8]{\nFootnote in term\n}\nDescription' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\footnotemark[7]}] '
'\\leavevmode\\footnotetext[7]{\nhttp://sphinx-doc.org/\n}\nDescription' in result) '\\leavevmode\\footnotetext[7]{\nhttp://sphinx-doc.org/\n}\nDescription' in result)
assert ('\\item[{Footnote in term \\protect\\footnotemark[9]}] '
'\\leavevmode\\footnotetext[9]{\nFootnote in term\n}\nDescription' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}\\protect\\footnotemark[8]}] '
'\\leavevmode\\footnotetext[8]{\nhttp://sphinx-doc.org/\n}\nDescription' in result)
assert ('\\href{https://github.com/sphinx-doc/sphinx}' assert ('\\href{https://github.com/sphinx-doc/sphinx}'
'{https://github.com/sphinx-doc/sphinx}\n' in result) '{https://github.com/sphinx-doc/sphinx}\n' in result)
assert ('\\href{mailto:sphinx-dev@googlegroups.com}' assert ('\\href{mailto:sphinx-dev@googlegroups.com}'
@ -405,11 +416,61 @@ def test_latex_show_urls_is_no(app, status, warning):
assert '\\href{http://sphinx-doc.org/~test/}{URL including tilde}' in result assert '\\href{http://sphinx-doc.org/~test/}{URL including tilde}' in result
assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}}] ' assert ('\\item[{\\href{http://sphinx-doc.org/}{URL in term}}] '
'\\leavevmode\nDescription' in result) '\\leavevmode\nDescription' in result)
assert ('\\item[{Footnote in term \\footnotemark[4]}] ' assert ('\\item[{Footnote in term \\protect\\footnotemark[5]}] '
'\\leavevmode\\footnotetext[4]{\nFootnote in term\n}\nDescription' in result) '\\leavevmode\\footnotetext[5]{\nFootnote in term\n}\nDescription' in result)
assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}}] ' assert ('\\item[{\\href{http://sphinx-doc.org/}{Term in deflist}}] '
'\\leavevmode\nDescription' in result) '\\leavevmode\nDescription' in result)
assert ('\\href{https://github.com/sphinx-doc/sphinx}' assert ('\\href{https://github.com/sphinx-doc/sphinx}'
'{https://github.com/sphinx-doc/sphinx}\n' in result) '{https://github.com/sphinx-doc/sphinx}\n' in result)
assert ('\\href{mailto:sphinx-dev@googlegroups.com}' assert ('\\href{mailto:sphinx-dev@googlegroups.com}'
'{sphinx-dev@googlegroups.com}\n' in result) '{sphinx-dev@googlegroups.com}\n' in result)
@with_app(buildername='latex', testroot='image-in-section')
def test_image_in_section(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert ('\chapter[Test section]{\includegraphics[width=15pt,height=15pt]{{pic}.png} Test section}'
in result)
assert ('\chapter[Other {[}blah{]} section]{Other {[}blah{]} \includegraphics[width=15pt,height=15pt]{{pic}.png} section}' in result)
assert ('\chapter{Another section}' in result)
@with_app(buildername='latex', confoverrides={'latex_logo': 'notfound.jpg'})
def test_latex_logo_if_not_found(app, status, warning):
try:
app.builder.build_all()
assert False # SphinxError not raised
except Exception as exc:
assert isinstance(exc, SphinxError)
@with_app(buildername='latex', testroot='toctree-maxdepth',
confoverrides={'latex_documents': [
('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'manual'),
]})
def test_toctree_maxdepth_manual(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\setcounter{tocdepth}{1}' in result
@with_app(buildername='latex', testroot='toctree-maxdepth',
confoverrides={'latex_documents': [
('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
'Georg Brandl', 'howto'),
]})
def test_toctree_maxdepth_howto(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'SphinxTests.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\setcounter{tocdepth}{2}' in result

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
"""
test_build_manpage
~~~~~~~~~~~~~~~~~~
Test the build process with manpage builder with the test root.
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function
from util import with_app
@with_app(buildername='man')
def test_all(app, status, warning):
app.builder.build_all()
assert (app.outdir / 'SphinxTests.1').exists()
content = (app.outdir / 'SphinxTests.1').text()
assert r'\fBprint \fP\fIi\fP\fB\en\fP' in content

View File

@ -9,9 +9,11 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import re
from six import text_type from six import text_type
from util import raises from util import raises, with_app
from sphinx import addnodes from sphinx import addnodes
from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError
@ -393,3 +395,49 @@ def test_templates():
# for a in ids: # for a in ids:
# print(a) # print(a)
# raise DefinitionError("") # raise DefinitionError("")
@with_app(testroot='domain-cpp')
def test_build_domain_cpp(app, status, warning):
app.builder.build_all()
roles = (app.outdir / 'roles.html').text()
assert re.search('<li><a .*?><code .*?><span .*?>Sphinx</span></code></a></li>', roles)
assert re.search(('<li>ref function without parens <a .*?><code .*?><span .*?>'
'hello\(\)</span></code></a>\.</li>'), roles)
assert re.search(('<li>ref function with parens <a .*?><code .*?><span .*?>'
'hello\(\)</span></code></a>\.</li>'), roles)
assert re.search('<li><a .*?><code .*?><span .*?>Sphinx::version</span></code></a></li>',
roles)
assert re.search('<li><a .*?><code .*?><span .*?>version</span></code></a></li>', roles)
assert re.search('<li><a .*?><code .*?><span .*?>List</span></code></a></li>', roles)
assert re.search('<li><a .*?><code .*?><span .*?>MyEnum</span></code></a></li>', roles)
any_role = (app.outdir / 'any-role.html').text()
assert re.search('<li><a .*?><code .*?><span .*?>Sphinx</span></code></a></li>', any_role)
assert re.search(('<li>ref function without parens <a .*?><code .*?><span .*?>'
'hello\(\)</span></code></a>\.</li>'), any_role)
assert re.search(('<li>ref function with parens <a .*?><code .*?><span .*?>'
'hello\(\)</span></code></a>\.</li>'), any_role)
assert re.search('<li><a .*?><code .*?><span .*?>Sphinx::version</span></code></a></li>',
any_role)
assert re.search('<li><a .*?><code .*?><span .*?>version</span></code></a></li>', any_role)
assert re.search('<li><a .*?><code .*?><span .*?>List</span></code></a></li>', any_role)
assert re.search('<li><a .*?><code .*?><span .*?>MyEnum</span></code></a></li>', any_role)
@with_app(testroot='domain-cpp', confoverrides={'add_function_parentheses': False})
def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, warning):
app.builder.build_all()
roles = (app.outdir / 'roles.html').text()
assert re.search(('<li>ref function without parens <a .*?><code .*?><span .*?>'
'hello</span></code></a>\.</li>'), roles)
assert re.search(('<li>ref function with parens <a .*?><code .*?><span .*?>'
'hello</span></code></a>\.</li>'), roles)
any_role = (app.outdir / 'any-role.html').text()
assert re.search(('<li>ref function without parens <a .*?><code .*?><span .*?>'
'hello</span></code></a>\.</li>'), any_role)
assert re.search(('<li>ref function with parens <a .*?><code .*?><span .*?>'
'hello</span></code></a>\.</li>'), any_role)

View File

@ -16,6 +16,7 @@ import re
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from xml.etree import ElementTree from xml.etree import ElementTree
from babel.messages import pofile
from nose.tools import assert_equal from nose.tools import assert_equal
from six import string_types from six import string_types
@ -40,6 +41,11 @@ def gen_with_intl_app(builder, confoverrides={}, *args, **kw):
return gen_with_app(builder, *args, **default_kw) return gen_with_app(builder, *args, **default_kw)
def read_po(pathname):
with pathname.open() as f:
return pofile.read_po(f)
def setup_module(): def setup_module():
if not root.exists(): if not root.exists():
(rootdir / 'roots' / 'test-intl').copytree(root) (rootdir / 'roots' / 'test-intl').copytree(root)
@ -175,16 +181,16 @@ def test_text_builder(app, status, warning):
u'WARNING: Literal block expected; none found.' u'WARNING: Literal block expected; none found.'
yield assert_re_search, expected_warning_expr, warnings yield assert_re_search, expected_warning_expr, warnings
# --- definition terms: regression test for #975 # --- definition terms: regression test for #975, #2198, #2205
result = (app.outdir / 'definition_terms.txt').text(encoding='utf-8') result = (app.outdir / 'definition_terms.txt').text(encoding='utf-8')
expect = (u"\nI18N WITH DEFINITION TERMS" expect = (u"\nI18N WITH DEFINITION TERMS"
u"\n**************************\n" u"\n**************************\n"
u"\nSOME TERM" u"\nSOME TERM"
u"\n THE CORRESPONDING DEFINITION\n" u"\n THE CORRESPONDING DEFINITION\n"
u"\nSOME OTHER TERM" u"\nSOME *TERM* WITH LINK"
u"\n THE CORRESPONDING DEFINITION #2\n" u"\n THE CORRESPONDING DEFINITION #2\n"
u"\nSOME TERM WITH : CLASSIFIER1 : CLASSIFIER2" u"\nSOME **TERM** WITH : CLASSIFIER1 : CLASSIFIER2"
u"\n THE CORRESPONDING DEFINITION\n" u"\n THE CORRESPONDING DEFINITION\n"
) )
yield assert_equal, result, expect yield assert_equal, result, expect
@ -280,8 +286,8 @@ def test_text_builder(app, status, warning):
u"\n * **foo** -- DESCRIPTION OF PARAMETER foo\n" u"\n * **foo** -- DESCRIPTION OF PARAMETER foo\n"
u"\n * **bar** -- DESCRIPTION OF PARAMETER bar\n" u"\n * **bar** -- DESCRIPTION OF PARAMETER bar\n"
u"\nclass Cls3(values)\n" u"\nclass Cls3(values)\n"
u"\n Raises ValueError:" u"\n Raises:"
u"\n IF THE VALUES ARE OUT OF RANGE\n" u"\n **ValueError** -- IF THE VALUES ARE OUT OF RANGE\n"
u"\nclass Cls4(values)\n" u"\nclass Cls4(values)\n"
u"\n Raises:" u"\n Raises:"
u"\n * **TypeError** -- IF THE VALUES ARE NOT VALID\n" u"\n * **TypeError** -- IF THE VALUES ARE NOT VALID\n"
@ -304,6 +310,31 @@ def test_text_builder(app, status, warning):
yield assert_in, d.upper() + " BODY", result yield assert_in, d.upper() + " BODY", result
@gen_with_intl_app('gettext', freshenv=True)
def test_gettext_builder(app, status, warning):
app.builder.build_all()
# --- definition terms: regression test for #2198, #2205
expect = read_po(app.srcdir / 'definition_terms.po')
actual = read_po(app.outdir / 'definition_terms.pot')
for expect_msg in [m for m in expect if m.id]:
yield assert_in, expect_msg.id, [m.id for m in actual if m.id]
# --- glossary terms: regression test for #1090
expect = read_po(app.srcdir / 'glossary_terms.po')
actual = read_po(app.outdir / 'glossary_terms.pot')
for expect_msg in [m for m in expect if m.id]:
yield assert_in, expect_msg.id, [m.id for m in actual if m.id]
warnings = warning.getvalue().replace(os.sep, '/')
yield assert_not_in, 'term not in glossary', warnings
# --- glossary term inconsistencies: regression test for #1090
expect = read_po(app.srcdir / 'glossary_terms_inconsistency.po')
actual = read_po(app.outdir / 'glossary_terms_inconsistency.pot')
for expect_msg in [m for m in expect if m.id]:
yield assert_in, expect_msg.id, [m.id for m in actual if m.id]
@gen_with_intl_app('html', freshenv=True) @gen_with_intl_app('html', freshenv=True)
def test_html_builder(app, status, warning): def test_html_builder(app, status, warning):
app.builder.build_all() app.builder.build_all()

View File

@ -55,7 +55,8 @@ def test_catalog_write_mo(dir):
cat = i18n.CatalogInfo(dir, 'test', 'utf-8') cat = i18n.CatalogInfo(dir, 'test', 'utf-8')
cat.write_mo('en') cat.write_mo('en')
assert path.exists(cat.mo_path) assert path.exists(cat.mo_path)
assert read_mo(open(cat.mo_path, 'rb')) is not None with open(cat.mo_path, 'rb') as f:
assert read_mo(f) is not None
@with_tempdir @with_tempdir