Merge branch 'stable'

This commit is contained in:
Takeshi KOMIYA 2017-06-13 00:32:39 +09:00
commit f6d0b07704
9 changed files with 245 additions and 189 deletions

View File

@ -75,6 +75,11 @@ Bugs fixed
* #3829: sphinx-quickstart template is incomplete regarding use of alabaster
* #3772: 'str object' has no attribute 'filename'
* Emit wrong warnings if citation label includes hyphens (refs: #3565)
* #3858: Some warnings are not colored when using --color option
* #3775: Remove unwanted whitespace in default template
* #3835: sphinx.ext.imgmath fails to convert SVG images if project directory
name contains spaces
* #3850: Fix color handling in make mode's help command
Testing
--------

View File

@ -206,11 +206,17 @@ The builder's "name" must be given to the **-b** command-line option of
.. autoattribute:: supported_image_types
Note that a direct PDF builder using ReportLab is available in `rst2pdf
<https://github.com/rst2pdf/rst2pdf>`_ version 0.12 or greater. You need to add
``'rst2pdf.pdfbuilder'`` to your :confval:`extensions` to enable it, its name is
``pdf``. Refer to the `rst2pdf manual <https://ralsina.me/static/manual.pdf>`_
for details.
Note that a direct PDF builder is being provided by `rinohtype`_. The builder's
name is ``rinoh``. Refer to the `rinohtype manual`_ for details. There is also
PDF builder using ReportLab in `rst2pdf`_ version 0.12 or greater. However,
rst2pdf is no longer being actively maintained and suffers from some problems
when used with recent Sphinx versions. See the `rst2pdf manual`_ for usage
instructions.
.. _rinohtype: https://github.com/brechtm/rinohtype
.. _rinohtype manual: http://www.mos6581.org/rinohtype/quickstart.html#sphinx-builder
.. _rst2pdf: https://github.com/rst2pdf/rst2pdf
.. _rst2pdf manual: http://ralsina.me/static/manual.pdf
.. module:: sphinx.builders.text
.. class:: TextBuilder

View File

@ -10,9 +10,13 @@ How do I...
-----------
... create PDF files without LaTeX?
You can use `rst2pdf <https://github.com/rst2pdf/rst2pdf>`_ version 0.12 or
greater which comes with built-in Sphinx integration. See the
:ref:`builders` section for details.
`rinohtype`_ provides a PDF builder that can be used as a drop-in
replacement for the LaTeX builder. Alternatively, you can use `rst2pdf`_
version 0.12 or greater which comes with built-in Sphinx integration. See
the :ref:`builders` section for details.
.. _rinohtype: https://github.com/brechtm/rinohtype
.. _rst2pdf: https://github.com/rst2pdf/rst2pdf
... get section numbers?
They are automatic in LaTeX output; for HTML, give a ``:numbered:`` option to

View File

@ -7,19 +7,21 @@ formats, automatically producing cross-references, indices etc. That is, if
you have a directory containing a bunch of reST-formatted documents (and
possibly subdirectories of docs in there as well), Sphinx can generate a
nicely-organized arrangement of HTML files (in some other directory) for easy
browsing and navigation. But from the same source, it can also generate a
LaTeX file that you can compile into a PDF version of the documents, or a
PDF file directly using `rst2pdf <https://github.com/rst2pdf/rst2pdf>`_.
browsing and navigation. But from the same source, it can also generate a PDF
file using LaTeX, `rinohtype`_ or `rst2pdf`_ (see :ref:`builders`).
The focus is on hand-written documentation, rather than auto-generated API docs.
Though there is support for that kind of docs as well (which is intended to be
freely mixed with hand-written content), if you need pure API docs have a look
at `Epydoc <http://epydoc.sourceforge.net/>`_, which also understands reST.
Though there is support for that kind of documentation as well (which is
intended to be freely mixed with hand-written content), if you need pure API
docs have a look at `Epydoc <http://epydoc.sourceforge.net/>`_, which also
understands reST.
For a great "introduction" to writing docs in general -- the whys and hows, see
also `Write the docs <http://write-the-docs.readthedocs.org/>`_, written by Eric
Holscher.
.. _rinohtype: https://github.com/brechtm/rinohtype
.. _rst2pdf: https://github.com/rst2pdf/rst2pdf
Conversion from other systems
-----------------------------

View File

@ -60,7 +60,7 @@ It is achieved via usage of the
.. highlight:: latex
If the size of the ``'preamble'`` contents become inconvenient, one may put
If the size of the ``'preamble'`` contents becomes inconvenient, one may move
all needed macros into some file :file:`mystyle.tex` of the project source
repertory, and get LaTeX to import it at run time::
@ -166,7 +166,7 @@ The available styling options
For Japanese ``'manual'`` docclass with pointsize ``11pt`` or ``12pt``,
use the ``nomag`` extra document class option (cf.
``'extraclassoptions'`` key of :confval:`latex_elements`) or so-called
TeX "true" units:
TeX "true" units::
'sphinxsetup': 'hmargin=1.5truein, vmargin=1.5truein, marginpar=5zw',
@ -224,9 +224,12 @@ The available styling options
``TitleColor``
default ``{rgb}{0.126,0.263,0.361}``. The colour for titles (as configured
via use of package "titlesec".) It must obey the syntax of the
``\definecolor`` command. Check the documentation of packages ``color`` or
``xcolor``.
via use of package "titlesec".)
.. warning::
Colours set via ``'sphinxsetup'`` must obey the syntax of the
argument of the ``color/xcolor`` packages ``\definecolor`` command.
``InnerLinkColor``
default ``{rgb}{0.208,0.374,0.486}``. A colour passed to ``hyperref`` as
@ -260,85 +263,35 @@ The available styling options
``shadowrule``
default ``\fboxrule``. The width of the frame around :dudir:`topic` boxes.
``noteBorderColor``
default ``{rgb}{0,0,0}``. The colour for the two horizontal rules used by
Sphinx in LaTeX for styling a
:dudir:`note` admonition. Defaults to black.
|notebdcolors|
default ``{rgb}{0,0,0}`` (black). The colour for the two horizontal rules
used by Sphinx in LaTeX for styling a :dudir:`note` type admonition.
.. note::
.. note::
The actual name of the colour as declared to "color" or "xcolor" is
``sphinxnoteBorderColor``. The same "sphinx" prefix applies to all
colours for notices and admonitions.
The actual colour names declared to "color" or "xcolor" are prefixed with
"sphinx".
``hintBorderColor``
default ``{rgb}{0,0,0}``. id.
``importantBorderColor``
default ``{rgb}{0,0,0}``. id.
``tipBorderColor``
default ``{rgb}{0,0,0}``. id.
``noteborder``
``noteborder``, ``hintborder``, ``importantborder``, ``tipborder``
default ``0.5pt``. The width of the two horizontal rules.
``hintborder``
default ``0.5pt``. id.
.. only:: not latex
``importantborder``
default ``0.5pt``. id.
|warningbdcolors|
default ``{rgb}{0,0,0}`` (black). The colour for the admonition frame.
``tipborder``
default ``0.5pt``. id.
.. only:: latex
``warningBorderColor``
default ``{rgb}{0,0,0}``. The colour of the frame for :dudir:`warning` type
admonitions. Defaults to black.
|wgbdcolorslatex|
default ``{rgb}{0,0,0}`` (black). The colour for the admonition frame.
``cautionBorderColor``
default ``{rgb}{0,0,0}``. id.
|warningbgcolors|
default ``{rgb}{1,1,1}`` (white). The background colours for the respective
admonitions.
``attentionBorderColor``
default ``{rgb}{0,0,0}``. id.
``dangerBorderColor``
default ``{rgb}{0,0,0}``. id.
``errorBorderColor``
default ``{rgb}{0,0,0}``. id.
``warningBgColor``
default ``{rgb}{1,1,1}``. The background colour for :dudir:`warning` type
admonition, defaults to white.
``cautionBgColor``
default ``{rgb}{1,1,1}``. id.
``attentionBgColor``
default ``{rgb}{1,1,1}``. id.
``dangerBgColor``
default ``{rgb}{1,1,1}``. id.
``errorBgColor``
default ``{rgb}{1,1,1}``. id.
``warningborder``
|warningborders|
default ``1pt``. The width of the frame.
``cautionborder``
default ``1pt``. id.
``attentionborder``
default ``1pt``. id.
``dangerborder``
default ``1pt``. id.
``errorborder``
default ``1pt``. id.
``AtStartFootnote``
default ``\mbox{ }``. LaTeX macros inserted at the start of the footnote
text at bottom of page, after the footnote number.
@ -353,6 +306,28 @@ The available styling options
``HeaderFamily``
default ``\sffamily\bfseries``. Sets the font used by headings.
.. |notebdcolors| replace:: ``noteBorderColor``, ``hintBorderColor``,
``importantBorderColor``, ``tipBorderColor``
.. |warningbdcolors| replace:: ``warningBorderColor``, ``cautionBorderColor``,
``attentionBorderColor``, ``dangerBorderColor``,
``errorBorderColor``
.. |wgbdcolorslatex| replace:: ``warningBorderColor``, ``cautionBorderColor``,
``attentionB..C..``, ``dangerB..C..``,
``errorB..C..``
.. else latex goes into right margin, as it does not hyphenate the names
.. |warningbgcolors| replace:: ``warningBgColor``, ``cautionBgColor``,
``attentionBgColor``, ``dangerBgColor``,
``errorBgColor``
.. |warningborders| replace:: ``warningBorder``, ``cautionBorder``,
``attentionBorder``, ``dangerBorder``,
``errorBorder``
LaTeX macros and environments
-----------------------------
@ -443,10 +418,10 @@ Environments
.. versionadded:: 1.5
options ``verbatimwithframe``, ``verbatimwrapslines``,
``verbatimsep``, ``verbatimborder``.
- the bibliography and Python Module index are typeset respectively within
environments ``sphinxthebibliography`` and ``sphinxtheindex``, which are
simple wrappers of the non-modified ``thebibliography`` and ``theindex``
environments.
- the bibliography uses ``sphinxthebibliography`` and the Python Module index
as well as the general index both use ``sphinxtheindex``; these environments
are wrappers of the ``thebibliography`` and respectively ``theindex``
environments as provided by the document class (or packages).
.. versionchanged:: 1.5
formerly, the original environments were modified by Sphinx.

