Merge branch 'master' into refactor_config

This commit is contained in:
Takeshi KOMIYA 2018-04-22 18:56:04 +09:00
commit 5897d45cc6
89 changed files with 1336 additions and 510 deletions

View File

@ -40,6 +40,7 @@ Other contributors, listed alphabetically, are:
* Timotheus Kampik - JS theme & search enhancements
* Dave Kuhlman -- original LaTeX writer
* Blaise Laflamme -- pyramid theme
* Chris Lamb -- reproducibility fixes
* Thomas Lamb -- linkcheck builder
* Łukasz Langa -- partial support for autodoc
* Ian Lee -- quickstart improvements

36
CHANGES
View File

@ -15,12 +15,19 @@ Incompatible changes
* The default value of :confval:`epub_author` and :confval:`epub_publisher` are
changed from ``'unknown'`` to the value of :confval:`author`. This is same as
a ``conf.py`` file sphinx-build generates.
* The ``gettext_compact`` attribute is removed from ``document.settings``
object. Please use ``config.gettext_compact`` instead.
* The processing order on reading phase is changed. smart_quotes, sphinx
domains, :event:`doctree-read` event and versioning doctrees are invoked
earlier than so far. For more details, please read a description of
:py:meth:`.Sphinx.add_transform()`
* #4827: All ``substitution_definition`` nodes are removed from doctree on
reading phase
Deprecated
----------
* :confval:`source_parsers` is deprecated
instead.
* ``Application.import_object()`` is deprecated
* Drop function based directive support. For now, Sphinx only supports class
based directives.
@ -34,6 +41,8 @@ Deprecated
* #2157: helper function ``warn()`` for HTML themes is deprecated
* ``env._nitpick_ignore`` is deprecated
* ``app.override_domain()`` is deprecated
* ``app.add_stylesheet()`` is deprecated
* ``sphinx.versioning.prepare()`` is deprecated
* ``Config.__init__()`` has changed; the *dirname*, *filename* and *tags*
argument has been deprecated
* ``Config.check_types()`` is deprecated
@ -61,6 +70,11 @@ Features added
* LaTeX: new key ``'fvset'`` for :confval:`latex_elements`. For
XeLaTeX/LuaLaTeX its default sets ``fanvyvrb`` to use normal, not small,
fontsize in code-blocks (refs: #4793)
* Add :confval:`html_css_files` and :confval:`epub_css_files` for adding CSS
files from configuration
* #4834: Ensure set object descriptions are reproducible.
* #4828: Allow to override :confval:`numfig_format` partially. Full definition
is not needed.
* Add ``Config.from_conf_py()`` classmethod to create a new config object from
configuration file
@ -95,6 +109,23 @@ Features added
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
* #4812: autodoc ignores type annotated variables
* #4817: wrong URLs on warning messages
* #4784: latex: :confval:`latex_show_urls` assigns incorrect footnote numbers if
hyperlinks exists inside substitutions
* #4837: latex with class memoir Error: Font command ``\sf`` is not supported
* #4803: latex: too slow in proportion to number of auto numbered footnotes
* #4838: htmlhelp: The entries in .hhp file is not ordered
* toctree directive tries to glob for URL having query_string
* #4871: html search: Upper characters problem in German
* #4717: latex: Compilation for German docs failed with LuaLaTeX and XeLaTeX
Testing
--------
@ -128,6 +159,7 @@ Bugs fixed
* #1435: qthelp builder should htmlescape keywords
* epub: Fix docTitle elements of toc.ncx is not escaped
* #4520: apidoc: Subpackage not in toc (introduced in 1.6.6) now fixed
* #4767: html: search highlighting breaks mathjax equations
Release 1.7.1 (released Feb 23, 2018)
=====================================
@ -203,6 +235,8 @@ Incompatible changes
(refs: #4295)
* #4246: Limit width of text body for all themes. Conifigurable via theme
options ``body_min_width`` and ``body_max_width``.
* #4771: apidoc: The ``exclude_patterns`` arguments are ignored if they are
placed just after command line options
1.7.0b2

View File

@ -317,7 +317,7 @@ Documentation using a custom theme or integrated in a website
* PSI4: http://www.psicode.org/psi4manual/master/index.html
* PyMOTW: https://pymotw.com/2/
* python-aspectlib: https://python-aspectlib.readthedocs.io/
(`sphinx_py3doc_enhanced_theme <https://pypi.python.org/pypi/sphinx_py3doc_enhanced_theme>`__)
(`sphinx_py3doc_enhanced_theme <https://pypi.org/project/sphinx_py3doc_enhanced_theme/>`__)
* QGIS: https://qgis.org/en/docs/index.html
* qooxdoo: http://www.qooxdoo.org/current/
* Roundup: http://www.roundup-tracker.org/

View File

@ -3,7 +3,7 @@
========
.. image:: https://img.shields.io/pypi/v/sphinx.svg
:target: https://pypi.python.org/pypi/Sphinx
:target: https://pypi.org/project/Sphinx/
:alt: Package on PyPi
.. image:: https://readthedocs.org/projects/sphinx/badge/
@ -71,7 +71,7 @@ We also publish beta releases::
If you wish to install `Sphinx` for development purposes, refer to `the
contributors guide`__.
__ https://pypi.python.org/pypi/Sphinx
__ https://pypi.org/project/Sphinx/
__ http://www.sphinx-doc.org/en/master/devguide.html
Documentation

View File

@ -8,11 +8,11 @@
not released yet.{%endtrans%}</p>
<p>{%trans%}You can use it from the
<a href="https://github.com/sphinx-doc/sphinx/">Git repo</a> or look for
released versions in the <a href="https://pypi.python.org/pypi/Sphinx">Python
released versions in the <a href="https://pypi.org/project/Sphinx/">Python
Package Index</a>.{%endtrans%}</p>
{% else %}
<p>{%trans%}Current version: <b><a href="changes.html">{{ version }}</a></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.org/project/Sphinx/">Python Package
Index</a>, or install it with:{%endtrans%}</p>
<pre>pip install -U Sphinx</pre>
{% endif %}

View File

@ -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>

View File

@ -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.
To pass options directly to the
``(pdf|xe|lua)latex`` executable, use variable ``LATEXOPTS`` (for example
``LATEXOPTS="--interaction=nonstopmode"``).
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
make latexpdf LATEXOPTS="--interaction=nonstopmode"
.. autoattribute:: name
@ -285,7 +288,7 @@ name is ``rinoh``. Refer to the `rinohtype manual`_ for details.
globalcontext_filename = 'globalcontext.phpdump'
searchindex_filename = 'searchindex.phpdump'
.. _PHP serialization: https://pypi.python.org/pypi/phpserialize
.. _PHP serialization: https://pypi.org/project/phpserialize/
.. attribute:: implementation

View File

@ -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',
@ -56,9 +56,14 @@ latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
'Georg Brandl', 'manual', 1)]
latex_logo = '_static/sphinx.png'
latex_elements = {
'fontpkg': '\\usepackage{palatino}',
'fontpkg': r'''
\usepackage[sc]{mathpazo}
\usepackage[scaled]{helvet}
\usepackage{courier}
''',
'passoptionstopackages': '\\PassOptionsToPackage{svgnames}{xcolor}',
'preamble': '\\DeclareUnicodeCharacter{229E}{\\ensuremath{\\boxplus}}',
'fvset': '\\fvset{fontsize=auto}',
# fix missing index entry due to RTD doing only once pdflatex after makeindex
'printindex': r'''
\IfFileExists{\jobname.ind}

View File

@ -59,9 +59,6 @@ Important points to note:
Note that the current builder tag is not available in ``conf.py``, as it is
created *after* the builder is initialized.
.. seealso:: Additional configurations, such as adding stylesheets,
javascripts, builders, etc. can be made through the :doc:`/extdev/appapi`.
General configuration
---------------------
@ -195,8 +192,9 @@ General configuration
.. index:: pair: global; substitutions
A string of reStructuredText that will be included at the end of every source
file that is read. This is the right place to add substitutions that should
be available in every file. An example::
file that is read. This is a possible place to add substitutions that should
be available in every file (another being :confval:`rst_prolog`). An
example::
rst_epilog = """
.. |psf| replace:: Python Software Foundation
@ -206,8 +204,16 @@ General configuration
.. confval:: rst_prolog
.. index:: pair: global; substitutions
A string of reStructuredText that will be included at the beginning of every
source file that is read.
source file that is read. This is a possible place to add substitutions that
should be available in every file (another being :confval:`rst_epilog`). An
example::
rst_prolog = """
.. |psf| replace:: Python Software Foundation
"""
.. versionadded:: 1.0
@ -846,6 +852,22 @@ that use Sphinx's HTMLWriter class.
The image file will be copied to the ``_static`` directory of the output
HTML, but only if the file does not already exist there.
.. confval:: html_css_files
A list of CSS files. The entry must be a *filename* string or a tuple
containing the *filename* string and the *attributes* dictionary. The
*filename* must be relative to the :confval:`html_static_path`, or a full URI
with scheme like ``http://example.org/style.css``. The *attributes* is used
for attributes of ``<link>`` tag. It defaults to an empty list.
Example::
html_css_files = ['custom.css'
'https://example.com/css/custom.css',
('print.css', {'media': 'print'})]
.. versionadded:: 1.8
.. confval:: html_static_path
A list of paths that contain custom static files (such as style
@ -1125,8 +1147,8 @@ that use Sphinx's HTMLWriter class.
Sphinx uses a Python implementation by default. You can use a C
implementation to accelerate building the index file.
* `PorterStemmer <https://pypi.python.org/pypi/PorterStemmer>`_ (``en``)
* `PyStemmer <https://pypi.python.org/pypi/PyStemmer>`_ (all languages)
* `PorterStemmer <https://pypi.org/project/PorterStemmer/>`_ (``en``)
* `PyStemmer <https://pypi.org/project/PyStemmer/>`_ (all languages)
.. versionadded:: 1.1
With support for ``en`` and ``ja``.
@ -1158,7 +1180,7 @@ that use Sphinx's HTMLWriter class.
library ('libmecab.so' for linux, 'libmecab.dll' for windows) is required.
:'sphinx.search.ja.JanomeSplitter':
Janome binding. To use this splitter,
`Janome <https://pypi.python.org/pypi/Janome>`_ is required.
`Janome <https://pypi.org/project/Janome/>`_ is required.
To keep compatibility, ``'mecab'``, ``'janome'`` and ``'default'`` are also
acceptable. However it will be deprecated in Sphinx-1.6.
@ -1511,6 +1533,14 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
.. versionadded:: 1.1
.. confval:: epub_css_files
A list of CSS files. The entry must be a *filename* string or a tuple
containing the *filename* string and the *attributes* dictionary. For more
information, see :confval:`html_css_files`.
.. versionadded:: 1.8
.. confval:: epub_guide
Meta data for the guide element of :file:`content.opf`. This is a
@ -1837,8 +1867,15 @@ These options influence LaTeX output. See further :doc:`latex`.
``'lualatex'`` uses same default setting as ``'xelatex'``
``'fontpkg'``
Font package inclusion, default ``'\\usepackage{times}'`` (which uses
Times and Helvetica). You can set this to ``''`` to use the Computer
Modern fonts.
Times for text, Helvetica for sans serif and Courier for code-blocks).
.. hint::
Courier is much wider than Times, and Sphinx emits LaTeX command
``\small`` in code-blocks to compensate. Since ``1.5`` this is not
hard-coded anymore: ``\fvset{fontsize=auto}`` can be added to
preamble to not change font size in code-blocks. Since ``1.8`` a
separate ``'fvset'`` key is provided for this.
.. versionchanged:: 1.2
Defaults to ``''`` when the :confval:`language` uses the Cyrillic
@ -1847,6 +1884,8 @@ These options influence LaTeX output. See further :doc:`latex`.
Defaults to ``''`` when :confval:`latex_engine` is ``'xelatex'``.
.. versionchanged:: 1.6
Defaults to ``''`` also with ``'lualatex'``.
.. versionchanged:: 1.8
``'xelatex'`` and ``'lualatex'`` do ``\fvset{fontsize=auto}``.
``'fncychap'``
Inclusion of the "fncychap" package (which makes fancy chapter titles),
default ``'\\usepackage[Bjarne]{fncychap}'`` for English documentation

View File

@ -141,5 +141,5 @@ own extensions.
.. _inlinesyntaxhighlight: https://sphinxcontrib-inlinesyntaxhighlight.readthedocs.io/
.. _CMake: https://cmake.org
.. _domaintools: https://bitbucket.org/klorenz/sphinxcontrib-domaintools
.. _restbuilder: https://pypi.python.org/pypi/sphinxcontrib-restbuilder
.. _restbuilder: https://pypi.org/project/sphinxcontrib-restbuilder/
.. _Lasso: http://www.lassosoft.com/

View File

@ -1,7 +1,9 @@
.. highlight:: rest
:mod:`sphinx.ext.imgconverter` -- Convert images to appropriate format for builders
===================================================================================
.. _sphinx.ext.imgconverter:
:mod:`sphinx.ext.imgconverter` -- A reference implementation for image converter using Imagemagick
==================================================================================================
.. module:: sphinx.ext.imgconverter
:synopsis: Convert images to appropriate format for builders
@ -16,6 +18,12 @@ Internally, this extension uses Imagemagick_ to convert images.
.. _Imagemagick: https://www.imagemagick.org/script/index.php
.. note:: Imagemagick rasterizes a SVG image on conversion. As a result, the image
becomes not scalable. To avoid that, please use other image converters
like sphinxcontrib-svg2pdfconverter_ (which uses Inkscape or rsvg-convert).
.. _sphinxcontrib-svg2pdfconverter: https://github.com/missinglinkelectronics/sphinxcontrib-svg2pdfconverter
Configuration
-------------

View File

@ -94,6 +94,7 @@ APIs used for writing extensions
nodes
logging
i18n
utils
Deprecated APIs
---------------
@ -113,6 +114,11 @@ The following is a list of deprecated interface.
- (will be) Removed
- Alternatives
* - :meth:`~sphinx.application.Sphinx.add_stylesheet()`
- 1.8
- 4.0
- :meth:`~sphinx.application.Sphinx.add_css_file()`
* - ``Config.check_unicode()``
- 1.8
- 3.0
@ -129,6 +135,11 @@ The following is a list of deprecated interface.
- 3.0
- ``Config.from_conf_py()``
* - ``sphinx.versioning.prepare()``
- 1.8
- 3.0
- ``sphinx.versioning.UIDTransform``
* - ``sphinx.application.Sphinx.override_domain()``
- 1.8
- 3.0
@ -278,13 +289,18 @@ The following is a list of deprecated interface.
* - ``sphinx.websupport``
- 1.6
- 2.0
- `sphinxcontrib-websupport <https://pypi.python.org/pypi/sphinxcontrib-websupport>`_
- `sphinxcontrib-websupport <https://pypi.org/project/sphinxcontrib-websupport/>`_
* - ``StandaloneHTMLBuilder.css_files``
- 1.6
- 2.0
- :meth:`~sphinx.application.Sphinx.add_stylesheet()`
* - ``document.settings.gettext_compact``
- 1.8
- 1.8
- :confval:`gettext_compact`
* - ``Sphinx.status_iterator()``
- 1.6
- 1.7

22
doc/extdev/utils.rst Normal file
View File

@ -0,0 +1,22 @@
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:
.. autoclass:: sphinx.transforms.post_transforms.images.ImageConverter
:members:

View File

@ -23,7 +23,7 @@ How do I...
Use themes, see :doc:`theming`.
... add global substitutions or includes?
Add them in the :confval:`rst_epilog` config value.
Add them in the :confval:`rst_prolog` or :confval:`rst_epilog` config value.
... display the whole TOC tree in the sidebar?
Use the :data:`toctree` callable in a custom layout template, probably in the
@ -72,7 +72,7 @@ SCons
PyPI
Jannis Leidel wrote a `setuptools command
<https://pypi.python.org/pypi/Sphinx-PyPI-upload>`_ that automatically
<https://pypi.org/project/Sphinx-PyPI-upload/>`_ that automatically
uploads Sphinx documentation to the PyPI package documentation area at
https://pythonhosted.org/.

View File

@ -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`_.
@ -322,8 +322,8 @@ There is `sphinx translation page`_ for Sphinx-1.3 documentation.
.. [2] Because nobody expects the Spanish Inquisition!
.. _`transifex-client`: https://pypi.python.org/pypi/transifex-client
.. _`sphinx-intl`: https://pypi.python.org/pypi/sphinx-intl
.. _`transifex-client`: https://pypi.org/project/transifex-client/
.. _`sphinx-intl`: https://pypi.org/project/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/

View File

@ -29,7 +29,7 @@ This section is intended to collect helpful hints for those wanting to migrate
to reStructuredText/Sphinx from other documentation systems.
* Gerard Flanagan has written a script to convert pure HTML to reST; it can be
found at the `Python Package Index <https://pypi.python.org/pypi/html2rest>`_.
found at the `Python Package Index <https://pypi.org/project/html2rest/>`_.
* For converting the old Python docs to Sphinx, a converter was written which
can be found at `the Python SVN repository
@ -40,7 +40,7 @@ to reStructuredText/Sphinx from other documentation systems.
markup; it is at `GitHub <https://github.com/wojdyr/db2rst>`_.
* Christophe de Vienne wrote a tool to convert from Open/LibreOffice documents
to Sphinx: `odt2sphinx <https://pypi.python.org/pypi/odt2sphinx/>`_.
to Sphinx: `odt2sphinx <https://pypi.org/project/odt2sphinx/>`_.
* To convert different markups, `Pandoc <https://pandoc.org/>`_ is
a very helpful tool.

View File

@ -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::

View File

@ -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::

View File

@ -134,7 +134,7 @@ These themes are:
Check out at its `installation page`_ how to set up properly
:confval:`html_sidebars` for its use.
.. _Alabaster theme: https://pypi.python.org/pypi/alabaster
.. _Alabaster theme: https://pypi.org/project/alabaster/
.. _installation page: https://alabaster.readthedocs.io/en/latest/installation.html
* **classic** -- This is the classic theme, which looks like `the Python 2
@ -418,7 +418,7 @@ Third Party Themes
View a working demo over on readthedocs.org. You can get install and options
information at `Read the Docs Sphinx Theme`_ page.
.. _Read the Docs Sphinx Theme: https://pypi.python.org/pypi/sphinx_rtd_theme
.. _Read the Docs Sphinx Theme: https://pypi.org/project/sphinx_rtd_theme/
.. versionchanged:: 1.4
**sphinx_rtd_theme** has become optional.

View File

@ -7,6 +7,8 @@ Installing Sphinx
:local:
:backlinks: none
.. highlight:: console
Overview
--------
@ -25,7 +27,7 @@ Debian/Ubuntu
Install either ``python3-sphinx`` (Python 3) or ``python-sphinx`` (Python 2)
using :command:`apt-get`:
.. code-block:: bash
::
$ apt-get install python3-sphinx
@ -36,7 +38,7 @@ RHEL, CentOS
Install ``python-sphinx`` using :command:`yum`:
.. code-block:: bash
::
$ yum install python-sphinx
@ -65,7 +67,7 @@ __ https://www.anaconda.com/download/#macos
Homebrew
~~~~~~~~
.. code-block:: bash
::
$ brew install sphinx-doc
@ -79,13 +81,13 @@ MacPorts
Install either ``python36-sphinx`` (Python 3) or ``python27-sphinx`` (Python 2)
using :command:`port`:
.. code-block:: bash
::
$ sudo port install py36-sphinx
To set up the executable paths, use the ``port select`` command:
.. code-block:: bash
::
$ sudo port select --set python python36
$ sudo port select --set sphinx py36-sphinx
@ -97,7 +99,7 @@ __ https://www.macports.org/ports.php?by=library&substr=py36-sphinx
Anaconda
~~~~~~~~
.. code-block:: console
::
$ conda install sphinx
@ -130,20 +132,20 @@ Installation from PyPI
----------------------
Sphinx packages are published on the `Python Package Index
<https://pypi.python.org/pypi/Sphinx>`_. The preferred tool for installing
<https://pypi.org/project/Sphinx/>`_. The preferred tool for installing
packages from *PyPI* is :command:`pip`. This tool is provided with all modern
versions of Python.
On Linux or MacOS, you should open your terminal and run the following command.
.. code-block:: shell
::
$ pip install -U sphinx
On Windows, you should open *Command Prompt* (:kbd:`⊞Win-r` and type
:command:`cmd`) and run the same command.
.. code-block:: bat
.. code-block:: doscon
C:\> pip install -U sphinx
@ -156,7 +158,7 @@ release. You will not generally need (or want) to do this, but it can be
useful if you see a possible bug in the latest stable release. To do this, use
the ``--pre`` flag.
.. code-block:: shell
::
$ pip install -U --pre sphinx
@ -168,13 +170,13 @@ You can install Sphinx directly from a clone of the `Git repository`__. This
can be done either by cloning the repo and installing from the local clone, on
simply installing directly via :command:`git`.
.. code-block:: shell
::
$ git clone https://github.com/sphinx-doc/sphinx
$ cd sphinx
$ pip install .
.. code-block:: shell
::
$ pip install git+https://github.com/sphinx-doc/sphinx
@ -182,6 +184,8 @@ You can also download a snapshot of the Git repo in either `tar.gz`__ or
`zip`__ format. Once downloaded and extracted, these can be installed with
:command:`pip` as above.
.. highlight:: default
__ https://github.com/sphinx-doc/sphinx
__ https://github.com/sphinx-doc/sphinx/archive/master.tar.gz
__ https://github.com/sphinx-doc/sphinx/archive/master.zip

View File

@ -1,5 +1,7 @@
.. highlightlang:: rst
.. _rst-primer:
=======================
reStructuredText Primer
=======================
@ -506,11 +508,14 @@ or this::
See the :duref:`reST reference for substitutions <substitution-definitions>`
for details.
.. index:: ! pair: global; substitutions
If you want to use some substitutions for all documents, put them into
:confval:`rst_prolog` or put them into a separate file and include it into all
documents you want to use them in, using the :rst:dir:`include` directive. (Be
sure to give the include file a file name extension differing from that of
other source files, to avoid Sphinx finding it as a standalone document.)
:confval:`rst_prolog` or :confval:`rst_epilog` or put them into a separate file
and include it into all documents you want to use them in, using the
:rst:dir:`include` directive. (Be sure to give the include file a file name
extension differing from that of other source files, to avoid Sphinx finding it
as a standalone document.)
Sphinx defines some default substitutions, see :ref:`default-substitutions`.

View File

@ -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``.

View File

@ -1287,18 +1287,18 @@ Jinja_, Operation_, and Scala_.
.. _sphinx-contrib: https://bitbucket.org/birkenfeld/sphinx-contrib/
.. _Ada: https://pypi.python.org/pypi/sphinxcontrib-adadomain
.. _Chapel: https://pypi.python.org/pypi/sphinxcontrib-chapeldomain
.. _CoffeeScript: https://pypi.python.org/pypi/sphinxcontrib-coffee
.. _Common Lisp: https://pypi.python.org/pypi/sphinxcontrib-cldomain
.. _dqn: https://pypi.python.org/pypi/sphinxcontrib-dqndomain
.. _Erlang: https://pypi.python.org/pypi/sphinxcontrib-erlangdomain
.. _Go: https://pypi.python.org/pypi/sphinxcontrib-golangdomain
.. _HTTP: https://pypi.python.org/pypi/sphinxcontrib-httpdomain
.. _Jinja: https://pypi.python.org/pypi/sphinxcontrib-jinjadomain
.. _Lasso: https://pypi.python.org/pypi/sphinxcontrib-lassodomain
.. _MATLAB: https://pypi.python.org/pypi/sphinxcontrib-matlabdomain
.. _Operation: https://pypi.python.org/pypi/sphinxcontrib-operationdomain
.. _PHP: https://pypi.python.org/pypi/sphinxcontrib-phpdomain
.. _Ada: https://pypi.org/project/sphinxcontrib-adadomain/
.. _Chapel: https://pypi.org/project/sphinxcontrib-chapeldomain/
.. _CoffeeScript: https://pypi.org/project/sphinxcontrib-coffee/
.. _Common Lisp: https://pypi.org/project/sphinxcontrib-cldomain/
.. _dqn: https://pypi.org/project/sphinxcontrib-dqndomain/
.. _Erlang: https://pypi.org/project/sphinxcontrib-erlangdomain/
.. _Go: https://pypi.org/project/sphinxcontrib-golangdomain/
.. _HTTP: https://pypi.org/project/sphinxcontrib-httpdomain/
.. _Jinja: https://pypi.org/project/sphinxcontrib-jinjadomain/
.. _Lasso: https://pypi.org/project/sphinxcontrib-lassodomain/
.. _MATLAB: https://pypi.org/project/sphinxcontrib-matlabdomain/
.. _Operation: https://pypi.org/project/sphinxcontrib-operationdomain/
.. _PHP: https://pypi.org/project/sphinxcontrib-phpdomain/
.. _Ruby: https://bitbucket.org/birkenfeld/sphinx-contrib/src/default/rubydomain
.. _Scala: https://pypi.python.org/pypi/sphinxcontrib-scaladomain
.. _Scala: https://pypi.org/project/sphinxcontrib-scaladomain/

View File

@ -1,3 +1,5 @@
.. _rst-index:
================
reStructuredText
================

View File

@ -40,9 +40,17 @@ The WebSupport Class
comment that was added.
staticdir
If static files are served from a location besides ``'/static'``, this
should be a string with the name of that location
(e.g. ``'/static_files'``).
If the static files should be created in a different location
**and not in** ``'/static'``, this should be a string with the name of
that location (e.g. ``builddir + '/static_files'``).
.. note::
If you specify ``staticdir``, you will typically want to adjust
``staticroot`` accordingly.
staticroot
If the static files are not served from ``'/static'``, this should be a
string with the name of that location (e.g. ``'/static_files'``).
docroot
If the documentation is not served from the base path of a URL, this

View File

@ -176,7 +176,7 @@ setup(
name='Sphinx',
version=sphinx.__version__,
url='http://sphinx-doc.org/',
download_url='https://pypi.python.org/pypi/Sphinx',
download_url='https://pypi.org/project/Sphinx/',
license='BSD',
author='Georg Brandl',
author_email='georg@python.org',
@ -189,6 +189,9 @@ setup(
'Environment :: Web Environment',
'Intended Audience :: Developers',
'Intended Audience :: Education',
'Intended Audience :: End Users/Desktop',
'Intended Audience :: Science/Research',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
@ -200,12 +203,22 @@ setup(
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Framework :: Setuptools Plugin',
'Framework :: Sphinx',
'Framework :: Sphinx :: Extension',
'Framework :: Sphinx :: Theme',
'Topic :: Documentation',
'Topic :: Documentation :: Sphinx',
'Topic :: Internet :: WWW/HTTP :: Site Management',
'Topic :: Printing',
'Topic :: Software Development',
'Topic :: Software Development :: Documentation',
'Topic :: Text Processing',
'Topic :: Text Processing :: General',
'Topic :: Text Processing :: Indexing',
'Topic :: Text Processing :: Markup',
'Topic :: Text Processing :: Markup :: HTML',
'Topic :: Text Processing :: Markup :: LaTeX',
'Topic :: Utilities',
],
platforms='any',

View File

@ -27,7 +27,9 @@ from six.moves import cStringIO
import sphinx
from sphinx import package_dir, locale
from sphinx.config import Config, check_unicode
from sphinx.deprecation import RemovedInSphinx20Warning, RemovedInSphinx30Warning
from sphinx.deprecation import (
RemovedInSphinx20Warning, RemovedInSphinx30Warning, RemovedInSphinx40Warning
)
from sphinx.environment import BuildEnvironment
from sphinx.errors import ApplicationError, ConfigError, VersionRequirementError
from sphinx.events import EventManager
@ -41,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:
@ -349,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:
@ -964,7 +966,30 @@ class Sphinx(object):
Add the standard docutils :class:`Transform` subclass *transform* to
the list of transforms that are applied after Sphinx parses a reST
document.
"""
.. list-table:: priority range categories for Sphinx transforms
* - Priority
- Main purpose in Sphinx
* - 0-99
- Fix invalid nodes by docutils. Translate a doctree.
* - 100-299
- Preparation
* - 300-399
- early
* - 400-699
- main
* - 700-799
- Post processing. Deadline to modify text and referencing.
* - 800-899
- Collect referencing and referenced nodes. Domain processing.
* - 900-999
- Finalize and clean up.
refs: `Transform Priority Range Categories`__
__ http://docutils.sourceforge.net/docs/ref/transforms.html#transform-priority-range-categories
""" # NOQA
self.registry.add_transform(transform)
def add_post_transform(self, transform):
@ -997,13 +1022,27 @@ class Sphinx(object):
StandaloneHTMLBuilder.script_files.append(
posixpath.join('_static', filename))
def add_stylesheet(self, filename, alternate=False, title=None):
# type: (unicode, bool, unicode) -> None
def add_css_file(self, filename, **kwargs):
# type: (unicode, **unicode) -> None
"""Register a stylesheet to include in the HTML output.
Add *filename* to the list of CSS files that the default HTML template
will include. Like for :meth:`add_javascript`, the filename must be
relative to the HTML static path, or a full URI with scheme.
will include. The filename must be relative to the HTML static path,
or a full URI with scheme. The keyword arguments are also accepted for
attributes of ``<link>`` tag.
Example::
app.add_css_file('custom.css')
# => <link rel="stylesheet" href="_static/custom.css" type="text/css" />
app.add_css_file('print.css', media='print')
# => <link rel="stylesheet" href="_static/print.css"
# type="text/css" media="print" />
app.add_css_file('fancy.css', rel='alternate stylesheet', title='fancy')
# => <link rel="alternate stylesheet" href="_static/fancy.css"
# type="text/css" title="fancy" />
.. versionadded:: 1.0
@ -1013,17 +1052,33 @@ class Sphinx(object):
arguments. The default is no title and *alternate* = ``False``. For
more information, refer to the `documentation
<https://mdn.io/Web/CSS/Alternative_style_sheets>`__.
.. versionchanged:: 1.8
Renamed from ``app.add_stylesheet()``.
And it allows keyword arguments as attributes of link tag.
"""
logger.debug('[app] adding stylesheet: %r', filename)
from sphinx.builders.html import StandaloneHTMLBuilder, Stylesheet
if '://' not in filename:
filename = posixpath.join('_static', filename)
self.registry.add_css_files(filename, **kwargs)
def add_stylesheet(self, filename, alternate=False, title=None):
# type: (unicode, bool, unicode) -> None
"""An alias of :meth:`add_css_file`."""
warnings.warn('The app.add_stylesheet() is deprecated. '
'Please use app.add_css_file() instead.',
RemovedInSphinx40Warning)
attributes = {} # type: Dict[unicode, unicode]
if alternate:
rel = u'alternate stylesheet'
attributes['rel'] = 'alternate stylesheet'
else:
rel = u'stylesheet'
css = Stylesheet(filename, title, rel) # type: ignore
StandaloneHTMLBuilder.css_files.append(css)
attributes['rel'] = 'stylesheet'
if title:
attributes['title'] = title
self.add_css_file(filename, **attributes)
def add_latex_package(self, packagename, options=None):
# type: (unicode, unicode) -> None

View File

@ -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",

View File

@ -708,9 +708,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
"""
logger.info(__('writing %s file...'), outname)
epub_filename = path.join(outdir, outname)
with ZipFile(epub_filename, 'w', ZIP_DEFLATED) as epub: # type: ignore
epub.write(path.join(outdir, 'mimetype'), 'mimetype', ZIP_STORED) # type: ignore
with ZipFile(epub_filename, 'w', ZIP_DEFLATED) as epub:
epub.write(path.join(outdir, 'mimetype'), 'mimetype', ZIP_STORED)
for filename in [u'META-INF/container.xml', u'content.opf', u'toc.ncx']:
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED) # type: ignore
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED)
for filename in self.files:
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED) # type: ignore
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED)

View File

@ -247,6 +247,7 @@ def setup(app):
app.add_config_value('epub_guide', (), 'env')
app.add_config_value('epub_pre_files', [], 'env')
app.add_config_value('epub_post_files', [], 'env')
app.add_config_value('epub_css_files', lambda config: config.html_css_files, 'epub')
app.add_config_value('epub_exclude_files', [], 'env')
app.add_config_value('epub_tocdepth', 3, 'env')
app.add_config_value('epub_tocdup', True, 'env')

View File

@ -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 ..."

View File

@ -50,6 +50,7 @@ from sphinx.util.matching import patmatch, Matcher, DOTFILES
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, os_path, relative_uri, ensuredir, \
movefile, copyfile
from sphinx.util.pycompat import htmlescape
from sphinx.writers.html import HTMLWriter, HTMLTranslator
if False:
@ -101,7 +102,7 @@ class CSSContainer(list):
if isinstance(obj, Stylesheet):
super(CSSContainer, self).append(obj)
else:
super(CSSContainer, self).append(Stylesheet(obj, None, 'stylesheet')) # type: ignore # NOQA
super(CSSContainer, self).append(Stylesheet(obj))
def insert(self, index, obj):
# type: (int, Union[unicode, Stylesheet]) -> None
@ -111,7 +112,7 @@ class CSSContainer(list):
if isinstance(obj, Stylesheet):
super(CSSContainer, self).insert(index, obj)
else:
super(CSSContainer, self).insert(index, Stylesheet(obj, None, 'stylesheet')) # type: ignore # NOQA
super(CSSContainer, self).insert(index, Stylesheet(obj))
def extend(self, other): # type: ignore
# type: (List[Union[unicode, Stylesheet]]) -> None
@ -144,12 +145,19 @@ class Stylesheet(text_type):
its filename (str).
"""
def __new__(cls, filename, title, rel):
attributes = None # type: Dict[unicode, unicode]
filename = None # type: unicode
def __new__(cls, filename, *args, **attributes):
# type: (unicode, unicode, unicode) -> None
self = text_type.__new__(cls, filename) # type: ignore
self.filename = filename
self.title = title
self.rel = rel
self.attributes = attributes
self.attributes.setdefault('rel', 'stylesheet')
self.attributes.setdefault('type', 'text/css')
if args: # old style arguments (rel, title)
self.attributes['rel'] = args[0]
self.attributes['title'] = args[1]
return self
@ -241,8 +249,6 @@ class StandaloneHTMLBuilder(Builder):
# This is a class attribute because it is mutated by Sphinx.add_javascript.
script_files = ['_static/jquery.js', '_static/underscore.js',
'_static/doctools.js'] # type: List[unicode]
# Ditto for this one (Sphinx.add_stylesheet).
css_files = CSSContainer() # type: List[Dict[unicode, unicode]]
imgpath = None # type: unicode
domain_indices = [] # type: List[Tuple[unicode, Type[Index], List[Tuple[unicode, List[List[Union[unicode, int]]]]], bool]] # NOQA
@ -250,6 +256,13 @@ class StandaloneHTMLBuilder(Builder):
# cached publisher object for snippets
_publisher = None
def __init__(self, app):
# type: (Sphinx) -> None
super(StandaloneHTMLBuilder, self).__init__(app)
# CSS files
self.css_files = CSSContainer() # type: List[Dict[unicode, unicode]]
def init(self):
# type: () -> None
self.build_info = self.create_build_info()
@ -262,6 +275,7 @@ class StandaloneHTMLBuilder(Builder):
self.init_templates()
self.init_highlighter()
self.init_css_files()
if self.config.html_file_suffix is not None:
self.out_suffix = self.config.html_file_suffix
@ -324,6 +338,27 @@ class StandaloneHTMLBuilder(Builder):
self.highlighter = PygmentsBridge('html', style,
self.config.trim_doctest_flags)
def init_css_files(self):
# type: () -> None
for filename, attrs in self.app.registry.css_files:
self.css_files.append(Stylesheet(filename, **attrs)) # type: ignore
for entry in self.get_builder_config('css_files', 'html'):
if isinstance(entry, string_types):
filename = entry
attrs = {}
else:
try:
filename, attrs = entry
except (TypeError, ValueError):
logger.warning('invalid css_file: %r', entry)
continue
if '://' not in filename:
filename = path.join('_static', filename)
self.css_files.append(Stylesheet(filename, **attrs)) # type: ignore
@property
def default_translator_class(self):
# type: () -> nodes.NodeVisitor
@ -988,6 +1023,17 @@ class StandaloneHTMLBuilder(Builder):
return uri
ctx['pathto'] = pathto
def css_tag(css):
# type: (Stylesheet) -> unicode
attrs = []
for key in sorted(css.attributes):
value = css.attributes[key]
if value is not None:
attrs.append('%s="%s"' % (key, htmlescape(value, True)))
attrs.append('href="%s"' % pathto(css.filename, resource=True))
return '<link %s />' % ' '.join(attrs)
ctx['css_tag'] = css_tag
def hasdoc(name):
# type: (unicode) -> bool
if name in self.env.all_docs:
@ -1316,6 +1362,7 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
self.templates = None # no template bridge necessary
self.init_templates()
self.init_highlighter()
self.init_css_files()
self.use_index = self.get_builder_config('use_index', 'html')
def get_target_uri(self, docname, typ=None):
@ -1440,6 +1487,7 @@ def setup(app):
app.add_config_value('html_style', None, 'html', string_classes)
app.add_config_value('html_logo', None, 'html', string_classes)
app.add_config_value('html_favicon', None, 'html', string_classes)
app.add_config_value('html_css_files', [], 'html')
app.add_config_value('html_static_path', [], 'html')
app.add_config_value('html_extra_path', [], 'html')
app.add_config_value('html_last_updated_fmt', None, 'html', string_classes)

View File

@ -248,6 +248,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
outdir += os.sep
olen = len(outdir)
for root, dirs, files in os.walk(outdir):
dirs.sort()
files.sort()
staticdir = root.startswith(path.join(outdir, '_static'))
for fn in sorted(files):
if (staticdir and not fn.endswith('.js')) or \

View File

@ -24,6 +24,7 @@ from sphinx.environment import NoUri
from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.errors import SphinxError, ConfigError
from sphinx.locale import _, __
from sphinx.transforms import SphinxTransformer
from sphinx.util import texescape, logging, status_iterator
from sphinx.util.console import bold, darkgreen # type: ignore
from sphinx.util.docutils import new_document
@ -144,6 +145,7 @@ class LaTeXBuilder(Builder):
docname, toctree_only,
appendices=((docclass != 'howto') and self.config.latex_appendices or []))
doctree['tocdepth'] = tocdepth
self.apply_transforms(doctree)
self.post_process_images(doctree)
logger.info(__("writing... "), nonl=1)
doctree.settings = docsettings
@ -210,6 +212,12 @@ class LaTeXBuilder(Builder):
pendingnode.replace_self(newnodes)
return largetree
def apply_transforms(self, doctree):
# type: (nodes.document) -> None
transformer = SphinxTransformer(doctree)
transformer.set_environment(self.env)
transformer.apply_transforms()
def finish(self):
# type: () -> None
self.copy_image_files()

View File

@ -0,0 +1,161 @@
# -*- coding: utf-8 -*-
"""
sphinx.builders.latex.transforms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transforms for LaTeX builder.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from docutils import nodes
from sphinx.transforms import SphinxTransform
if False:
# For type annotation
from typing import Dict, List, Set, Union # NOQA
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
class ShowUrlsTransform(SphinxTransform):
"""Expand references to inline text or footnotes.
For more information, see :confval:`latex_show_urls`.
"""
default_priority = 400
# references are expanded to footnotes (or not)
expanded = False
def apply(self):
# type: () -> None
# replace id_prefix temporarily
id_prefix = self.document.settings.id_prefix
self.document.settings.id_prefix = 'show_urls'
self.expand_show_urls()
if self.expanded:
self.renumber_footnotes()
# restore id_prefix
self.document.settings.id_prefix = id_prefix
def expand_show_urls(self):
# type: () -> None
show_urls = self.document.settings.env.config.latex_show_urls
if show_urls is False or show_urls == 'no':
return
for node in self.document.traverse(nodes.reference):
uri = node.get('refuri', '')
if uri.startswith(URI_SCHEMES):
if uri.startswith('mailto:'):
uri = uri[7:]
if node.astext() != uri:
index = node.parent.index(node)
if show_urls == 'footnote':
footnote_nodes = self.create_footnote(uri)
for i, fn in enumerate(footnote_nodes):
node.parent.insert(index + i + 1, fn)
self.expanded = True
else: # all other true values (b/w compat)
textnode = nodes.Text(" (%s)" % uri)
node.parent.insert(index + 1, textnode)
def create_footnote(self, uri):
# type: (unicode) -> List[Union[nodes.footnote, nodes.footnote_ref]]
label = nodes.label('', '#')
para = nodes.paragraph()
para.append(nodes.reference('', nodes.Text(uri), refuri=uri, nolinkurl=True))
footnote = nodes.footnote(uri, label, para, auto=1)
footnote['names'].append('#')
self.document.note_autofootnote(footnote)
label = nodes.Text('#')
footnote_ref = nodes.footnote_reference('[#]_', label, auto=1,
refid=footnote['ids'][0])
self.document.note_autofootnote_ref(footnote_ref)
footnote.add_backref(footnote_ref['ids'][0])
return [footnote, footnote_ref]
def renumber_footnotes(self):
# type: () -> None
collector = FootnoteCollector(self.document)
self.document.walkabout(collector)
num = 0
for document, footnote in collector.auto_footnotes:
# search unused footnote number
while True:
num += 1
if str(num) not in collector.used_footnote_numbers:
break
# assign new footnote number
old_label = footnote[0].astext()
footnote[0].replace_self(nodes.label('', str(num)))
if old_label in footnote['names']:
footnote['names'].remove(old_label)
footnote['names'].append(str(num))
# update footnote_references by new footnote number
for ref in collector.footnote_refs.get(document, []):
if footnote['ids'][0] == ref['refid']:
ref.remove(ref[0])
ref += nodes.Text(str(num))
class FootnoteCollector(nodes.NodeVisitor):
"""Collect footnotes and footnote references on the document"""
def __init__(self, document):
# type: (nodes.document) -> None
self.auto_footnotes = [] # type: List[nodes.footnote]
self.used_footnote_numbers = set() # type: Set[unicode]
self.footnote_refs = {} # type: Dict[nodes.Node, List[nodes.footnote_reference]] # NOQA
self.current_document = [] # type: List[nodes.Node]
nodes.NodeVisitor.__init__(self, document)
def visit_document(self, node):
# type: (nodes.Node) -> None
self.current_document.append(node)
def depart_document(self, node):
# type: (nodes.Node) -> None
self.current_document.pop()
def visit_start_of_file(self, node):
# type: (nodes.Node) -> None
self.current_document.append(node)
def depart_start_of_file(self, node):
# type: (nodes.Node) -> None
self.current_document.pop()
def unknown_visit(self, node):
# type: (nodes.Node) -> None
pass
def visit_footnote(self, node):
# type: (nodes.footnote) -> None
document = self.current_document[-1]
if node.get('auto'):
self.auto_footnotes.append((document, node))
else:
for name in node['names']:
self.used_footnote_numbers.add(name)
def visit_footnote_reference(self, node):
# type: (nodes.footnote_reference) -> None
document = self.current_document[-1]
footnote_refs = self.footnote_refs.setdefault(document, [])
footnote_refs.append(node)
def unknown_departure(self, node):
# type: (nodes.Node) -> None
pass

View File

@ -132,11 +132,7 @@ class Config(object):
nitpick_ignore = ([], None),
numfig = (False, 'env'),
numfig_secnum_depth = (1, 'env'),
numfig_format = ({'section': _('Section %s'),
'figure': _('Fig. %s'),
'table': _('Table %s'),
'code-block': _('Listing %s')},
'env'),
numfig_format = ({}, 'env'), # will be initialized in init_numfig_format()
tls_verify = (True, 'env'),
tls_cacerts = (None, 'env'),
@ -364,6 +360,19 @@ def convert_source_suffix(app, config):
"But `%r' is given." % source_suffix))
def init_numfig_format(app, config):
# type: (Sphinx, Config) -> None
"""Initialize :confval:`numfig_format`."""
numfig_format = {'section': _('Section %s'),
'figure': _('Fig. %s'),
'table': _('Table %s'),
'code-block': _('Listing %s')}
# override default labels by configuration
numfig_format.update(config.numfig_format)
config.numfig_format = numfig_format # type: ignore
def correct_copyright_year(app, config):
# type: (Sphinx, Config) -> None
"""correct values of copyright year that are not coherent with
@ -446,6 +455,7 @@ def check_unicode(config):
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.connect('config-inited', convert_source_suffix)
app.connect('config-inited', init_numfig_format)
app.connect('config-inited', correct_copyright_year)
app.connect('config-inited', check_confval_types)

View File

@ -33,6 +33,10 @@ class RemovedInSphinx30Warning(PendingDeprecationWarning):
pass
class RemovedInSphinx40Warning(PendingDeprecationWarning):
pass
RemovedInNextVersionWarning = RemovedInSphinx18Warning

View File

@ -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 []

View File

@ -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)

View File

@ -7,8 +7,10 @@
:license: BSD, see LICENSE for details.
"""
import re
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,13 +20,14 @@ 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
if False:
# For type annotation
from typing import Any, Dict, List, Tuple # NOQA
from typing import Any, Dict, Generator, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
@ -41,6 +44,8 @@ locale.versionlabels = DeprecatedDict(
RemovedInSphinx30Warning
)
glob_re = re.compile('.*[*?\[].*')
def int_or_nothing(argument):
# type: (unicode) -> int
@ -49,7 +54,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,30 +77,50 @@ class TocTree(Directive):
def run(self):
# type: () -> List[nodes.Node]
env = self.state.document.settings.env
suffixes = env.config.source_suffix
glob = 'glob' in self.options
subnode = addnodes.toctree()
subnode['parent'] = self.env.docname
ret = []
# (title, ref) pairs, where ref may be a document, or an external link,
# 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()
# don't add the currently visited file in catch-all patterns
all_docnames.remove(env.docname)
subnode['entries'] = []
subnode['includefiles'] = []
subnode['maxdepth'] = self.options.get('maxdepth', -1)
subnode['caption'] = self.options.get('caption')
subnode['glob'] = 'glob' in self.options
subnode['hidden'] = 'hidden' in self.options
subnode['includehidden'] = 'includehidden' in self.options
subnode['numbered'] = self.options.get('numbered', 0)
subnode['titlesonly'] = 'titlesonly' in self.options
set_source_info(self, subnode)
wrappernode = nodes.compound(classes=['toctree-wrapper'])
wrappernode.append(subnode)
self.add_name(wrappernode)
ret = self.parse_content(subnode)
ret.append(wrappernode)
return ret
def parse_content(self, toctree):
suffixes = self.config.source_suffix
# glob target documents
all_docnames = self.env.found_docs.copy()
all_docnames.remove(self.env.docname) # remove current document
ret = []
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)
if (toctree['glob'] and glob_re.match(entry) and
not explicit and not url_re.match(entry)):
patname = docname_join(self.env.docname, entry)
docnames = sorted(patfilter(all_docnames, patname))
for docname in docnames:
all_docnames.remove(docname) # don't include it again
entries.append((None, docname))
includefiles.append(docname)
toctree['entries'].append((None, docname))
toctree['includefiles'].append(docname)
if not docnames:
ret.append(self.state.document.reporter.warning(
'toctree glob pattern %r didn\'t match any documents'
@ -114,42 +139,27 @@ 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:
toctree['entries'].append((title, ref))
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
toctree['entries'].append((title, docname))
toctree['includefiles'].append(docname)
# entries contains all entries (self references, external links etc.)
if 'reversed' in self.options:
entries.reverse()
subnode['entries'] = entries
# includefiles only entries that are documents
subnode['includefiles'] = includefiles
subnode['maxdepth'] = self.options.get('maxdepth', -1)
subnode['caption'] = self.options.get('caption')
subnode['glob'] = glob
subnode['hidden'] = 'hidden' in self.options
subnode['includehidden'] = 'includehidden' in self.options
subnode['numbered'] = self.options.get('numbered', 0)
subnode['titlesonly'] = 'titlesonly' in self.options
set_source_info(self, subnode)
wrappernode = nodes.compound(classes=['toctree-wrapper'])
wrappernode.append(subnode)
self.add_name(wrappernode)
ret.append(wrappernode)
toctree['entries'] = list(reversed(toctree['entries']))
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 +172,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 +192,7 @@ class Author(Directive):
return [para] + messages
class Index(Directive):
class Index(SphinxDirective):
"""
Directive to add entries to the index.
"""
@ -196,8 +205,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 +217,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 +260,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 +272,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 +290,7 @@ class TabularColumns(Directive):
return [node]
class Centered(Directive):
class Centered(SphinxDirective):
"""
Directive to create a centered line of bold text.
"""
@ -304,7 +311,7 @@ class Centered(Directive):
return [subnode] + messages
class Acks(Directive):
class Acks(SphinxDirective):
"""
Directive for a list of names.
"""
@ -326,7 +333,7 @@ class Acks(Directive):
return [node]
class HList(Directive):
class HList(SphinxDirective):
"""
Directive for a list that gets compacted horizontally.
"""
@ -363,7 +370,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 +428,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 +436,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)

View File

@ -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']

View File

@ -21,10 +21,10 @@ from os import path
from docutils.frontend import OptionParser
from docutils.utils import Reporter, get_source_line
from six import BytesIO, itervalues, class_types, next
from six import BytesIO, class_types, next
from six.moves import cPickle as pickle
from sphinx import addnodes, versioning
from sphinx import addnodes
from sphinx.deprecation import RemovedInSphinx20Warning, RemovedInSphinx30Warning
from sphinx.environment.adapters.indexentries import IndexEntries
from sphinx.environment.adapters.toctree import TocTree
@ -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)]
@ -540,7 +540,6 @@ class BuildEnvironment(object):
"""Update settings by new config."""
self.settings['input_encoding'] = config.source_encoding
self.settings['trim_footnote_reference_space'] = config.trim_footnote_reference_space
self.settings['gettext_compact'] = config.gettext_compact
self.settings['language_code'] = config.language or 'en'
# Allow to disable by 3rd party extension (workaround)
@ -571,14 +570,6 @@ class BuildEnvironment(object):
with sphinx_domains(self), rst.default_role(docname, self.config.default_role):
doctree = read_doc(self.app, self, self.doc2path(docname))
# post-processing
for domain in itervalues(self.domains):
domain.process_doc(self, docname, doctree)
# allow extension-specific post-processing
if app:
app.emit('doctree-read', doctree)
# store time of reading, for outdated files detection
# (Some filesystems have coarse timestamp resolution;
# therefore time.time() can be older than filesystem's timestamp.
@ -586,10 +577,6 @@ class BuildEnvironment(object):
self.all_docs[docname] = max(
time.time(), path.getmtime(self.doc2path(docname)))
if self.versioning_condition:
# add uids for versioning
versioning.prepare(doctree)
# cleanup
self.temp_data.clear()
self.ref_context.clear()

View File

@ -1301,7 +1301,10 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
inspect.ismethoddescriptor(self.object):
# can never get arguments of a C function or method
return None
args = Signature(self.object, bound_method=True).format_args()
if isstaticmethod(self.object, cls=self.parent, name=self.object_name):
args = Signature(self.object, bound_method=False).format_args()
else:
args = Signature(self.object, bound_method=True).format_args()
# escape backslashes for reST
args = args.replace('\\', '\\\\')
return args

View File

@ -91,7 +91,7 @@ if False:
logger = logging.getLogger(__name__)
periods_re = re.compile('\.(?:\s+)')
periods_re = re.compile(r'\.(?:\s+)')
# -- autosummary_toc node ------------------------------------------------------
@ -361,7 +361,7 @@ class Autosummary(Directive):
*items* is a list produced by :meth:`get_items`.
"""
table_spec = addnodes.tabular_col_spec()
table_spec['spec'] = r'p{0.5\linewidth}p{0.5\linewidth}'
table_spec['spec'] = r'\X{1}{2}\X{1}{2}'
table = autosummary_table('')
real_table = nodes.table('', classes=['longtable'])

View File

@ -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)

View File

@ -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

View File

@ -26,7 +26,7 @@ if False:
def html_visit_math(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate'))
self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate nohighlight'))
self.body.append(self.encode(node['latex']) + '</span>')
raise nodes.SkipNode
@ -34,7 +34,7 @@ def html_visit_math(self, node):
def html_visit_displaymath(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
if node['nowrap']:
self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight'))
self.body.append(self.encode(node['latex']))
self.body.append('</div>')
raise nodes.SkipNode
@ -47,7 +47,7 @@ def html_visit_displaymath(self, node):
self.body.append('<span class="eqno">(%s)' % number)
self.add_permalink_ref(node, _('Permalink to this equation'))
self.body.append('</span>')
self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight'))
else:
# but only once!
self.body.append('<div class="math">')

View File

@ -27,7 +27,7 @@ if False:
def html_visit_math(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate'))
self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate nohighlight'))
self.body.append(self.builder.config.mathjax_inline[0] +
self.encode(node['latex']) +
self.builder.config.mathjax_inline[1] + '</span>')
@ -36,7 +36,7 @@ def html_visit_math(self, node):
def html_visit_displaymath(self, node):
# type: (nodes.NodeVisitor, nodes.Node) -> None
self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
self.body.append(self.starttag(node, 'div', CLASS='math notranslate nohighlight'))
if node['nowrap']:
self.body.append(self.encode(node['latex']))
self.body.append('</div>')

View File

@ -24,15 +24,17 @@ from sphinx.transforms import (
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink
UnreferencedFootnotesDetector, SphinxSmartQuotes, DoctreeReadEvent, ManpageLink
)
from sphinx.transforms import SphinxTransformer
from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform
from sphinx.transforms.i18n import (
PreserveTranslatableMessages, Locale, RemoveTranslatableInline,
)
from sphinx.transforms.references import SphinxDomains, SubstitutionDefinitionsRemover
from sphinx.util import logging
from sphinx.util.docutils import LoggingReporter
from sphinx.versioning import UIDTransform
if False:
# For type annotation
@ -93,7 +95,9 @@ class SphinxStandaloneReader(SphinxBaseReader):
Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets,
HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds,
RemoveTranslatableInline, FilterSystemMessages, RefOnlyBulletListTransform,
UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink
UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink,
SphinxDomains, SubstitutionDefinitionsRemover, DoctreeReadEvent,
UIDTransform,
] # type: List[Transform]
def __init__(self, app, *args, **kwargs):
@ -116,7 +120,8 @@ class SphinxI18nReader(SphinxBaseReader):
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
AutoNumbering, SortIds, RemoveTranslatableInline,
FilterSystemMessages, RefOnlyBulletListTransform,
UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink]
UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink,
SubstitutionDefinitionsRemover]
def set_lineno_for_reporter(self, lineno):
# type: (int) -> None

View File

@ -425,7 +425,7 @@ msgstr "行规范 %r未能从包含文件 %r 中拉取行"
#: sphinx/directives/other.py:157
msgid "Section author: "
msgstr "节作者:"
msgstr "节作者:"
#: sphinx/directives/other.py:159
msgid "Module author: "
@ -878,7 +878,7 @@ msgstr "格式转换程序退出并报错:\n[stderr]\n%s\n[stdout]\n%s"
#: sphinx/ext/imgmath.py:338 sphinx/ext/jsmath.py:41 sphinx/ext/mathjax.py:42
msgid "Permalink to this equation"
msgstr "永久链接至公式"
msgstr "公式的永久链接"
#: sphinx/ext/intersphinx.py:339
#, python-format
@ -1047,7 +1047,7 @@ msgstr "搜索"
#: sphinx/themes/agogo/layout.html:54 sphinx/themes/basic/searchbox.html:16
msgid "Go"
msgstr "转向"
msgstr ""
#: sphinx/themes/agogo/layout.html:81 sphinx/themes/basic/sourcelink.html:15
msgid "Show Source"
@ -1250,13 +1250,13 @@ msgstr "其他更改"
#: sphinx/writers/html.py:410 sphinx/writers/html5.py:351
#: sphinx/writers/html5.py:356
msgid "Permalink to this headline"
msgstr "永久链接至标题"
msgstr "标题的永久链接"
#: sphinx/themes/basic/static/doctools.js_t:199 sphinx/writers/html.py:126
#: sphinx/writers/html.py:137 sphinx/writers/html5.py:95
#: sphinx/writers/html5.py:106
msgid "Permalink to this definition"
msgstr "永久链接至目标"
msgstr "定义的永久链接"
#: sphinx/themes/basic/static/doctools.js_t:232
msgid "Hide Search Matches"
@ -1313,19 +1313,19 @@ msgstr "当添加指令类时,不应该给定额外参数"
#: sphinx/writers/html.py:414 sphinx/writers/html5.py:360
msgid "Permalink to this table"
msgstr "永久链接至表格"
msgstr "表格的永久链接"
#: sphinx/writers/html.py:466 sphinx/writers/html5.py:412
msgid "Permalink to this code"
msgstr "永久链接至代码"
msgstr "代码的永久链接"
#: sphinx/writers/html.py:470 sphinx/writers/html5.py:416
msgid "Permalink to this image"
msgstr "永久链接至图片"
msgstr "图片的永久链接"
#: sphinx/writers/html.py:472 sphinx/writers/html5.py:418
msgid "Permalink to this toctree"
msgstr "永久链接至目录树"
msgstr "目录的永久链接"
#: sphinx/writers/latex.py:554
msgid "Release"

View File

@ -1046,7 +1046,7 @@ msgstr "搜尋"
#: sphinx/themes/agogo/layout.html:54 sphinx/themes/basic/searchbox.html:16
msgid "Go"
msgstr "前往"
msgstr ""
#: sphinx/themes/agogo/layout.html:81 sphinx/themes/basic/sourcelink.html:15
msgid "Show Source"

View File

@ -12,6 +12,7 @@ import ast
import inspect
import itertools
import re
import sys
import tokenize
from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING
from tokenize import COMMENT, NL
@ -27,6 +28,21 @@ indent_re = re.compile(u'^\\s*$')
emptyline_re = re.compile(u'^\\s*(#.*)?$')
if sys.version_info >= (3, 6):
ASSIGN_NODES = (ast.Assign, ast.AnnAssign)
else:
ASSIGN_NODES = (ast.Assign)
def get_assign_targets(node):
# type: (ast.AST) -> List[ast.expr]
"""Get list of targets from Assign and AnnAssign node."""
if isinstance(node, ast.Assign):
return node.targets
else:
return [node.target] # type: ignore
def get_lvar_names(node, self=None):
# type: (ast.AST, ast.expr) -> List[unicode]
"""Convert assignment-AST to variable names.
@ -285,7 +301,8 @@ class VariableCommentPicker(ast.NodeVisitor):
# type: (ast.Assign) -> None
"""Handles Assign node and pick up a variable comment."""
try:
varnames = sum([get_lvar_names(t, self=self.get_self()) for t in node.targets], [])
targets = get_assign_targets(node)
varnames = sum([get_lvar_names(t, self=self.get_self()) for t in targets], [])
current_line = self.get_line(node.lineno)
except TypeError:
return # this assignment is not new definition!
@ -321,12 +338,18 @@ class VariableCommentPicker(ast.NodeVisitor):
for varname in varnames:
self.add_entry(varname)
def visit_AnnAssign(self, node):
# type: (ast.AST) -> None
"""Handles AnnAssign node and pick up a variable comment."""
self.visit_Assign(node) # type: ignore
def visit_Expr(self, node):
# type: (ast.Expr) -> None
"""Handles Expr node and pick up a comment if string."""
if (isinstance(self.previous, ast.Assign) and isinstance(node.value, ast.Str)):
if (isinstance(self.previous, ASSIGN_NODES) and isinstance(node.value, ast.Str)):
try:
varnames = get_lvar_names(self.previous.targets[0], self.get_self())
targets = get_assign_targets(self.previous)
varnames = get_lvar_names(targets[0], self.get_self())
for varname in varnames:
if isinstance(node.value.s, text_type):
docstring = node.value.s

View File

@ -65,6 +65,9 @@ class SphinxComponentRegistry(object):
#: autodoc documenters; a dict of documenter name -> documenter class
self.documenters = {} # type: Dict[unicode, Type[Documenter]]
#: css_files; a list of tuple of filename and attributes
self.css_files = [] # type: List[Tuple[unicode, Dict[unicode, unicode]]]
#: domains; a dict of domain name -> domain class
self.domains = {} # type: Dict[unicode, Type[Domain]]
@ -412,6 +415,9 @@ class SphinxComponentRegistry(object):
# type: (Type, Callable[[Any, unicode, Any], Any]) -> None
self.autodoc_attrgettrs[typ] = attrgetter
def add_css_files(self, filename, **attributes):
self.css_files.append((filename, attributes))
def add_latex_package(self, name, options):
# type: (unicode, unicode) -> None
logger.debug('[app] adding latex package: %r', name)

View File

@ -318,4 +318,4 @@ class SearchGerman(SearchLanguage):
def stem(self, word):
# type: (unicode) -> unicode
return self.stemmer.stemWord(word)
return self.stemmer.stemWord(word.lower())

View File

@ -4,7 +4,7 @@
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/stable/config
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------

View File

@ -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):

View File

@ -97,8 +97,8 @@
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
{%- for css in css_files %}
{%- 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 %} />
{%- if css|attr("filename") %}
{{ css_tag(css) }}
{%- else %}
<link rel="stylesheet" href="{{ pathto(css, 1) }}" type="text/css" />
{%- endif %}

View File

@ -70,7 +70,9 @@ jQuery.fn.highlightText = function(text, className) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {

View File

@ -43,7 +43,7 @@ def extract_zip(filename, targetdir):
"""Extract zip file to target directory."""
ensuredir(targetdir)
with ZipFile(filename) as archive: # type: ignore
with ZipFile(filename) as archive:
for name in archive.namelist():
if name.endswith('/'):
continue
@ -155,7 +155,7 @@ def is_archived_theme(filename):
# type: (unicode) -> bool
"""Check the specified file is an archived theme file or not."""
try:
with ZipFile(filename) as f: # type: ignore
with ZipFile(filename) as f:
return THEMECONF in f.namelist()
except Exception:
return False

View File

@ -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
@ -350,6 +343,8 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
refs: sphinx.parsers.RSTParser
"""
default_priority = 750
def apply(self):
# type: () -> None
if not self.is_available():
@ -404,6 +399,15 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
yield (texttype[notsmartquotable], txtnode.astext())
class DoctreeReadEvent(SphinxTransform):
"""Emit :event:`doctree-read` event."""
default_priority = 880
def apply(self):
# type: () -> None
self.app.emit('doctree-read', self.document)
class ManpageLink(SphinxTransform):
"""Find manpage section numbers and names"""
default_priority = 999

View File

@ -92,8 +92,7 @@ class Locale(SphinxTransform):
assert source.startswith(self.env.srcdir)
docname = path.splitext(relative_path(path.join(self.env.srcdir, 'dummy'),
source))[0]
textdomain = find_catalog(docname,
self.document.settings.gettext_compact)
textdomain = find_catalog(docname, self.config.gettext_compact)
# fetch translations
dirs = [path.join(self.env.srcdir, directory)

View File

@ -165,19 +165,37 @@ def get_filename_for(filename, mimetype):
class ImageConverter(BaseImageConverter):
"""A base class images converter.
"""A base class for image converters.
The concrete image converters should derive this class and
overrides the following methods and attributes:
An image converter is kind of Docutils transform module. It is used to
convert image files which does not supported by builder to appropriate
format for that builder.
* default_priority (if needed)
* conversion_rules
* is_available()
* convert()
For example, :py:class:`LaTeX builder <.LaTeXBuilder>` supports PDF,
PNG and JPEG as image formats. However it does not support SVG images.
For such case, to use image converters allows to embed these
unsupported images into the document. One of image converters;
:ref:`sphinx.ext. imgconverter <sphinx.ext.imgconverter>` can convert
a SVG image to PNG format using Imagemagick internally.
There are three steps to make your custom image converter:
1. Make a subclass of ``ImageConverter`` class
2. Override ``conversion_rules``, ``is_available()`` and ``convert()``
3. Register your image converter to Sphinx using
:py:meth:`.Sphinx.add_post_transform`
"""
default_priority = 200
#: A conversion rules between two mimetypes which this converters supports
#: A conversion rules the image converter supports.
#: It is represented as a list of pair of source image format (mimetype) and
#: destination one::
#:
#: conversion_rules = [
#: ('image/svg+xml', 'image/png'),
#: ('image/gif', 'image/png'),
#: ('application/pdf', 'image/png'),
#: ]
conversion_rules = [] # type: List[Tuple[unicode, unicode]]
def __init__(self, *args, **kwargs):
@ -216,7 +234,7 @@ class ImageConverter(BaseImageConverter):
def is_available(self):
# type: () -> bool
"""Confirms the converter is available or not."""
"""Return the image converter is available or not."""
raise NotImplementedError()
def guess_mimetypes(self, node):
@ -255,7 +273,11 @@ class ImageConverter(BaseImageConverter):
def convert(self, _from, _to):
# type: (unicode, unicode) -> bool
"""Converts the image to expected one."""
"""Convert a image file to expected format.
*_from* is a path for source image file, and *_to* is a path for
destination file.
"""
raise NotImplementedError()

View File

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
"""
sphinx.transforms.references
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Docutils transforms used by Sphinx.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from docutils import nodes
from docutils.transforms.references import Substitutions
from six import itervalues
from sphinx.transforms import SphinxTransform
class SubstitutionDefinitionsRemover(SphinxTransform):
"""Remove ``substitution_definition node from doctrees."""
# should be invoked after Substitutions process
default_priority = Substitutions.default_priority + 1
def apply(self):
# type: () -> None
for node in self.document.traverse(nodes.substitution_definition):
node.parent.remove(node)
class SphinxDomains(SphinxTransform):
"""Collect objects to Sphinx domains for cross references."""
default_priority = 850
def apply(self):
# type: () -> None
for domain in itervalues(self.env.domains):
domain.process_doc(self, self.env.docname, self.document)

View File

@ -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

View File

@ -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)

View File

@ -244,8 +244,19 @@ def object_description(object):
except TypeError:
pass # Cannot sort dict keys, fall back to generic repr
else:
items = ("%r: %r" % (key, object[key]) for key in sorted_keys)
items = ("%s: %s" %
(object_description(key), object_description(object[key]))
for key in sorted_keys)
return "{%s}" % ", ".join(items)
if isinstance(object, set):
try:
sorted_values = sorted(object)
except TypeError:
pass # Cannot sort set values, fall back to generic repr
else:
template = "{%s}" if PY3 else "set([%s])"
return template % ", ".join(object_description(x)
for x in sorted_values)
try:
s = repr(object)
except Exception:
@ -313,7 +324,10 @@ class Signature(object):
try:
self.signature = inspect.signature(subject)
except IndexError:
if hasattr(subject, '_partialmethod'): # partialmethod with no argument
# Until python 3.6.4, cpython has been crashed on inspection for
# partialmethods not having any arguments.
# https://bugs.python.org/issue33009
if hasattr(subject, '_partialmethod'):
self.signature = None
self.partialmethod_with_noargs = True
else:

View File

@ -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

View File

@ -9,6 +9,7 @@
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import warnings
from itertools import product
from operator import itemgetter
from uuid import uuid4
@ -17,6 +18,7 @@ from six import iteritems
from six.moves import cPickle as pickle
from six.moves import range, zip_longest
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.transforms import SphinxTransform
if False:
@ -155,12 +157,15 @@ def levenshtein_distance(a, b):
class UIDTransform(SphinxTransform):
"""Add UIDs to doctree for versioning."""
default_priority = 100
default_priority = 880
def apply(self):
# type: () -> None
env = self.env
old_doctree = None
if not env.versioning_condition:
return
if env.versioning_compare:
# get old doctree
try:
@ -180,5 +185,7 @@ class UIDTransform(SphinxTransform):
def prepare(document):
# type: (nodes.Node) -> None
"""Simple wrapper for UIDTransform."""
warnings.warn('versioning.prepare() is deprecated. Use UIDTransform instead.',
RemovedInSphinx30Warning)
transform = UIDTransform(document)
transform.apply()

View File

@ -876,7 +876,7 @@ class HTMLTranslator(BaseTranslator):
# type: (nodes.Node, unicode) -> None
logger.warning(__('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html'),
'described at http://sphinx-doc.org/en/master/ext/math.html'),
location=(self.builder.current_docname, node.line))
raise nodes.SkipNode

View File

@ -827,7 +827,7 @@ class HTML5Translator(BaseTranslator):
# type: (nodes.Node, unicode) -> None
logger.warning(__('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html'),
'described at http://sphinx-doc.org/en/master/ext/math.html'),
location=(self.builder.current_docname, node.line))
raise nodes.SkipNode

View File

@ -23,12 +23,12 @@ from six import itervalues, text_type
from sphinx import addnodes
from sphinx import highlighting
from sphinx.builders.latex.transforms import URI_SCHEMES, ShowUrlsTransform # NOQA # for compatibility
from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _, __
from sphinx.transforms import SphinxTransform
from sphinx.util import split_into, logging
from sphinx.util.i18n import format_date
from sphinx.util.nodes import clean_astext, traverse_parent
from sphinx.util.nodes import clean_astext
from sphinx.util.template import LaTeXRenderer
from sphinx.util.texescape import tex_escape_map, tex_replace_map
@ -47,7 +47,6 @@ BEGIN_DOC = r'''
'''
URI_SCHEMES = ('mailto:', 'http:', 'https:', 'ftp:')
LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
"subsubsection", "paragraph", "subparagraph"]
@ -190,10 +189,11 @@ class LaTeXWriter(writers.Writer):
# Helper classes
class ExtBabel(Babel):
def __init__(self, language_code):
# type: (unicode) -> None
def __init__(self, language_code, use_polyglossia=False):
# type: (unicode, bool) -> None
super(ExtBabel, self).__init__(language_code or '')
self.language_code = language_code
self.use_polyglossia = use_polyglossia
def get_shorthandoff(self):
# type: () -> unicode
@ -221,116 +221,27 @@ class ExtBabel(Babel):
def get_language(self):
# type: () -> unicode
language = super(ExtBabel, self).get_language()
if not language:
if language == 'ngerman' and self.use_polyglossia:
# polyglossia calls new orthography (Neue Rechtschreibung) as
# german (with new spelling option).
return 'german'
elif not language:
return 'english' # fallback to english
else:
return language
class ShowUrlsTransform(SphinxTransform, object):
def __init__(self, document, startnode=None):
# type: (nodes.document, nodes.Node) -> None
super(ShowUrlsTransform, self).__init__(document, startnode)
self.expanded = False
def apply(self):
# type: () -> None
# replace id_prefix temporarily
id_prefix = self.document.settings.id_prefix
self.document.settings.id_prefix = 'show_urls'
self.expand_show_urls()
if self.expanded:
self.renumber_footnotes()
# restore id_prefix
self.document.settings.id_prefix = id_prefix
def expand_show_urls(self):
# type: () -> None
show_urls = self.document.settings.env.config.latex_show_urls
if show_urls is False or show_urls == 'no':
return
for node in self.document.traverse(nodes.reference):
uri = node.get('refuri', '')
if uri.startswith(URI_SCHEMES):
if uri.startswith('mailto:'):
uri = uri[7:]
if node.astext() != uri:
index = node.parent.index(node)
if show_urls == 'footnote':
footnote_nodes = self.create_footnote(uri)
for i, fn in enumerate(footnote_nodes):
node.parent.insert(index + i + 1, fn)
self.expanded = True
else: # all other true values (b/w compat)
textnode = nodes.Text(" (%s)" % uri)
node.parent.insert(index + 1, textnode)
def create_footnote(self, uri):
# type: (unicode) -> List[Union[nodes.footnote, nodes.footnote_ref]]
label = nodes.label('', '#')
para = nodes.paragraph()
para.append(nodes.reference('', nodes.Text(uri), refuri=uri, nolinkurl=True))
footnote = nodes.footnote(uri, label, para, auto=1)
footnote['names'].append('#')
self.document.note_autofootnote(footnote)
label = nodes.Text('#')
footnote_ref = nodes.footnote_reference('[#]_', label, auto=1,
refid=footnote['ids'][0])
self.document.note_autofootnote_ref(footnote_ref)
footnote.add_backref(footnote_ref['ids'][0])
return [footnote, footnote_ref]
def renumber_footnotes(self):
# type: () -> None
def is_used_number(number):
# type: (unicode) -> bool
for node in self.document.traverse(nodes.footnote):
if not node.get('auto') and number in node['names']:
return True
return False
def is_auto_footnote(node):
# type: (nodes.Node) -> bool
return isinstance(node, nodes.footnote) and node.get('auto')
def footnote_ref_by(node):
# type: (nodes.Node) -> Callable[[nodes.Node], bool]
ids = node['ids']
parent = list(traverse_parent(node, (nodes.document, addnodes.start_of_file)))[0]
def is_footnote_ref(node):
# type: (nodes.Node) -> bool
return (isinstance(node, nodes.footnote_reference) and
ids[0] == node['refid'] and
parent in list(traverse_parent(node)))
return is_footnote_ref
startnum = 1
for footnote in self.document.traverse(is_auto_footnote):
while True:
label = str(startnum)
startnum += 1
if not is_used_number(label):
break
old_label = footnote[0].astext()
footnote.remove(footnote[0])
footnote.insert(0, nodes.label('', label))
if old_label in footnote['names']:
footnote['names'].remove(old_label)
footnote['names'].append(label)
for footnote_ref in self.document.traverse(footnote_ref_by(footnote)):
footnote_ref.remove(footnote_ref[0])
footnote_ref += nodes.Text(label)
def get_mainlanguage_options(self):
# type: () -> unicode
"""Return options for polyglossia's ``\setmainlanguage``."""
language = super(ExtBabel, self).get_language()
if self.use_polyglossia is False:
return None
elif language == 'ngerman':
return 'spelling=new'
elif language == 'german':
return 'spelling=old'
else:
return None
class Table(object):
@ -618,9 +529,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
if builder.config.language \
and 'fncychap' not in builder.config.latex_elements:
# use Sonny style if any language specified
self.elements['fncychap'] = '\\usepackage[Sonny]{fncychap}'
self.elements['fncychap'] = ('\\usepackage[Sonny]{fncychap}\n'
'\\ChNameVar{\\Large\\normalfont'
'\\sffamily}\n\\ChTitleVar{\\Large'
'\\normalfont\\sffamily}')
self.babel = ExtBabel(builder.config.language)
self.babel = ExtBabel(builder.config.language,
not self.elements['babel'])
if builder.config.language and not self.babel.is_supported_language():
# emit warning if specified language is invalid
# (only emitting, nothing changed to processing)
@ -654,8 +569,15 @@ class LaTeXTranslator(nodes.NodeVisitor):
# disable fncychap in Japanese documents
self.elements['fncychap'] = ''
elif self.elements['polyglossia']:
self.elements['multilingual'] = '%s\n\\setmainlanguage{%s}' % \
(self.elements['polyglossia'], self.babel.get_language())
options = self.babel.get_mainlanguage_options()
if options:
mainlanguage = r'\setmainlanguage[%s]{%s}' % (options,
self.babel.get_language())
else:
mainlanguage = r'\setmainlanguage{%s}' % self.babel.get_language()
self.elements['multilingual'] = '%s\n%s' % (self.elements['polyglossia'],
mainlanguage)
if getattr(builder, 'usepackages', None):
def declare_package(packagename, options=None):
@ -930,8 +852,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
def render(self, template_name, variables):
# type: (unicode, Dict) -> unicode
for template_path in self.builder.config.templates_path:
template = path.join(template_path, template_name)
for template_dir in self.builder.config.templates_path:
template = path.join(self.builder.confdir, template_dir,
template_name)
if path.exists(template):
return LaTeXRenderer().render(template, variables)
@ -2501,14 +2424,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
self.body.append('}}$')
def visit_substitution_definition(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_substitution_reference(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_inline(self, node):
# type: (nodes.Node) -> None
classes = node.get('classes', [])
@ -2634,7 +2549,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
logger.warning(__('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html'),
'described at http://sphinx-doc.org/en/master/ext/math.html'),
location=(self.curfilestack[-1], node.line))
raise nodes.SkipNode

View File

@ -515,7 +515,7 @@ class ManualPageTranslator(BaseTranslator):
# type: (nodes.Node) -> None
logger.warning(__('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html'))
'described at http://sphinx-doc.org/en/master/ext/math.html'))
raise nodes.SkipNode
visit_math_block = visit_math

View File

@ -1385,18 +1385,6 @@ class TexinfoTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
pass
def visit_substitution_reference(self, node):
# type: (nodes.Node) -> None
pass
def depart_substitution_reference(self, node):
# type: (nodes.Node) -> None
pass
def visit_substitution_definition(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_system_message(self, node):
# type: (nodes.Node) -> None
self.body.append('\n@verbatim\n'
@ -1745,7 +1733,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
logger.warning(__('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html'))
'described at http://sphinx-doc.org/en/master/ext/math.html'))
raise nodes.SkipNode
visit_math_block = visit_math

View File

@ -987,10 +987,6 @@ class TextTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_substitution_definition(self, node):
# type: (nodes.Node) -> None
raise nodes.SkipNode
def visit_pending_xref(self, node):
# type: (nodes.Node) -> None
pass
@ -1185,7 +1181,7 @@ class TextTranslator(nodes.NodeVisitor):
# type: (nodes.Node) -> None
logger.warning(__('using "math" markup without a Sphinx math extension '
'active, please use one of the math extensions '
'described at http://sphinx-doc.org/ext/math.html'),
'described at http://sphinx-doc.org/en/master/ext/math.html'),
location=(self.builder.current_docname, node.line))
raise nodes.SkipNode

View File

@ -6,4 +6,6 @@ version = '1.4.4'
html_static_path = ['static', 'subdir']
html_extra_path = ['extra', 'subdir']
html_css_files = ['css/style.css',
('https://example.com/custom.css', {'title': 'title', 'media': 'print'})]
exclude_patterns = ['**/_build', '**/.htpasswd']

View File

@ -4,7 +4,7 @@ References
Translation Tips
-----------------
.. _download Sphinx: https://pypi.python.org/pypi/sphinx
.. _download Sphinx: https://pypi.org/project/Sphinx/
.. _Docutils site: http://docutils.sourceforge.net/
.. _Sphinx site: http://sphinx-doc.org/

View File

@ -0,0 +1 @@
SALUT LES COPAINS

View File

@ -15,7 +15,7 @@ normal order
hyperref <https://sphinx-doc.org/?q=sphinx>
reversed order
-------------
--------------
.. toctree::
:glob:

View File

@ -804,7 +804,7 @@ def test_generate():
' .. py:attribute:: Class._private_inst_attr',
' .. py:classmethod:: Class.inheritedclassmeth()',
' .. py:method:: Class.inheritedmeth()',
' .. py:staticmethod:: Class.inheritedstaticmeth()',
' .. py:staticmethod:: Class.inheritedstaticmeth(cls)',
],
'class', 'Class', member_order='bysource', all_members=True)
del directive.env.ref_context['py:module']
@ -952,7 +952,10 @@ def test_partialmethod():
' Update state of cell to *state*.',
' ',
]
if sys.version_info < (3, 5, 4):
if (sys.version_info < (3, 5, 4) or
(3, 6, 5) <= sys.version_info < (3, 7) or
(3, 7, 0, 'beta', 3) <= sys.version_info):
# TODO: this condition should be updated after 3.7-final release.
expected = '\n'.join(expected).replace(' -> None', '').split('\n')
assert call_autodoc('class', 'target.partialmethod.Cell') == expected

View File

@ -317,6 +317,34 @@ def test_epub_writing_mode(app):
assert 'writing-mode: vertical-rl;' in css
@pytest.mark.sphinx('epub', testroot='html_assets')
def test_epub_assets(app):
app.builder.build_all()
# epub_sytlesheets (same as html_css_files)
content = (app.outdir / 'index.xhtml').text()
assert ('<link rel="stylesheet" type="text/css" href="_static/css/style.css" />'
in content)
assert ('<link media="print" rel="stylesheet" title="title" type="text/css" '
'href="https://example.com/custom.css" />' in content)
@pytest.mark.sphinx('epub', testroot='html_assets',
confoverrides={'epub_css_files': ['css/epub.css']})
def test_epub_css_files(app):
app.builder.build_all()
# epub_css_files
content = (app.outdir / 'index.xhtml').text()
assert '<link rel="stylesheet" type="text/css" href="_static/css/epub.css" />' in content
# files in html_css_files are not outputed
assert ('<link rel="stylesheet" type="text/css" href="_static/css/style.css" />'
not in content)
assert ('<link media="print" rel="stylesheet" title="title" type="text/css" '
'href="https://example.com/custom.css" />' not in content)
@pytest.mark.sphinx('epub')
def test_run_epubcheck(app):
app.build()

View File

@ -1094,9 +1094,10 @@ def test_html_assets(app):
assert not (app.outdir / '_static' / '.htpasswd').exists()
assert (app.outdir / '_static' / 'API.html').exists()
assert (app.outdir / '_static' / 'API.html').text() == 'Sphinx-1.4.4'
assert (app.outdir / '_static' / 'css/style.css').exists()
assert (app.outdir / '_static' / 'css' / 'style.css').exists()
assert (app.outdir / '_static' / 'js' / 'custom.js').exists()
assert (app.outdir / '_static' / 'rimg.png').exists()
assert not (app.outdir / '_static' / '_build/index.html').exists()
assert not (app.outdir / '_static' / '_build' / 'index.html').exists()
assert (app.outdir / '_static' / 'background.png').exists()
assert not (app.outdir / '_static' / 'subdir' / '.htaccess').exists()
assert not (app.outdir / '_static' / 'subdir' / '.htpasswd').exists()
@ -1107,11 +1108,17 @@ def test_html_assets(app):
assert (app.outdir / 'API.html_t').exists()
assert (app.outdir / 'css/style.css').exists()
assert (app.outdir / 'rimg.png').exists()
assert not (app.outdir / '_build/index.html').exists()
assert not (app.outdir / '_build' / 'index.html').exists()
assert (app.outdir / 'background.png').exists()
assert (app.outdir / 'subdir' / '.htaccess').exists()
assert not (app.outdir / 'subdir' / '.htpasswd').exists()
# html_css_files
content = (app.outdir / 'index.html').text()
assert '<link rel="stylesheet" type="text/css" href="_static/css/style.css" />' in content
assert ('<link media="print" rel="stylesheet" title="title" type="text/css" '
'href="https://example.com/custom.css" />' in content)
@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_copy_source': False})
def test_html_copy_source(app):

View File

@ -534,6 +534,50 @@ def test_babel_with_unknown_language(app, status, warning):
assert "WARNING: no Babel option known for language 'unknown'" in warning.getvalue()
@pytest.mark.sphinx(
'latex', testroot='latex-babel',
confoverrides={'language': 'de', 'latex_engine': 'lualatex'})
def test_polyglossia_with_language_de(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\documentclass[letterpaper,10pt,german]{sphinxmanual}' in result
assert '\\usepackage{polyglossia}' in result
assert '\\setmainlanguage[spelling=new]{german}' in result
assert '\\usepackage{times}' not in result
assert '\\usepackage[Sonny]{fncychap}' in result
assert ('\\addto\\captionsgerman{\\renewcommand{\\contentsname}{Table of content}}\n'
in result)
assert '\\addto\\captionsgerman{\\renewcommand{\\figurename}{Fig.}}\n' in result
assert '\\addto\\captionsgerman{\\renewcommand{\\tablename}{Table.}}\n' in result
assert '\\def\\pageautorefname{Seite}\n' in result
assert '\\shorthandoff' not in result
@pytest.mark.sphinx(
'latex', testroot='latex-babel',
confoverrides={'language': 'de-1901', 'latex_engine': 'lualatex'})
def test_polyglossia_with_language_de_1901(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(result)
print(status.getvalue())
print(warning.getvalue())
assert '\\documentclass[letterpaper,10pt,german]{sphinxmanual}' in result
assert '\\usepackage{polyglossia}' in result
assert '\\setmainlanguage[spelling=old]{german}' in result
assert '\\usepackage{times}' not in result
assert '\\usepackage[Sonny]{fncychap}' in result
assert ('\\addto\\captionsgerman{\\renewcommand{\\contentsname}{Table of content}}\n'
in result)
assert '\\addto\\captionsgerman{\\renewcommand{\\figurename}{Fig.}}\n' in result
assert '\\addto\\captionsgerman{\\renewcommand{\\tablename}{Table.}}\n' in result
assert '\\def\\pageautorefname{page}\n' in result
assert '\\shorthandoff' not in result
@pytest.mark.sphinx('latex')
def test_footnote(app, status, warning):
app.builder.build_all()
@ -750,6 +794,15 @@ def test_latex_show_urls_is_no(app, status, warning):
'{sphinx-dev@googlegroups.com}\n') in result
@pytest.mark.sphinx(
'latex', testroot='footnotes',
confoverrides={'latex_show_urls': 'footnote',
'rst_prolog': '.. |URL| replace:: `text <http://www.example.com/>`__'})
def test_latex_show_urls_footnote_and_substitutions(app, status, warning):
# hyperlinks in substitutions should not effect to make footnotes (refs: #4784)
test_latex_show_urls_is_footnote(app, status, warning)
@pytest.mark.sphinx('latex', testroot='image-in-section')
def test_image_in_section(app, status, warning):
app.builder.build_all()
@ -1098,6 +1151,30 @@ def test_latex_table_complex_tables(app, status, warning):
assert actual == expected
@pytest.mark.sphinx('latex', testroot='latex-table',
confoverrides={'templates_path': ['_mytemplates/latex']})
def test_latex_table_custom_template_caseA(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'test.tex').text(encoding='utf8')
assert 'SALUT LES COPAINS' in result
@pytest.mark.sphinx('latex', testroot='latex-table',
confoverrides={'templates_path': ['_mytemplates']})
def test_latex_table_custom_template_caseB(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'test.tex').text(encoding='utf8')
assert 'SALUT LES COPAINS' not in result
@pytest.mark.sphinx('latex', testroot='latex-table')
@pytest.mark.test_params(shared_result='latex-table')
def test_latex_table_custom_template_caseC(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'test.tex').text(encoding='utf8')
assert 'SALUT LES COPAINS' not in result
@pytest.mark.sphinx('latex', testroot='directives-raw')
def test_latex_raw_directive(app, status, warning):
app.builder.build_all()

View File

@ -0,0 +1,153 @@
# -*- coding: utf-8 -*-
"""
test_directive_other
~~~~~~~~~~~~~~~~~~~~
Test the other directives.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import pytest
from docutils import nodes
from docutils.core import publish_doctree
from sphinx import addnodes
from sphinx.io import SphinxStandaloneReader
from sphinx.parsers import RSTParser
from sphinx.testing.util import assert_node
def parse(app, docname, text):
app.env.temp_data['docname'] = docname
return publish_doctree(text, app.srcdir / docname + '.rst',
reader=SphinxStandaloneReader(app),
parser=RSTParser(),
settings_overrides={'env': app.env,
'gettext_compact': True})
@pytest.mark.sphinx(testroot='toctree-glob')
def test_toctree(app):
text = (".. toctree::\n"
"\n"
" foo\n"
" bar/index\n"
" baz\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'foo'), (None, 'bar/index'), (None, 'baz')],
includefiles=['foo', 'bar/index', 'baz'])
@pytest.mark.sphinx(testroot='toctree-glob')
def test_relative_toctree(app):
text = (".. toctree::\n"
"\n"
" bar_1\n"
" bar_2\n"
" bar_3\n"
" ../quux\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'bar/index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'bar/bar_1'), (None, 'bar/bar_2'), (None, 'bar/bar_3'),
(None, 'quux')],
includefiles=['bar/bar_1', 'bar/bar_2', 'bar/bar_3', 'quux'])
@pytest.mark.sphinx(testroot='toctree-glob')
def test_toctree_urls_and_titles(app):
text = (".. toctree::\n"
"\n"
" Sphinx <https://www.sphinx-doc.org/>\n"
" https://readthedocs.org/\n"
" The BAR <bar/index>\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[('Sphinx', 'https://www.sphinx-doc.org/'),
(None, 'https://readthedocs.org/'),
('The BAR', 'bar/index')],
includefiles=['bar/index'])
@pytest.mark.sphinx(testroot='toctree-glob')
def test_toctree_glob(app):
text = (".. toctree::\n"
" :glob:\n"
"\n"
" *\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'baz'), (None, 'foo'), (None, 'quux')],
includefiles=['baz', 'foo', 'quux'])
# give both docname and glob (case1)
text = (".. toctree::\n"
" :glob:\n"
"\n"
" foo\n"
" *\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'foo'), (None, 'baz'), (None, 'quux')],
includefiles=['foo', 'baz', 'quux'])
# give both docname and glob (case2)
text = (".. toctree::\n"
" :glob:\n"
"\n"
" *\n"
" foo\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'baz'), (None, 'foo'), (None, 'quux'), (None, 'foo')],
includefiles=['baz', 'foo', 'quux', 'foo'])
@pytest.mark.sphinx(testroot='toctree-glob')
def test_toctree_glob_and_url(app):
text = (".. toctree::\n"
" :glob:\n"
"\n"
" https://example.com/?q=sphinx\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'https://example.com/?q=sphinx')],
includefiles=[])
@pytest.mark.sphinx(testroot='toctree-glob')
def test_toctree_twice(app):
text = (".. toctree::\n"
"\n"
" foo\n"
" foo\n")
app.env.find_files(app.config, app.builder)
doctree = parse(app, 'index', text)
assert_node(doctree, [nodes.document, nodes.compound, addnodes.toctree])
assert_node(doctree[0][0],
entries=[(None, 'foo'), (None, 'foo')],
includefiles=['foo', 'foo'])

View File

@ -188,6 +188,16 @@ def test_autosummary_generate(app, status, warning):
' \n' in Foo)
@pytest.mark.sphinx('latex', **default_kw)
def test_autosummary_latex_table_colspec(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'Python.tex').text(encoding='utf8')
print(status.getvalue())
print(warning.getvalue())
assert r'\begin{longtable}{\X{1}{2}\X{1}{2}}' in result
assert r'p{0.5\linewidth}' not in result
def test_import_by_name():
import sphinx
import sphinx.ext.autosummary

View File

@ -35,19 +35,19 @@ def test_jsmath(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'math.html').text()
assert '<div class="math notranslate">\na^2 + b^2 = c^2</div>' in content
assert ('<div class="math notranslate">\n\\begin{split}a + 1 &lt; b\\end{split}</div>'
in content)
assert '<div class="math notranslate nohighlight">\na^2 + b^2 = c^2</div>' in content
assert ('<div class="math notranslate nohighlight">\n\\begin{split}a + 1 &lt; '
'b\\end{split}</div>' in content)
assert (u'<span class="eqno">(1)<a class="headerlink" href="#equation-foo" '
u'title="Permalink to this equation">\xb6</a></span>'
u'<div class="math notranslate" id="equation-foo">\ne^{i\\pi} = 1</div>'
in content)
u'<div class="math notranslate nohighlight" id="equation-foo">'
'\ne^{i\\pi} = 1</div>' in content)
assert (u'<span class="eqno">(2)<a class="headerlink" href="#equation-math-0" '
u'title="Permalink to this equation">\xb6</a></span>'
u'<div class="math notranslate" id="equation-math-0">\n'
u'<div class="math notranslate nohighlight" id="equation-math-0">\n'
u'e^{ix} = \\cos x + i\\sin x</div>' in content)
assert '<div class="math notranslate">\nn \\in \\mathbb N</div>' in content
assert '<div class="math notranslate">\na + 1 &lt; b</div>' in content
assert '<div class="math notranslate nohighlight">\nn \\in \\mathbb N</div>' in content
assert '<div class="math notranslate nohighlight">\na + 1 &lt; b</div>' in content
@pytest.mark.skipif(not has_binary('dvipng'),
@ -91,7 +91,7 @@ def test_mathjax_align(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').text()
html = (r'<div class="math notranslate">\s*'
html = (r'<div class="math notranslate nohighlight">\s*'
r'\\\[ \\begin\{align\}\\begin\{aligned\}S \&amp;= \\pi r\^2\\\\'
r'V \&amp;= \\frac\{4\}\{3\} \\pi r\^3\\end\{aligned\}\\end\{align\} \\\]</div>')
assert re.search(html, content, re.S)
@ -104,7 +104,7 @@ def test_math_number_all_mathjax(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'index.html').text()
html = (r'<div class="math notranslate" id="equation-index-0">\s*'
html = (r'<div class="math notranslate nohighlight" id="equation-index-0">\s*'
r'<span class="eqno">\(1\)<a .*>\xb6</a></span>\\\[a\^2\+b\^2=c\^2\\\]</div>')
assert re.search(html, content, re.S)
@ -169,7 +169,7 @@ def test_mathjax_numfig_html(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'math.html').text()
html = ('<div class="math notranslate" id="equation-math-0">\n'
html = ('<div class="math notranslate nohighlight" id="equation-math-0">\n'
'<span class="eqno">(1.2)')
assert html in content
html = ('<p>Referencing equation <a class="reference internal" '

View File

@ -9,6 +9,8 @@
:license: BSD, see LICENSE for details.
"""
import sys
import pytest
from six import PY2
@ -94,6 +96,18 @@ def test_comment_picker_location():
('Foo', 'attr3'): 'comment for attr3(3)'}
@pytest.mark.skipif(sys.version_info < (3, 6), reason='tests for py36+ syntax')
def test_annotated_assignment_py36():
source = ('a: str = "Sphinx" #: comment\n'
'b: int = 1\n'
'"""string on next line"""')
parser = Parser(source)
parser.parse()
assert parser.comments == {('', 'a'): 'comment',
('', 'b'): 'string on next line'}
assert parser.definitions == {}
def test_complex_assignment():
source = ('a = 1 + 1; b = a #: compound statement\n'
'c, d = (1, 1) #: unpack assignment\n'

View File

@ -346,6 +346,24 @@ def test_dictionary_sorting():
assert description == "{'a': 1, 'b': 4, 'c': 3, 'd': 2}"
def test_set_sorting():
set_ = set("gfedcba")
description = inspect.object_description(set_)
if PY3:
assert description == "{'a', 'b', 'c', 'd', 'e', 'f', 'g'}"
else:
assert description == "set(['a', 'b', 'c', 'd', 'e', 'f', 'g'])"
def test_set_sorting_fallback():
set_ = set((None, 1))
description = inspect.object_description(set_)
if PY3:
assert description in ("{1, None}", "{None, 1}")
else:
assert description in ("set([1, None])", "set([None, 1])")
def test_dict_customtype():
class CustomType(object):
def __init__(self, value):

View File

@ -12,7 +12,7 @@ for stable releases
* ``git commit -am 'Bump to X.Y.Z final'``
* ``make clean``
* ``python setup.py release bdist_wheel sdist upload --identity=[your key]``
* open https://pypi.python.org/pypi/Sphinx and check there are no obvious errors
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
* ``git tag vX.Y.Z``
* ``python utils/bump_version.py --in-develop X.Y.Zb0`` (ex. 1.5.3b0)
* Check diff by ``git diff``
@ -38,7 +38,7 @@ for first beta releases
* ``git commit -am 'Bump to X.Y.0 beta1'``
* ``make clean``
* ``python setup.py release bdist_wheel sdist upload --identity=[your key]``
* open https://pypi.python.org/pypi/Sphinx and check there are no obvious errors
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
* ``git tag vX.Y.0b1``
* ``python utils/bump_version.py --in-develop X.Y.0b2`` (ex. 1.6.0b2)
* Check diff by ``git diff``
@ -67,7 +67,7 @@ for other beta releases
* ``git commit -am 'Bump to X.Y.0 betaN'``
* ``make clean``
* ``python setup.py release bdist_wheel sdist upload --identity=[your key]``
* open https://pypi.python.org/pypi/Sphinx and check there are no obvious errors
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
* ``git tag vX.Y.0bN``
* ``python utils/bump_version.py --in-develop X.Y.0bM`` (ex. 1.6.0b3)
* Check diff by `git diff``
@ -95,7 +95,7 @@ for major releases
* ``git commit -am 'Bump to X.Y.0 final'``
* ``make clean``
* ``python setup.py release bdist_wheel sdist upload --identity=[your key]``
* open https://pypi.python.org/pypi/Sphinx and check there are no obvious errors
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
* ``git tag vX.Y.0``
* ``python utils/bump_version.py --in-develop X.Y.1b0`` (ex. 1.6.1b0)
* Check diff by ``git diff``