summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--doc/_themes/sphinx13/layout.html2
-rw-r--r--doc/builders.rst71
-rw-r--r--doc/conf.py2
-rw-r--r--doc/extdev/index.rst1
-rw-r--r--doc/extdev/utils.rst19
-rw-r--r--doc/intl.rst8
-rw-r--r--doc/latex.rst69
-rw-r--r--doc/man/sphinx-apidoc.rst6
-rw-r--r--doc/usage/restructuredtext/directives.rst6
-rw-r--r--sphinx/application.py4
-rw-r--r--sphinx/builders/__init__.py4
-rw-r--r--sphinx/builders/gettext.py5
-rw-r--r--sphinx/directives/__init__.py12
-rw-r--r--sphinx/directives/code.py21
-rw-r--r--sphinx/directives/other.py56
-rw-r--r--sphinx/directives/patches.py6
-rw-r--r--sphinx/environment/__init__.py4
-rw-r--r--sphinx/ext/autosummary/__init__.py2
-rw-r--r--sphinx/ext/doctest.py4
-rw-r--r--sphinx/ext/imgconverter.py25
-rw-r--r--sphinx/testing/util.py3
-rw-r--r--sphinx/transforms/__init__.py15
-rw-r--r--sphinx/util/docutils.py23
-rw-r--r--sphinx/util/i18n.py6
-rw-r--r--sphinx/util/osutil.py9
26 files changed, 225 insertions, 161 deletions
diff --git a/CHANGES b/CHANGES
index 02a817b22..184365670 100644
--- a/CHANGES
+++ b/CHANGES
@@ -93,6 +93,9 @@ Bugs fixed
* #4769: autodoc loses the first staticmethod parameter
* #4790: autosummary: too wide two column tables in PDF builds
* #4795: Latex customization via ``_templates/longtable.tex_t`` is broken
+* #4789: imgconverter: confused by convert.exe of Windows
+* #4783: On windows, Sphinx crashed when drives of srcdir and outdir are
+ different
Testing
--------
diff --git a/doc/_themes/sphinx13/layout.html b/doc/_themes/sphinx13/layout.html
index 597b6261f..8967d8265 100644
--- a/doc/_themes/sphinx13/layout.html
+++ b/doc/_themes/sphinx13/layout.html
@@ -70,7 +70,7 @@
<div class="pageheader">
<ul>
<li><a href="{{ pathto('index') }}">Home</a></li>
- <li><a href="{{ pathto('install') }}">Get it</a></li>
+ <li><a href="{{ pathto('usage/installation') }}">Get it</a></li>
<li><a href="{{ pathto('contents') }}">Docs</a></li>
<li><a href="{{ pathto('develop') }}">Extend/Develop</a></li>
</ul>
diff --git a/doc/builders.rst b/doc/builders.rst
index ffaa1e14f..6ab6227fa 100644
--- a/doc/builders.rst
+++ b/doc/builders.rst
@@ -155,36 +155,30 @@ The builder's "name" must be given to the **-b** command-line option of
configuration values that customize the output of this builder, see the
chapter :ref:`latex-options` for details.
+ The produced LaTeX file uses several LaTeX packages that may not be present
+ in a "minimal" TeX distribution installation. For example, on Ubuntu, the
+ following packages need to be installed for successful PDF builds:
+
+ * texlive-latex-recommended
+ * texlive-fonts-recommended
+ * texlive-latex-extra
+ * latexmk (for ``make latexpdf`` on GNU/Linux and MacOS X)
+ * latex-xcolor (old Ubuntu)
+ * texlive-luatex, texlive-xetex (see :confval:`latex_engine`)
+
+ The testing of Sphinx LaTeX is done on Ubuntu trusty with the above
+ mentioned packages, which are from a TeXLive 2013 snapshot dated
+ February 2014.
+
+ .. versionchanged:: 1.6
+ Formerly, testing had been done on Ubuntu precise (TeXLive 2009).
+
.. note::
- The produced LaTeX file uses several LaTeX packages that may not be
- present in a "minimal" TeX distribution installation. For example, on
- Ubuntu, the following packages need to be installed for successful PDF
- builds:
-
- * texlive-latex-recommended
- * texlive-fonts-recommended
- * texlive-latex-extra
- * latexmk (for ``make latexpdf``)
-
- Sphinx will use ``xcolor.sty`` if present: recent Ubuntu distributions
- have ``xcolor.sty`` included in latex-recommended, earlier ones have it
- in latex-xcolor. Unicode engines will need texlive-luatex or
- texlive-xetex.
-
- The testing of Sphinx LaTeX is done on Ubuntu trusty with the above
- mentioned packages, which are from a TeXLive 2013 snapshot dated
- February 2014.
-
- .. versionchanged:: 1.6
- Formerly, testing had been done for some years on Ubuntu precise
- (based on TeXLive 2009).
- .. versionchanged:: 1.6
- Use of ``latexmk`` for ``make latexpdf`` on GNU/Linux and Mac OS X
-
- Since 1.6, ``make latexpdf`` (or
- ``make -C "<builddir>/latex"`` after a ``sphinx-build`` run) uses
- ``latexmk`` (not on Windows).
+ Since 1.6, ``make latexpdf`` uses ``latexmk`` (not on Windows). This
+ makes sure the needed number of runs is automatically executed to get
+ the cross-references, bookmarks, indices, and tables of contents right.
+
One can pass to ``latexmk`` options via the ``LATEXMKOPTS``
Makefile variable. For example:
@@ -192,13 +186,22 @@ The builder's "name" must be given to the **-b** command-line option of
make latexpdf LATEXMKOPTS="-silent"
- reduces console output to a minimum. Also, if ``latexmk`` version is
- 4.52b or higher (Jan 17) and ``xelatex`` is the :confval:`latex_engine`,
- then ``LATEXMKOPTS="-xelatex"`` will speed up PDF builds.
+ reduces console output to a minimum.
+
+ Also, if ``latexmk`` version is 4.52b or higher (Jan 17)
+ ``LATEXMKOPTS="-xelatex"`` will speed up PDF builds via XeLateX in case
+ of numerous graphics inclusions.
+
+ .. code-block:: console
+
+ make latexpdf LATEXMKOPTS="-xelatex"
+
+ To pass options directly to the ``(pdf|xe|lua)latex`` executable, use
+ variable ``LATEXOPTS``.
+
+ .. code-block:: console
- To pass options directly to the
- ``(pdf|xe|lua)latex`` executable, use variable ``LATEXOPTS`` (for example
- ``LATEXOPTS="--interaction=nonstopmode"``).
+ make latexpdf LATEXOPTS="--interaction=nonstopmode"
.. autoattribute:: name
diff --git a/doc/conf.py b/doc/conf.py
index 49f0930b6..18d82b223 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -39,7 +39,7 @@ epub_uid = 'web-site'
epub_scheme = 'url'
epub_identifier = epub_publisher
epub_pre_files = [('index.xhtml', 'Welcome')]
-epub_post_files = [('install.xhtml', 'Installing Sphinx'),
+epub_post_files = [('usage/installation.xhtml', 'Installing Sphinx'),
('develop.xhtml', 'Sphinx development')]
epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js',
'_static/jquery.js', '_static/searchtools.js',
diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst
index 78414cd09..2dba7a430 100644
--- a/doc/extdev/index.rst
+++ b/doc/extdev/index.rst
@@ -94,6 +94,7 @@ APIs used for writing extensions
nodes
logging
i18n
+ utils
Deprecated APIs
---------------
diff --git a/doc/extdev/utils.rst b/doc/extdev/utils.rst
new file mode 100644
index 000000000..6ec3f1b46
--- /dev/null
+++ b/doc/extdev/utils.rst
@@ -0,0 +1,19 @@
+Utilities
+=========
+
+Sphinx provides utility classes and functions to develop extensions.
+
+Base classes for components
+---------------------------
+
+These base classes are useful to allow your extensions to obtain Sphinx
+components (e.g. :class:`.Config`, :class:`.BuildEnvironment` and so on) easily.
+
+.. note:: The subclasses of them might not work with bare docutils because they
+ are strongly coupled with Sphinx.
+
+.. autoclass:: sphinx.transforms.SphinxTransform
+ :members:
+
+.. autoclass:: sphinx.util.docutils.SphinxDirective
+ :members:
diff --git a/doc/intl.rst b/doc/intl.rst
index ac4f47079..75263e6e4 100644
--- a/doc/intl.rst
+++ b/doc/intl.rst
@@ -207,7 +207,7 @@ easy to fetch and push translations.
$ pip install transifex-client
- .. seealso:: `Transifex Client v0.8 &mdash; Transifex documentation`_
+ .. seealso:: `Transifex Client documentation`_
#. Create your transifex_ account and create new project for your document
@@ -305,7 +305,7 @@ Contributing to Sphinx reference translation
The recommended way for new contributors to translate Sphinx reference
is to join the translation team on Transifex.
-There is `sphinx translation page`_ for Sphinx-1.3 documentation.
+There is `sphinx translation page`_ for Sphinx (master) documentation.
1. Login to transifex_ service.
2. Go to `sphinx translation page`_.
@@ -325,5 +325,5 @@ There is `sphinx translation page`_ for Sphinx-1.3 documentation.
.. _`transifex-client`: https://pypi.python.org/pypi/transifex-client
.. _`sphinx-intl`: https://pypi.python.org/pypi/sphinx-intl
.. _Transifex: https://www.transifex.com/
-.. _`sphinx translation page`: https://www.transifex.com/sphinx-doc/sphinx-doc-1_3/
-.. _`Transifex Client v0.8 &mdash; Transifex documentation`: https://docs.transifex.com/client/introduction/
+.. _`sphinx translation page`: https://www.transifex.com/sphinx-doc/sphinx-doc/
+.. _`Transifex Client documentation`: http://docs.transifex.com/developer/client/
diff --git a/doc/latex.rst b/doc/latex.rst
index f8e275020..b50f49377 100644
--- a/doc/latex.rst
+++ b/doc/latex.rst
@@ -8,8 +8,8 @@ LaTeX customization
.. module:: latex
:synopsis: LaTeX specifics.
-The *latex* target does not benefit from pre-prepared themes like the
-*html* target does (see :doc:`theming`).
+For details of the LaTeX/PDF builder command line invocation, refer to
+:py:class:`~sphinx.builders.latex.LaTeXBuilder`.
.. raw:: latex
@@ -34,8 +34,10 @@ The *latex* target does not benefit from pre-prepared themes like the
Basic customization
-------------------
-It is achieved via usage of the
-:ref:`latex-options` as described in :doc:`config`. For example::
+The *latex* target does not benefit from prepared themes.
+
+Basic customization is obtained via usage of the :ref:`latex-options`. For
+example::
# inside conf.py
latex_engine = 'xelatex'
@@ -69,7 +71,7 @@ repertory, and get LaTeX to import it at run time::
# or, if the \ProvidesPackage LaTeX macro is used in a file mystyle.sty
'preamble': r'\usepackage{mystyle}',
-It is needed to set appropriately :confval:`latex_additional_files`, for
+It is then needed to set appropriately :confval:`latex_additional_files`, for
example::
latex_additional_files = ["mystyle.sty"]
@@ -79,11 +81,14 @@ example::
The LaTeX style file options
----------------------------
+Additional customization is possible via LaTeX options of the Sphinx style
+file.
+
The sphinxsetup interface
~~~~~~~~~~~~~~~~~~~~~~~~~
The ``'sphinxsetup'`` key of :confval:`latex_elements` provides a convenient
-interface to the package options of the Sphinx style file::
+interface::
latex_elements = {
'sphinxsetup': 'key1=value1, key2=value2, ...',
@@ -103,40 +108,39 @@ inside the document preamble, like this::
.. versionadded:: 1.5
-It is possible to insert further uses of the ``\sphinxsetup`` LaTeX macro
-directly into the body of the document, via the help of the :rst:dir:`raw`
-directive. This is what is done for this documentation, for local styling
-of this chapter in the PDF output::
+.. hint::
- .. raw:: latex
+ It is possible to insert further uses of the ``\sphinxsetup`` LaTeX macro
+ directly into the body of the document, via the help of the :rst:dir:`raw`
+ directive. Here is how this present chapter in PDF is styled::
- \begingroup
- \sphinxsetup{%
- verbatimwithframe=false,
- VerbatimColor={named}{OldLace},
- TitleColor={named}{DarkGoldenrod},
- hintBorderColor={named}{LightCoral},
- attentionborder=3pt,
- attentionBorderColor={named}{Crimson},
- attentionBgColor={named}{FloralWhite},
- noteborder=2pt,
- noteBorderColor={named}{Olive},
- cautionborder=3pt,
- cautionBorderColor={named}{Cyan},
- cautionBgColor={named}{LightCyan}}
+ .. raw:: latex
-at the start of the chapter and::
+ \begingroup
+ \sphinxsetup{%
+ verbatimwithframe=false,
+ VerbatimColor={named}{OldLace},
+ TitleColor={named}{DarkGoldenrod},
+ hintBorderColor={named}{LightCoral},
+ attentionborder=3pt,
+ attentionBorderColor={named}{Crimson},
+ attentionBgColor={named}{FloralWhite},
+ noteborder=2pt,
+ noteBorderColor={named}{Olive},
+ cautionborder=3pt,
+ cautionBorderColor={named}{Cyan},
+ cautionBgColor={named}{LightCyan}}
- .. raw:: latex
+ at the start of the chapter and::
- \endgroup
+ .. raw:: latex
-at its end.
+ \endgroup
-.. note::
+ at its end.
- The colors above are made available via the ``svgnames`` option of
- the "xcolor" package::
+ The colors used in the above are provided by the ``svgnames`` option of the
+ "xcolor" package::
latex_elements = {
'passoptionstopackages': r'\PassOptionsToPackage{svgnames}{xcolor}',
@@ -465,7 +469,6 @@ Miscellany
.. versionchanged:: 1.5
formerly, use of *fncychap* with other styles than ``Bjarne`` was
dysfunctional.
-- check file :file:`sphinx.sty` for more...
.. hint::
diff --git a/doc/man/sphinx-apidoc.rst b/doc/man/sphinx-apidoc.rst
index 8f75d6f7c..97135d98e 100644
--- a/doc/man/sphinx-apidoc.rst
+++ b/doc/man/sphinx-apidoc.rst
@@ -15,8 +15,10 @@ style of other automatic API documentation tools.
*MODULE_PATH* is the path to a Python package to document, and *OUTPUT_PATH* is
the directory where the generated sources are placed. Any *EXCLUDE_PATTERN*\s
-given are `fnmatch-style <fnmatch>`_ file and/or directory patterns that will
-be excluded from generation.
+given are `fnmatch-style`_ file and/or directory patterns that will be excluded
+from generation.
+
+.. _fnmatch-style: https://docs.python.org/3/library/fnmatch.html
.. warning::
diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst
index 1a41dbef1..a99ccdbf5 100644
--- a/doc/usage/restructuredtext/directives.rst
+++ b/doc/usage/restructuredtext/directives.rst
@@ -596,7 +596,8 @@ __ http://pygments.org/docs/lexers/
``start-after`` is given as a string option, only lines that follow the
first line containing that string are included. If ``end-before`` is given
as a string option, only lines that precede the first lines containing that
- string are included.
+ string are included. The ``start-at`` and ``end-at`` options behave in a
+ similar way, but the lines containing the matched string are included.
With lines selected using ``start-after`` it is still possible to use
``lines``, the first allowed line having by convention the line number
@@ -638,6 +639,9 @@ __ http://pygments.org/docs/lexers/
Added the ``diff``, ``lineno-match``, ``caption``, ``name``, and
``dedent`` options.
+ .. versionchanged:: 1.5
+ Added the ``start-at``, and ``end-at`` options.
+
.. versionchanged:: 1.6
With both ``start-after`` and ``lines`` in use, the first line as per
``start-after`` is considered to be with line number ``1`` for ``lines``.
diff --git a/sphinx/application.py b/sphinx/application.py
index d6d66c925..c8e06245c 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -43,7 +43,7 @@ from sphinx.util.build_phase import BuildPhase
from sphinx.util.console import bold # type: ignore
from sphinx.util.docutils import directive_helper
from sphinx.util.i18n import find_catalog_source_files
-from sphinx.util.osutil import abspath, ensuredir
+from sphinx.util.osutil import abspath, ensuredir, relpath
from sphinx.util.tags import Tags
if False:
@@ -351,7 +351,7 @@ class Sphinx(object):
if self.statuscode == 0 and self.builder.epilog:
logger.info('')
logger.info(self.builder.epilog % {
- 'outdir': path.relpath(self.outdir),
+ 'outdir': relpath(self.outdir),
'project': self.config.project
})
except Exception as err:
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index d5b60a0a9..fb171dcde 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -23,7 +23,7 @@ from sphinx.util import i18n, import_object, logging, status_iterator
from sphinx.util.build_phase import BuildPhase
from sphinx.util.console import bold # type: ignore
from sphinx.util.i18n import find_catalog
-from sphinx.util.osutil import SEP, ensuredir, relative_uri
+from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
parallel_available
@@ -242,7 +242,7 @@ class Builder(object):
def cat2relpath(cat):
# type: (CatalogInfo) -> unicode
- return path.relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
+ return relpath(cat.mo_path, self.env.srcdir).replace(path.sep, SEP)
logger.info(bold(__('building [mo]: ')) + message)
for catalog in status_iterator(catalogs, __('writing output... '), "darkgreen",
diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py
index c8fbb9c32..b43dcfb3b 100644
--- a/sphinx/builders/gettext.py
+++ b/sphinx/builders/gettext.py
@@ -27,7 +27,7 @@ from sphinx.util import split_index_msg, logging, status_iterator
from sphinx.util.console import bold # type: ignore
from sphinx.util.i18n import find_catalog
from sphinx.util.nodes import extract_messages, traverse_translatable_index
-from sphinx.util.osutil import safe_relpath, ensuredir, canon_path
+from sphinx.util.osutil import relpath, ensuredir, canon_path
from sphinx.util.tags import Tags
if False:
@@ -286,8 +286,7 @@ class MessageCatalogBuilder(I18nBuilder):
if self.config.gettext_location:
# generate "#: file1:line1\n#: file2:line2 ..."
output.write("#: %s\n" % "\n#: ".join( # type: ignore
- "%s:%s" % (canon_path(
- safe_relpath(source, self.outdir)), line)
+ "%s:%s" % (canon_path(relpath(source, self.outdir)), line)
for source, line, _ in positions))
if self.config.gettext_uuid:
# generate "# uuid1\n# uuid2\n ..."
diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py
index dc51810d3..81978b722 100644
--- a/sphinx/directives/__init__.py
+++ b/sphinx/directives/__init__.py
@@ -16,6 +16,7 @@ from docutils.parsers.rst import Directive, directives, roles
from sphinx import addnodes
from sphinx.util.docfields import DocFieldTransformer
+from sphinx.util.docutils import SphinxDirective
# import all directives sphinx provides
from sphinx.directives.code import ( # noqa
@@ -33,6 +34,7 @@ if False:
# For type annotation
from typing import Any, Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
+ from sphinx.config import Config # NOQA
from sphinx.environment import BuildEnvironment # NOQA
@@ -41,7 +43,7 @@ nl_escape_re = re.compile(r'\\\n')
strip_backslash_re = re.compile(r'\\(.)')
-class ObjectDescription(Directive):
+class ObjectDescription(SphinxDirective):
"""
Directive to describe a class, function or similar object. Not used
directly, but subclassed (in domain-specific directives) to add custom
@@ -135,7 +137,6 @@ class ObjectDescription(Directive):
self.domain, self.objtype = self.name.split(':', 1)
else:
self.domain, self.objtype = '', self.name
- self.env = self.state.document.settings.env # type: BuildEnvironment
self.indexnode = addnodes.index(entries=[])
node = addnodes.desc()
@@ -187,7 +188,7 @@ class ObjectDescription(Directive):
DescDirective = ObjectDescription
-class DefaultRole(Directive):
+class DefaultRole(SphinxDirective):
"""
Set the default interpreted text role. Overridden from docutils.
"""
@@ -212,7 +213,7 @@ class DefaultRole(Directive):
line=self.lineno)
return messages + [error]
roles._roles[''] = role
- self.state.document.settings.env.temp_data['default_role'] = role_name
+ self.env.temp_data['default_role'] = role_name
return messages
@@ -229,7 +230,6 @@ class DefaultDomain(Directive):
def run(self):
# type: () -> List[nodes.Node]
- env = self.state.document.settings.env
domain_name = self.arguments[0].lower()
# if domain_name not in env.domains:
# # try searching by label
@@ -237,7 +237,7 @@ class DefaultDomain(Directive):
# if domain.label.lower() == domain_name:
# domain_name = domain.name
# break
- env.temp_data['default_domain'] = env.domains.get(domain_name)
+ self.env.temp_data['default_domain'] = self.env.domains.get(domain_name)
return []
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index 8690fca0f..1c294ec7b 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -12,7 +12,7 @@ import sys
from difflib import unified_diff
from docutils import nodes
-from docutils.parsers.rst import Directive, directives
+from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from six import text_type
@@ -20,6 +20,7 @@ from sphinx import addnodes
from sphinx.locale import __
from sphinx.util import logging
from sphinx.util import parselinenos
+from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info
if False:
@@ -31,7 +32,7 @@ if False:
logger = logging.getLogger(__name__)
-class Highlight(Directive):
+class Highlight(SphinxDirective):
"""
Directive to set the highlighting language for code blocks, as well
as the threshold for line numbers.
@@ -77,7 +78,7 @@ def dedent_lines(lines, dedent, location=None):
def container_wrapper(directive, literal_node, caption):
- # type: (Directive, nodes.Node, unicode) -> nodes.container
+ # type: (SphinxDirective, nodes.Node, unicode) -> nodes.container
container_node = nodes.container('', literal_block=True,
classes=['literal-block-wrapper'])
parsed = nodes.Element()
@@ -95,7 +96,7 @@ def container_wrapper(directive, literal_node, caption):
return container_node
-class CodeBlock(Directive):
+class CodeBlock(SphinxDirective):
"""
Directive for a code block with special highlighting or line numbering
settings.
@@ -372,7 +373,7 @@ class LiteralIncludeReader(object):
return lines
-class LiteralInclude(Directive):
+class LiteralInclude(SphinxDirective):
"""
Like ``.. include:: :literal:``, but only warns if the include file is
not found, and does not raise errors. Also has several options for
@@ -412,19 +413,17 @@ class LiteralInclude(Directive):
if not document.settings.file_insertion_enabled:
return [document.reporter.warning('File insertion disabled',
line=self.lineno)]
- env = document.settings.env
-
# convert options['diff'] to absolute path
if 'diff' in self.options:
- _, path = env.relfn2path(self.options['diff'])
+ _, path = self.env.relfn2path(self.options['diff'])
self.options['diff'] = path
try:
location = self.state_machine.get_source_and_line(self.lineno)
- rel_filename, filename = env.relfn2path(self.arguments[0])
- env.note_dependency(rel_filename)
+ rel_filename, filename = self.env.relfn2path(self.arguments[0])
+ self.env.note_dependency(rel_filename)
- reader = LiteralIncludeReader(filename, self.options, env.config)
+ reader = LiteralIncludeReader(filename, self.options, self.config)
text, lines = reader.read(location=location)
retnode = nodes.literal_block(text, text, source=filename)
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index 252e6522a..450999435 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -8,7 +8,7 @@
"""
from docutils import nodes
-from docutils.parsers.rst import Directive, directives
+from docutils.parsers.rst import directives
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
from docutils.parsers.rst.directives.misc import Class
from docutils.parsers.rst.directives.misc import Include as BaseInclude
@@ -18,6 +18,7 @@ from sphinx import addnodes, locale
from sphinx.deprecation import DeprecatedDict, RemovedInSphinx30Warning
from sphinx.locale import _
from sphinx.util import url_re, docname_join
+from sphinx.util.docutils import SphinxDirective
from sphinx.util.matching import patfilter
from sphinx.util.nodes import explicit_title_re, set_source_info, \
process_index_entry
@@ -49,7 +50,7 @@ def int_or_nothing(argument):
return int(argument)
-class TocTree(Directive):
+class TocTree(SphinxDirective):
"""
Directive to notify Sphinx about the hierarchical structure of the docs,
and to include a table-of-contents like tree in the current document.
@@ -72,8 +73,7 @@ class TocTree(Directive):
def run(self):
# type: () -> List[nodes.Node]
- env = self.state.document.settings.env
- suffixes = env.config.source_suffix
+ suffixes = self.config.source_suffix
glob = 'glob' in self.options
ret = []
@@ -81,17 +81,17 @@ class TocTree(Directive):
# and title may be None if the document's title is to be used
entries = [] # type: List[Tuple[unicode, unicode]]
includefiles = []
- all_docnames = env.found_docs.copy()
+ all_docnames = self.env.found_docs.copy()
# don't add the currently visited file in catch-all patterns
- all_docnames.remove(env.docname)
+ all_docnames.remove(self.env.docname)
for entry in self.content:
if not entry:
continue
# look for explicit titles ("Some Title <document>")
explicit = explicit_title_re.match(entry)
if glob and ('*' in entry or '?' in entry or '[' in entry) and not explicit:
- patname = docname_join(env.docname, entry)
- docnames = sorted(patfilter(all_docnames, patname))
+ patname = docname_join(self.env.docname, entry)
+ docnames = sorted(patfilter(all_docnames, patname)) # type: ignore
for docname in docnames:
all_docnames.remove(docname) # don't include it again
entries.append((None, docname))
@@ -114,20 +114,20 @@ class TocTree(Directive):
docname = docname[:-len(suffix)]
break
# absolutize filenames
- docname = docname_join(env.docname, docname)
+ docname = docname_join(self.env.docname, docname)
if url_re.match(ref) or ref == 'self':
entries.append((title, ref))
- elif docname not in env.found_docs:
+ elif docname not in self.env.found_docs:
ret.append(self.state.document.reporter.warning(
'toctree contains reference to nonexisting '
'document %r' % docname, line=self.lineno))
- env.note_reread()
+ self.env.note_reread()
else:
all_docnames.discard(docname)
entries.append((title, docname))
includefiles.append(docname)
subnode = addnodes.toctree()
- subnode['parent'] = env.docname
+ subnode['parent'] = self.env.docname
# entries contains all entries (self references, external links etc.)
if 'reversed' in self.options:
entries.reverse()
@@ -149,7 +149,7 @@ class TocTree(Directive):
return ret
-class Author(Directive):
+class Author(SphinxDirective):
"""
Directive to give the name of the author of the current document
or section. Shown in the output only if the show_authors option is on.
@@ -162,8 +162,7 @@ class Author(Directive):
def run(self):
# type: () -> List[nodes.Node]
- env = self.state.document.settings.env
- if not env.config.show_authors:
+ if not self.config.show_authors:
return []
para = nodes.paragraph(translatable=False)
emph = nodes.emphasis()
@@ -183,7 +182,7 @@ class Author(Directive):
return [para] + messages
-class Index(Directive):
+class Index(SphinxDirective):
"""
Directive to add entries to the index.
"""
@@ -196,8 +195,7 @@ class Index(Directive):
def run(self):
# type: () -> List[nodes.Node]
arguments = self.arguments[0].split('\n')
- env = self.state.document.settings.env
- targetid = 'index-%s' % env.new_serialno('index')
+ targetid = 'index-%s' % self.env.new_serialno('index')
targetnode = nodes.target('', '', ids=[targetid])
self.state.document.note_explicit_target(targetnode)
indexnode = addnodes.index()
@@ -209,7 +207,7 @@ class Index(Directive):
return [indexnode, targetnode]
-class VersionChange(Directive):
+class VersionChange(SphinxDirective):
"""
Directive to describe a change/addition/deprecation in a specific version.
"""
@@ -252,9 +250,8 @@ class VersionChange(Directive):
classes=['versionmodified']),
translatable=False)
node.append(para)
- env = self.state.document.settings.env
# XXX should record node.source as well
- env.note_versionchange(node['type'], node['version'], node, node.line)
+ self.env.note_versionchange(node['type'], node['version'], node, node.line)
return [node] + messages
@@ -265,7 +262,7 @@ class SeeAlso(BaseAdmonition):
node_class = addnodes.seealso
-class TabularColumns(Directive):
+class TabularColumns(SphinxDirective):
"""
Directive to give an explicit tabulary column definition to LaTeX.
"""
@@ -283,7 +280,7 @@ class TabularColumns(Directive):
return [node]
-class Centered(Directive):
+class Centered(SphinxDirective):
"""
Directive to create a centered line of bold text.
"""
@@ -304,7 +301,7 @@ class Centered(Directive):
return [subnode] + messages
-class Acks(Directive):
+class Acks(SphinxDirective):
"""
Directive for a list of names.
"""
@@ -326,7 +323,7 @@ class Acks(Directive):
return [node]
-class HList(Directive):
+class HList(SphinxDirective):
"""
Directive for a list that gets compacted horizontally.
"""
@@ -363,7 +360,7 @@ class HList(Directive):
return [newnode]
-class Only(Directive):
+class Only(SphinxDirective):
"""
Directive to only include text if the given tag(s) are enabled.
"""
@@ -421,7 +418,7 @@ class Only(Directive):
self.state.memo.section_level = surrounding_section_level
-class Include(BaseInclude):
+class Include(BaseInclude, SphinxDirective):
"""
Like the standard "Include" directive, but interprets absolute paths
"correctly", i.e. relative to source directory.
@@ -429,14 +426,13 @@ class Include(BaseInclude):
def run(self):
# type: () -> List[nodes.Node]
- env = self.state.document.settings.env
if self.arguments[0].startswith('<') and \
self.arguments[0].endswith('>'):
# docutils "standard" includes, do not do path processing
return BaseInclude.run(self)
- rel_filename, filename = env.relfn2path(self.arguments[0])
+ rel_filename, filename = self.env.relfn2path(self.arguments[0])
self.arguments[0] = filename
- env.note_included(filename)
+ self.env.note_included(filename)
return BaseInclude.run(self)
diff --git a/sphinx/directives/patches.py b/sphinx/directives/patches.py
index 14f0ca17e..00be5584d 100644
--- a/sphinx/directives/patches.py
+++ b/sphinx/directives/patches.py
@@ -12,6 +12,7 @@ from docutils.parsers.rst import directives
from docutils.parsers.rst.directives import images, html, tables
from sphinx import addnodes
+from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info
if False:
@@ -44,16 +45,15 @@ class Figure(images.Figure):
return [figure_node]
-class Meta(html.Meta):
+class Meta(html.Meta, SphinxDirective):
def run(self):
# type: () -> List[nodes.Node]
- env = self.state.document.settings.env
result = html.Meta.run(self)
for node in result:
if (isinstance(node, nodes.pending) and
isinstance(node.details['nodes'][0], html.MetaBody.meta)):
meta = node.details['nodes'][0]
- meta.source = env.doc2path(env.docname)
+ meta.source = self.env.doc2path(self.env.docname)
meta.line = self.lineno
meta.rawcontent = meta['content']
diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py
index 1a8dd6a85..b69a5fd32 100644
--- a/sphinx/environment/__init__.py
+++ b/sphinx/environment/__init__.py
@@ -38,7 +38,7 @@ from sphinx.util.docutils import sphinx_domains, WarningStream
from sphinx.util.i18n import find_catalog_files
from sphinx.util.matching import compile_matchers
from sphinx.util.nodes import is_translatable
-from sphinx.util.osutil import SEP, ensuredir
+from sphinx.util.osutil import SEP, ensuredir, relpath
from sphinx.util.websupport import is_commentable
if False:
@@ -354,7 +354,7 @@ class BuildEnvironment(object):
*filename* should be absolute or relative to the source directory.
"""
if filename.startswith(self.srcdir):
- filename = os.path.relpath(filename, self.srcdir)
+ filename = relpath(filename, self.srcdir)
for suffix in self.config.source_suffix:
if filename.endswith(suffix):
return filename[:-len(suffix)]
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index be76d8572..80a2b4e63 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -91,7 +91,7 @@ if False:
logger = logging.getLogger(__name__)
-periods_re = re.compile('\.(?:\s+)')
+periods_re = re.compile(r'\.(?:\s+)')
# -- autosummary_toc node ------------------------------------------------------
diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py
index 255a38f6d..b86775d5e 100644
--- a/sphinx/ext/doctest.py
+++ b/sphinx/ext/doctest.py
@@ -30,7 +30,7 @@ from sphinx.locale import __
from sphinx.util import force_decode, logging
from sphinx.util.console import bold # type: ignore
from sphinx.util.nodes import set_source_info
-from sphinx.util.osutil import fs_encoding
+from sphinx.util.osutil import fs_encoding, relpath
if False:
# For type annotation
@@ -372,7 +372,7 @@ Doctest summary
"""Try to get the file which actually contains the doctest, not the
filename of the document it's included in."""
try:
- filename = path.relpath(node.source, self.env.srcdir)\
+ filename = relpath(node.source, self.env.srcdir)\
.rsplit(':docstring of ', maxsplit=1)[0]
except Exception:
filename = self.env.doc2path(docname, base=None)
diff --git a/sphinx/ext/imgconverter.py b/sphinx/ext/imgconverter.py
index 8546593a7..fe086b1fe 100644
--- a/sphinx/ext/imgconverter.py
+++ b/sphinx/ext/imgconverter.py
@@ -8,6 +8,7 @@
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import locale
import subprocess
from sphinx.errors import ExtensionError
@@ -38,17 +39,29 @@ class ImagemagickConverter(ImageConverter):
try:
args = [self.config.image_converter, '-version']
logger.debug('Invoking %r ...', args)
- ret = subprocess.call(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- if ret == 0:
- return True
- else:
- return False
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except (OSError, IOError):
logger.warning(__('convert command %r cannot be run.'
'check the image_converter setting'),
self.config.image_converter)
return False
+ try:
+ stdout, stderr = p.communicate()
+ except (OSError, IOError) as err:
+ if err.errno not in (EPIPE, EINVAL):
+ raise
+ stdout, stderr = p.stdout.read(), p.stderr.read()
+ p.wait()
+ if p.returncode != 0:
+ encoding = locale.getpreferredencoding()
+ logger.warning(__('convert exited with error:\n'
+ '[stderr]\n%s\n[stdout]\n%s'),
+ stderr.decode(encoding), stdout.decode(encoding))
+ return False
+
+ return True
+
def convert(self, _from, _to):
# type: (unicode, unicode) -> bool
"""Converts the image to expected one."""
@@ -61,7 +74,7 @@ class ImagemagickConverter(ImageConverter):
self.config.image_converter_args +
[_from, _to])
logger.debug('Invoking %r ...', args)
- p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError as err:
if err.errno != ENOENT: # No such file or directory
raise
diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py
index e55007d80..24f5267b8 100644
--- a/sphinx/testing/util.py
+++ b/sphinx/testing/util.py
@@ -23,6 +23,7 @@ from sphinx.builders.latex import LaTeXBuilder
from sphinx.ext.autodoc import AutoDirective
from sphinx.pycode import ModuleAnalyzer
from sphinx.testing.path import path
+from sphinx.util.osutil import relpath
if False:
# For type annotation
@@ -201,7 +202,7 @@ def find_files(root, suffix=None):
dirpath = path(dirpath)
for f in [f for f in files if not suffix or f.endswith(suffix)]: # type: ignore
fpath = dirpath / f
- yield os.path.relpath(fpath, root)
+ yield relpath(fpath, root)
def strip_escseq(text):
diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py
index d82b02149..b32b317bb 100644
--- a/sphinx/transforms/__init__.py
+++ b/sphinx/transforms/__init__.py
@@ -44,35 +44,28 @@ default_substitutions = set([
class SphinxTransform(Transform):
- """
- A base class of Transforms.
+ """A base class of Transforms.
Compared with ``docutils.transforms.Transform``, this class improves accessibility to
Sphinx APIs.
-
- The subclasses can access following objects and functions:
-
- self.app
- The application object (:class:`sphinx.application.Sphinx`)
- self.config
- The config object (:class:`sphinx.config.Config`)
- self.env
- The environment object (:class:`sphinx.environment.BuildEnvironment`)
"""
@property
def app(self):
# type: () -> Sphinx
+ """Reference to the :class:`.Sphinx` object."""
return self.document.settings.env.app
@property
def env(self):
# type: () -> BuildEnvironment
+ """Reference to the :class:`.BuildEnvironment` object."""
return self.document.settings.env
@property
def config(self):
# type: () -> Config
+ """Reference to the :class:`.Config` object."""
return self.document.settings.env.config
diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py
index 949bec3b4..747b24565 100644
--- a/sphinx/util/docutils.py
+++ b/sphinx/util/docutils.py
@@ -20,7 +20,7 @@ from distutils.version import LooseVersion
import docutils
from docutils import nodes
from docutils.languages import get_language
-from docutils.parsers.rst import directives, roles, convert_directive_function
+from docutils.parsers.rst import Directive, directives, roles, convert_directive_function
from docutils.statemachine import StateMachine
from docutils.utils import Reporter
@@ -36,6 +36,7 @@ if False:
# For type annotation
from typing import Any, Callable, Generator, Iterator, List, Set, Tuple # NOQA
from docutils.statemachine import State, ViewList # NOQA
+ from sphinx.config import Config # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.io import SphinxFileInput # NOQA
@@ -273,6 +274,26 @@ def switch_source_input(state, content):
state.memo.reporter.get_source_and_line = get_source_and_line
+class SphinxDirective(Directive):
+ """A base class for Directives.
+
+ Compared with ``docutils.parsers.rst.Directive``, this class improves
+ accessibility to Sphinx APIs.
+ """
+
+ @property
+ def env(self):
+ # type: () -> BuildEnvironment
+ """Reference to the :class:`.BuildEnvironment` object."""
+ return self.state.document.settings.env
+
+ @property
+ def config(self):
+ # type: () -> Config
+ """Reference to the :class:`.Config` object."""
+ return self.env.config
+
+
# cache a vanilla instance of nodes.document
# Used in new_document() function
__document_cache__ = None # type: nodes.document
diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py
index 9b6270bdf..d18889756 100644
--- a/sphinx/util/i18n.py
+++ b/sphinx/util/i18n.py
@@ -23,7 +23,7 @@ from babel.messages.pofile import read_po
from sphinx.errors import SphinxError
from sphinx.locale import __
from sphinx.util import logging
-from sphinx.util.osutil import SEP, walk
+from sphinx.util.osutil import SEP, relpath, walk
logger = logging.getLogger(__name__)
@@ -97,7 +97,7 @@ def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
domain = find_catalog(docname, compaction)
files = [gettext.find(domain, path.join(srcdir, dir_), [lang]) # type: ignore
for dir_ in locale_dirs]
- files = [path.relpath(f, srcdir) for f in files if f] # type: ignore
+ files = [relpath(f, srcdir) for f in files if f] # type: ignore
return files # type: ignore
@@ -138,7 +138,7 @@ def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact
filenames = [f for f in filenames if f.endswith('.po')]
for filename in filenames:
base = path.splitext(filename)[0]
- domain = path.relpath(path.join(dirpath, base), base_dir)
+ domain = relpath(path.join(dirpath, base), base_dir)
if gettext_compact and path.sep in domain:
domain = path.split(domain)[0]
domain = domain.replace(path.sep, SEP)
diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py
index 21464bbe6..986171293 100644
--- a/sphinx/util/osutil.py
+++ b/sphinx/util/osutil.py
@@ -210,14 +210,21 @@ def ustrftime(format, *args):
return r.encode().decode('unicode-escape')
-def safe_relpath(path, start=None):
+def relpath(path, start=os.curdir):
# type: (unicode, unicode) -> unicode
+ """Return a relative filepath to *path* either from the current directory or
+ from an optional *start* directory.
+
+ This is an alternative of ``os.path.relpath()``. This returns original path
+ if *path* and *start* are on different drives (for Windows platform).
+ """
try:
return os.path.relpath(path, start)
except ValueError:
return path
+safe_relpath = relpath # for compatibility
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() # type: unicode