View File

@ -33,8 +33,10 @@ from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath
if False:
# For type annotation
from typing import Any, Dict, Tuple # NOQA
from typing import Any, Dict, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.config import Config # NOQA
from sphinx.ext.mathbase import math as math_node, displaymath # NOQA
logger = logging.getLogger(__name__)
@ -52,6 +54,12 @@ class MathExtError(SphinxError):
SphinxError.__init__(self, msg)
class InvokeError(SphinxError):
"""errors on invoking converters."""
SUPPORT_FORMAT = ('png', 'svg')
DOC_HEAD = r'''
\documentclass[12pt]{article}
\usepackage[utf8x]{inputenc}
@ -82,6 +90,131 @@ DOC_BODY_PREVIEW = r'''
depth_re = re.compile(br'\[\d+ depth=(-?\d+)\]')
def generate_latex_macro(math, config):
# type: (unicode, Config) -> unicode
"""Generate LaTeX macro."""
fontsize = config.imgmath_font_size
baselineskip = int(round(fontsize * 1.2))
latex = DOC_HEAD + config.imgmath_latex_preamble
if config.imgmath_use_preview:
latex += DOC_BODY_PREVIEW % (fontsize, baselineskip, math)
else:
latex += DOC_BODY % (fontsize, baselineskip, math)
return latex
def ensure_tempdir(builder):
# type: (Builder) -> unicode
"""Create temporary directory.
use only one tempdir per build -- the use of a directory is cleaner
than using temporary files, since we can clean up everything at once
just removing the whole directory (see cleanup_tempdir)
"""
if not hasattr(builder, '_imgmath_tempdir'):
builder._imgmath_tempdir = tempfile.mkdtemp() # type: ignore
return builder._imgmath_tempdir # type: ignore
def compile_math(latex, builder):
# type: (unicode, Builder) -> unicode
"""Compile LaTeX macros for math to DVI."""
tempdir = ensure_tempdir(builder)
filename = path.join(tempdir, 'math.tex')
with codecs.open(filename, 'w', 'utf-8') as f: # type: ignore
f.write(latex)
# build latex command; old versions of latex don't have the
# --output-directory option, so we have to manually chdir to the
# temp dir to run it.
command = [builder.config.imgmath_latex, '--interaction=nonstopmode']
# add custom args from the config file
command.extend(builder.config.imgmath_latex_args)
command.append('math.tex')
with cd(tempdir):
try:
p = Popen(command, stdout=PIPE, stderr=PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning('LaTeX command %r cannot be run (needed for math '
'display), check the imgmath_latex setting',
builder.config.imgmath_latex)
raise InvokeError
stdout, stderr = p.communicate()
if p.returncode != 0:
raise MathExtError('latex exited with error', stderr, stdout)
return path.join(tempdir, 'math.dvi')
def convert_dvi_to_image(command, name):
# type: (List[unicode], unicode) -> Tuple[unicode, unicode]
"""Convert DVI file to specific image format."""
try:
p = Popen(command, stdout=PIPE, stderr=PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning('%s command %r cannot be run (needed for math '
'display), check the imgmath_%s setting',
name, command[0], name)
raise InvokeError
stdout, stderr = p.communicate()
if p.returncode != 0:
raise MathExtError('%s exited with error' % name, stderr, stdout)
return stdout, stderr
def convert_dvi_to_png(dvipath, builder):
# type: (unicode, Builder) -> Tuple[unicode, int]
"""Convert DVI file to PNG image."""
tempdir = ensure_tempdir(builder)
filename = path.join(tempdir, 'math.png')
name = 'dvipng'
command = [builder.config.imgmath_dvipng, '-o', filename, '-T', 'tight', '-z9']
command.extend(builder.config.imgmath_dvipng_args)
if builder.config.imgmath_use_preview:
command.append('--depth')
command.append(dvipath)
stdout, stderr = convert_dvi_to_image(command, name)
depth = None
if builder.config.imgmath_use_preview:
for line in stdout.splitlines():
matched = depth_re.match(line) # type: ignore
if matched:
depth = int(matched.group(1))
write_png_depth(filename, depth)
break
return filename, depth
def convert_dvi_to_svg(dvipath, builder):
# type: (unicode, Builder) -> Tuple[unicode, int]
"""Convert DVI file to SVG image."""
tempdir = ensure_tempdir(builder)
filename = path.join(tempdir, 'math.svg')
name = 'dvisvgm'
command = [builder.config.imgmath_dvisvgm, '-o', filename]
command.extend(builder.config.imgmath_dvisvgm_args)
command.append(dvipath)
convert_dvi_to_image(command, name)
return filename, None
def render_math(self, math):
# type: (nodes.NodeVisitor, unicode) -> Tuple[unicode, int]
"""Render the LaTeX math expression *math* using latex and dvipng or
@ -97,20 +230,15 @@ def render_math(self, math):
docs successfully). If the programs are there, however, they may not fail
since that indicates a problem in the math source.
"""
image_format = self.builder.config.imgmath_image_format
if image_format not in ('png', 'svg'):
raise MathExtError(
'imgmath_image_format must be either "png" or "svg"')
image_format = self.builder.config.imgmath_image_format.lower()
if image_format not in SUPPORT_FORMAT:
raise MathExtError('imgmath_image_format must be either "png" or "svg"')
font_size = self.builder.config.imgmath_font_size
use_preview = self.builder.config.imgmath_use_preview
latex = DOC_HEAD + self.builder.config.imgmath_latex_preamble
latex += (use_preview and DOC_BODY_PREVIEW or DOC_BODY) % (
font_size, int(round(font_size * 1.2)), math)
latex = generate_latex_macro(math, self.builder.config)
shasum = "%s.%s" % (sha1(latex.encode('utf-8')).hexdigest(), image_format)
relfn = posixpath.join(self.builder.imgpath, 'math', shasum)
outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', shasum)
filename = "%s.%s" % (sha1(latex.encode('utf-8')).hexdigest(), image_format)
relfn = posixpath.join(self.builder.imgpath, 'math', filename)
outfn = path.join(self.builder.outdir, self.builder.imagedir, 'math', filename)
if path.isfile(outfn):
depth = read_png_depth(outfn)
return relfn, depth
@ -120,91 +248,26 @@ def render_math(self, math):
hasattr(self.builder, '_imgmath_warned_image_translator'):
return None, None
# use only one tempdir per build -- the use of a directory is cleaner
# than using temporary files, since we can clean up everything at once
# just removing the whole directory (see cleanup_tempdir)
if not hasattr(self.builder, '_imgmath_tempdir'):
tempdir = self.builder._imgmath_tempdir = tempfile.mkdtemp()
else:
tempdir = self.builder._imgmath_tempdir
with codecs.open(path.join(tempdir, 'math.tex'), 'w', 'utf-8') as tf:
tf.write(latex)
# build latex command; old versions of latex don't have the
# --output-directory option, so we have to manually chdir to the
# temp dir to run it.
ltx_args = [self.builder.config.imgmath_latex, '--interaction=nonstopmode']
# add custom args from the config file
ltx_args.extend(self.builder.config.imgmath_latex_args)
ltx_args.append('math.tex')
with cd(tempdir):
try:
p = Popen(ltx_args, stdout=PIPE, stderr=PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning('LaTeX command %r cannot be run (needed for math '
'display), check the imgmath_latex setting',
self.builder.config.imgmath_latex)
self.builder._imgmath_warned_latex = True
return None, None
stdout, stderr = p.communicate()
if p.returncode != 0:
raise MathExtError('latex exited with error', stderr, stdout)
ensuredir(path.dirname(outfn))
if image_format == 'png':
image_translator = 'dvipng'
image_translator_executable = self.builder.config.imgmath_dvipng
# use some standard dvipng arguments
image_translator_args = [self.builder.config.imgmath_dvipng]
image_translator_args += ['-o', outfn, '-T', 'tight', '-z9']
# add custom ones from config value
image_translator_args.extend(self.builder.config.imgmath_dvipng_args)
if use_preview:
image_translator_args.append('--depth')
elif image_format == 'svg':
image_translator = 'dvisvgm'
image_translator_executable = self.builder.config.imgmath_dvisvgm
# use some standard dvisvgm arguments
image_translator_args = [self.builder.config.imgmath_dvisvgm]
image_translator_args += ['-o', outfn]
# add custom ones from config value
image_translator_args.extend(self.builder.config.imgmath_dvisvgm_args)
else:
raise MathExtError(
'imgmath_image_format must be either "png" or "svg"')
# last, the input file name
image_translator_args.append(path.join(tempdir, 'math.dvi'))
# .tex -> .dvi
try:
p = Popen(image_translator_args, stdout=PIPE, stderr=PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
logger.warning('%s command %r cannot be run (needed for math '
'display), check the imgmath_%s setting',
image_translator, image_translator_executable,
image_translator)
dvipath = compile_math(latex, self.builder)
except InvokeError:
self.builder._imgmath_warned_latex = True
return None, None
# .dvi -> .png/.svg
try:
if image_format == 'png':
imgpath, depth = convert_dvi_to_png(dvipath, self.builder)
elif image_format == 'svg':
imgpath, depth = convert_dvi_to_svg(dvipath, self.builder)
except InvokeError:
self.builder._imgmath_warned_image_translator = True
return None, None
stdout, stderr = p.communicate()
if p.returncode != 0:
raise MathExtError('%s exited with error' %
image_translator, stderr, stdout)
depth = None
if use_preview and image_format == 'png': # depth is only useful for png
for line in stdout.splitlines():
m = depth_re.match(line)
if m:
depth = int(m.group(1))
write_png_depth(outfn, depth)
break
# Move generated image on tempdir to build dir
ensuredir(path.dirname(outfn))
shutil.move(imgpath, outfn)
return relfn, depth

View File

@ -109,7 +109,7 @@
{%- if css|attr("rel") %}
<link rel="{{ css.rel }}" href="{{ pathto(css.filename, 1) }}" type="text/css"{% if css.title is not none %} title="{{ css.title }}"{% endif %} />
{%- else %}
<link href="{{ pathto(css, 1) }}" type="text/css" />
<link rel="stylesheet" href="{{ pathto(css, 1) }}" type="text/css" />
{%- endif %}
{%- endfor %}
{%- endmacro %}
@ -125,16 +125,16 @@
{%- else %}
<meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
{%- endif %}
{{ metatags }}
{{- metatags }}
{%- block htmltitle %}
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
{%- endblock %}
{%- block csss %}
{{ css() }}
{{- css() }}
{%- endblock %}
{%- if not embedded %}
{%- block scripts %}
{{ script() }}
{{- script() }}
{%- endblock %}
{%- if use_opensearch %}
<link rel="search" type="application/opensearchdescription+xml"

View File

@ -51,6 +51,7 @@ VERBOSITY_MAP.update({
COLOR_MAP = defaultdict(lambda: 'blue') # type: Dict[int, unicode]
COLOR_MAP.update({
logging.ERROR: 'darkred',
logging.WARNING: 'darkred',
logging.DEBUG: 'darkgray',
})

View File

@ -232,7 +232,7 @@ def test_colored_logs(app, status, warning):
assert 'message3\n' in status.getvalue() # not colored
assert colorize('darkred', 'WARNING: message4') in warning.getvalue()
assert 'WARNING: message5\n' in warning.getvalue() # not colored
assert 'WARNING: message6\n' in warning.getvalue() # not colored
assert colorize('darkred', 'WARNING: message6') in warning.getvalue()
# color specification
logger.debug('message7', color='white')