mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge remote-tracking branch 'upstream/master'
Conflicts: tests/test_build_html.py
This commit is contained in:
commit
1cfed262d2
@ -42,6 +42,7 @@ addons:
|
||||
- texlive-luatex
|
||||
- texlive-xetex
|
||||
- lmodern
|
||||
- latex-xcolor
|
||||
install:
|
||||
- pip install -U pip setuptools
|
||||
- pip install docutils==$DOCUTILS
|
||||
|
77
CHANGES
77
CHANGES
@ -1,6 +1,15 @@
|
||||
Release 1.6 (in development)
|
||||
============================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* (updated) latex output is tested with Ubuntu trusty's texlive packages (Feb.
|
||||
2014) and earlier tex installations may not be fully compliant, particularly
|
||||
regarding Unicode engines xelatex and lualatex
|
||||
* (added) latexmk is requirement for ``make latexpdf`` on Unix-like platforms
|
||||
(refs: #3082)
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
@ -18,14 +27,21 @@ Incompatible changes
|
||||
relative (refs #3412)
|
||||
* ``literalinclude`` directive does not allow the combination of ``:diff:``
|
||||
option and other options (refs: #3416)
|
||||
* Default config for LuaLaTeX engine uses ``fontspec`` hence needs TeXLive 2013
|
||||
or more recent TeX installation for compatibility. This also means that the
|
||||
fonts used by default have changed to the defaults as chosen by ``fontspec``.
|
||||
(refs #3070, #3466)
|
||||
* LuaLaTeX engine uses ``fontspec`` like XeLaTeX. It is advised ``latex_engine
|
||||
= 'lualatex'`` be used only on up-to-date TeX installs (refs #3070, #3466)
|
||||
* :confval:`latex_keep_old_macro_names` default value has been changed from
|
||||
``True`` to ``False``. This means that some LaTeX macros for styling are
|
||||
by default defined only with ``\sphinx..`` prefixed names. (refs: #3429)
|
||||
* Footer "Continued on next page" of LaTeX longtable's now not framed (refs: #3497)
|
||||
* #3529: The arguments of ``BuildEnvironment.__init__`` is changed
|
||||
* #3082: Use latexmk for pdf (and dvi) targets (Unix-like platforms only)
|
||||
* latex made available (non documented) colour macros from a file distributed
|
||||
with pdftex engine for Plain TeX. This is removed in order to provide better
|
||||
support for multiple TeX engines. Only interface from ``color`` or
|
||||
``xcolor`` packages should be used by extensions of Sphinx latex writer.
|
||||
(refs #3550)
|
||||
* ``Builder.env`` is not filled at instantiation
|
||||
* #3594: LaTeX: single raw directive has been considered as block level element
|
||||
|
||||
Features removed
|
||||
----------------
|
||||
@ -80,6 +96,13 @@ Features added
|
||||
as do normal cells (refs: #3435)
|
||||
* HTML buildre uses experimental HTML5 writer if ``html_experimental_html5_builder`` is True
|
||||
and docutils 0.13 and newer is installed.
|
||||
* LaTeX macros to customize space before and after tables in PDF output (refs #3504)
|
||||
* #3348: Show decorators in literalinclude and viewcode directives
|
||||
* #3108: Show warning if :start-at: and other literalinclude options does not
|
||||
match to the text
|
||||
* #3609: Allow to suppress "duplicate citation" warnings using
|
||||
``suppress_warnings``
|
||||
* #2803: Discovery of builders by entry point
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
@ -87,6 +110,13 @@ Bugs fixed
|
||||
* ``literalinclude`` directive expands tabs after dedent-ing (refs: #3416)
|
||||
* #1574: Paragraphs in table cell doesn't work in Latex output
|
||||
* #3288: Table with merged headers not wrapping text
|
||||
* #3491: Inconsistent vertical space around table and longtable in PDF
|
||||
* #3506: Depart functions for all admonitions in HTML writer now properly pass ``node`` to ``depart_admonition``.
|
||||
* #2693: Sphinx latex style file wrongly inhibits colours for section headings
|
||||
for latex+dvi(ps,pdf,pdfmx)
|
||||
* C++, properly look up ``any`` references.
|
||||
* #3624: sphinx.ext.intersphinx couldn't load inventories compressed with gzip
|
||||
* #3551: PDF information dictionary is lacking author and title data
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
@ -116,8 +146,9 @@ Deprecated
|
||||
* #3429: deprecate config setting ``latex_keep_old_macro_names``. It will be
|
||||
removed at 1.7, and already its default value has changed from ``True`` to
|
||||
``False``.
|
||||
* #3221: epub2 builder is deprecated
|
||||
|
||||
Release 1.5.4 (in development)
|
||||
Release 1.5.6 (in development)
|
||||
==============================
|
||||
|
||||
Incompatible changes
|
||||
@ -129,6 +160,27 @@ Deprecated
|
||||
Features added
|
||||
--------------
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 1.5.5 (released Apr 03, 2017)
|
||||
=====================================
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #3597: python domain raises UnboundLocalError if invalid name given
|
||||
* #3599: Move to new Mathjax CDN
|
||||
|
||||
Release 1.5.4 (released Apr 02, 2017)
|
||||
=====================================
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #3470: Make genindex support all kinds of letters, not only Latin ones
|
||||
|
||||
Bugs fixed
|
||||
@ -144,9 +196,17 @@ Bugs fixed
|
||||
are same without creation date. Thanks to Yoshiki Shibukawa.
|
||||
* #3487: intersphinx: failed to refer options
|
||||
* #3496: latex longtable's last column may be much wider than its contents
|
||||
|
||||
Testing
|
||||
--------
|
||||
* #3507: wrong quotes in latex output for productionlist directive
|
||||
* #3533: Moving from Sphinx 1.3.1 to 1.5.3 breaks LaTeX compilation of links
|
||||
rendered as code
|
||||
* #2665, #2607: Link names in C++ docfields, and make it possible for other domains.
|
||||
* #3542: C++, fix parsing error of non-type template argument with template.
|
||||
* #3065, #3520: python domain fails to recognize nested class
|
||||
* #3575: Problems with pdflatex in a Turkish document built with sphinx has
|
||||
reappeared (refs #2997, #2397)
|
||||
* #3577: Fix intersphinx debug tool
|
||||
* A LaTeX command such as ``\\large`` inserted in the title items of
|
||||
:confval:`latex_documents` causes failed PDF build (refs #3551, #3567)
|
||||
|
||||
Release 1.5.3 (released Feb 26, 2017)
|
||||
=====================================
|
||||
@ -181,6 +241,7 @@ Bugs fixed
|
||||
* #3450:   is appeared in EPUB docs
|
||||
* #3418: Search button is misaligned in nature and pyramid theme
|
||||
* #3421: Could not translate a caption of tables
|
||||
* #3552: linkcheck raises UnboundLocalError
|
||||
|
||||
Release 1.5.2 (released Jan 22, 2017)
|
||||
=====================================
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. highlight:: console
|
||||
|
||||
Sphinx Developer's Guide
|
||||
========================
|
||||
|
||||
@ -127,6 +129,11 @@ These are the basic steps needed to start developing on Sphinx.
|
||||
cd doc
|
||||
make clean html latexpdf
|
||||
|
||||
* Run code style checks and type checks (type checks require mypy)::
|
||||
|
||||
make style-check
|
||||
make type-check
|
||||
|
||||
* Run the unit tests under different Python environments using
|
||||
:program:`tox`::
|
||||
|
||||
@ -269,14 +276,12 @@ Debugging Tips
|
||||
* Set the debugging options in the `Docutils configuration file
|
||||
<http://docutils.sourceforge.net/docs/user/config.html>`_.
|
||||
|
||||
* JavaScript stemming algorithms in `sphinx/search/*.py` (except `en.py`) are
|
||||
* JavaScript stemming algorithms in ``sphinx/search/*.py`` (except ``en.py``) are
|
||||
generated by this
|
||||
`modified snowballcode generator <https://github.com/shibukawa/snowball>`_.
|
||||
Generated `JSX <http://jsx.github.io/>`_ files are
|
||||
in `this repository <https://github.com/shibukawa/snowball-stemmer.jsx>`_.
|
||||
You can get the resulting JavaScript files using the following command:
|
||||
|
||||
.. code-block:: bash
|
||||
You can get the resulting JavaScript files using the following command::
|
||||
|
||||
$ npm install
|
||||
$ node_modules/.bin/grunt build # -> dest/*.global.js
|
||||
|
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
||||
License for Sphinx
|
||||
==================
|
||||
|
||||
Copyright (c) 2007-2016 by the Sphinx team (see AUTHORS file).
|
||||
Copyright (c) 2007-2017 by the Sphinx team (see AUTHORS file).
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
2
doc/_themes/sphinx13/layout.html
vendored
2
doc/_themes/sphinx13/layout.html
vendored
@ -4,7 +4,7 @@
|
||||
|
||||
Sphinx layout template for the sphinxdoc theme.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- extends "basic/layout.html" %}
|
||||
|
2
doc/_themes/sphinx13/static/sphinx13.css
vendored
2
doc/_themes/sphinx13/static/sphinx13.css
vendored
@ -4,7 +4,7 @@
|
||||
*
|
||||
* Sphinx stylesheet -- sphinx13 theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
* :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
@ -178,28 +178,29 @@ The builder's "name" must be given to the **-b** command-line option of
|
||||
.. note::
|
||||
|
||||
The produced LaTeX file uses several LaTeX packages that may not be
|
||||
present in a "minimal" TeX distribution installation. For TeXLive,
|
||||
the following packages need to be installed:
|
||||
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``)
|
||||
|
||||
You may also need latex-xcolor, but Sphinx does not require it (and
|
||||
recent distributions have ``xcolor.sty`` included in latex-recommended).
|
||||
|
||||
Unicode engines will need their respective packages texlive-luatex or
|
||||
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
|
||||
texlive packages. They are from a `TeXLive 2013 snapshot dated
|
||||
20140215`__.
|
||||
mentioned packages, which are from a TeXLive 2013 snapshot dated
|
||||
February 2014.
|
||||
|
||||
__ http://packages.ubuntu.com/trusty/texlive-latex-recommended
|
||||
|
||||
.. versionchanged::
|
||||
1.6 Formerly, testing was done for some years on Ubuntu precise
|
||||
.. versionchanged:: 1.6
|
||||
Formerly, testing had been done for some years on Ubuntu precise
|
||||
(based on TeXLive 2009).
|
||||
.. versionchanged:: 1.6
|
||||
Use of ``latexmk`` on GNU/Linux or Mac OS X.
|
||||
|
||||
.. autoattribute:: name
|
||||
|
||||
|
@ -15,7 +15,7 @@ templates_path = ['_templates']
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
project = 'Sphinx'
|
||||
copyright = '2007-2016, Georg Brandl and the Sphinx team'
|
||||
copyright = '2007-2017, Georg Brandl and the Sphinx team'
|
||||
version = sphinx.__released__
|
||||
release = version
|
||||
show_authors = True
|
||||
|
@ -76,9 +76,10 @@ directive name.
|
||||
|
||||
.. rubric:: Default Domain
|
||||
|
||||
To avoid having to writing the domain name all the time when you e.g. only
|
||||
describe Python objects, a default domain can be selected with either the config
|
||||
value :confval:`primary_domain` or this directive:
|
||||
For documentation describing objects from solely one domain, authors will not
|
||||
have to state again its name at each directive, role, etc... after
|
||||
having specified a default. This can be done either via the config
|
||||
value :confval:`primary_domain` or via this directive:
|
||||
|
||||
.. rst:directive:: .. default-domain:: name
|
||||
|
||||
@ -1103,6 +1104,22 @@ The JavaScript Domain
|
||||
|
||||
The JavaScript domain (name **js**) provides the following directives:
|
||||
|
||||
.. rst:directive:: .. js:module:: name
|
||||
|
||||
This directive sets the module name for object declarations that follow
|
||||
after. The module name is used in the global module index and in cross
|
||||
references. This directive does not create an object heading like
|
||||
:rst:dir:`py:class` would, for example.
|
||||
|
||||
By default, this directive will create a linkable entity and will cause an
|
||||
entry in the global module index, unless the ``noindex`` option is specified.
|
||||
If this option is specified, the directive will only update the current
|
||||
module name.
|
||||
|
||||
To clear the current module, set the module name to ``null`` or ``None``
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
.. rst:directive:: .. js:function:: name(signature)
|
||||
|
||||
Describes a JavaScript function or method. If you want to describe
|
||||
@ -1135,6 +1152,13 @@ The JavaScript domain (name **js**) provides the following directives:
|
||||
:throws SomeError: For whatever reason in that case.
|
||||
:returns: Something.
|
||||
|
||||
.. rst:directive:: .. js:method:: name(signature)
|
||||
|
||||
This directive is an alias for :rst:dir:`js:function`, however it describes a
|
||||
function that is implemented as a method on a class object.
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
.. rst:directive:: .. js:class:: name
|
||||
|
||||
Describes a constructor that creates an object. This is basically like
|
||||
@ -1164,7 +1188,9 @@ The JavaScript domain (name **js**) provides the following directives:
|
||||
|
||||
These roles are provided to refer to the described objects:
|
||||
|
||||
.. rst:role:: js:func
|
||||
.. rst:role:: js:mod
|
||||
js:func
|
||||
js:meth
|
||||
js:class
|
||||
js:data
|
||||
js:attr
|
||||
|
@ -158,7 +158,7 @@ is not supported.)
|
||||
may indicate that it's a better idea to write custom narrative documentation
|
||||
instead.
|
||||
|
||||
Autosummary uses the following template files:
|
||||
Autosummary uses the following Jinja template files:
|
||||
|
||||
- :file:`autosummary/base.rst` -- fallback template
|
||||
- :file:`autosummary/module.rst` -- template for modules
|
||||
@ -194,7 +194,8 @@ The following variables available in the templates:
|
||||
|
||||
.. data:: underline
|
||||
|
||||
A string containing ``len(full_name) * '='``.
|
||||
A string containing ``len(full_name) * '='``. Use the ``underline`` filter
|
||||
instead.
|
||||
|
||||
.. data:: members
|
||||
|
||||
@ -227,7 +228,25 @@ The following variables available in the templates:
|
||||
List containing names of "public" attributes in the class. Only available
|
||||
for classes.
|
||||
|
||||
|
||||
Additionally, the following filters are available
|
||||
|
||||
.. function:: escape(s)
|
||||
|
||||
Escape any special characters in the text to be used in formatting RST
|
||||
contexts. For instance, this prevents asterisks making things bolt. This
|
||||
replaces the builtin Jinja `escape filter`_ that does html-escaping.
|
||||
|
||||
.. function:: underline(s, line='=')
|
||||
|
||||
Add a title underline to a piece of text.
|
||||
|
||||
For instance, ``{{ fullname | escape | underline }}`` should be used to produce
|
||||
the title of a page.
|
||||
|
||||
.. note::
|
||||
|
||||
You can use the :rst:dir:`autosummary` directive in the stub pages.
|
||||
Stub pages are generated also based on these directives.
|
||||
|
||||
.. _`escape filter`: http://jinja.pocoo.org/docs/2.9/templates/#escape
|
||||
|
@ -288,6 +288,11 @@ package.
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to the list
|
||||
of transforms that are applied after Sphinx parses a reST document.
|
||||
|
||||
.. method:: Sphinx.add_post_transform(transform)
|
||||
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to the list
|
||||
of transforms that are applied before Sphinx writes a document.
|
||||
|
||||
.. method:: Sphinx.add_javascript(filename)
|
||||
|
||||
Add *filename* to the list of JavaScript files that the default HTML template
|
||||
|
@ -11,6 +11,12 @@ Builder API
|
||||
|
||||
This is the base class for all builders.
|
||||
|
||||
These attributes should be set on builder classes:
|
||||
|
||||
.. autoattribute:: name
|
||||
.. autoattribute:: format
|
||||
.. autoattribute:: supported_image_types
|
||||
|
||||
These methods are predefined and will be called from the application:
|
||||
|
||||
.. automethod:: get_relative_uri
|
||||
|
@ -22,6 +22,36 @@ The configuration file itself can be treated as an extension if it contains a
|
||||
``setup()`` function. All other extensions to load must be listed in the
|
||||
:confval:`extensions` configuration value.
|
||||
|
||||
Discovery of builders by entry point
|
||||
------------------------------------
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
:term:`Builder` extensions can be discovered by means of `entry points`_ so
|
||||
that they do not have to be listed in the :confval:`extensions` configuration
|
||||
value.
|
||||
|
||||
Builder extensions should define an entry point in the ``sphinx.builders``
|
||||
group. The name of the entry point needs to match your builder's
|
||||
:attr:`~.Builder.name` attribute, which is the name passed to the
|
||||
:option:`sphinx-build -b` option. The entry point value should equal the
|
||||
dotted name of the extension module. Here is an example of how an entry point
|
||||
for 'mybuilder' can be defined in the extension's ``setup.py``::
|
||||
|
||||
setup(
|
||||
# ...
|
||||
entry_points={
|
||||
'sphinx.builders': [
|
||||
'mybuilder = my.extension.module',
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
Note that it is still necessary to register the builder using
|
||||
:meth:`~.Sphinx.add_builder` in the extension's :func:`setup` function.
|
||||
|
||||
.. _entry points: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins
|
||||
|
||||
Extension metadata
|
||||
------------------
|
||||
|
||||
|
@ -98,8 +98,9 @@ in which a Sphinx project is built: this works in several phases.
|
||||
|
||||
Now that the metadata and cross-reference data of all existing documents is
|
||||
known, all temporary nodes are replaced by nodes that can be converted into
|
||||
output. For example, links are created for object references that exist, and
|
||||
simple literal nodes are created for those that don't.
|
||||
output using components called tranform. For example, links are created for
|
||||
object references that exist, and simple literal nodes are created for those
|
||||
that don't.
|
||||
|
||||
**Phase 4: Writing**
|
||||
|
||||
|
@ -201,6 +201,11 @@ Including content based on tags
|
||||
.. versionchanged:: 1.2
|
||||
Added the name of the builder and the prefixes.
|
||||
|
||||
.. warning::
|
||||
|
||||
This directive is designed to control only content of document. It could
|
||||
not control sections, labels and so on.
|
||||
|
||||
|
||||
Tables
|
||||
------
|
||||
|
@ -3,7 +3,7 @@ tag_build = .dev
|
||||
tag_date = true
|
||||
|
||||
[aliases]
|
||||
release = egg_info -RDb ''
|
||||
release = egg_info -Db ''
|
||||
upload = upload --sign --identity=36580288
|
||||
|
||||
[extract_messages]
|
||||
|
1
setup.py
1
setup.py
@ -52,6 +52,7 @@ requires = [
|
||||
'imagesize',
|
||||
'requests>=2.0.0',
|
||||
'typing',
|
||||
'setuptools',
|
||||
]
|
||||
extras_require = {
|
||||
# Environment Marker works for wheel 0.24 or later
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
Sphinx - Python documentation toolchain
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The Sphinx documentation toolchain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The Sphinx documentation toolchain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import sys
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Additional docutils nodes.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
Copyright 2008 Société des arts technologiques (SAT),
|
||||
http://www.sat.qc.ca/
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
@ -23,9 +23,10 @@ from os import path
|
||||
from six import binary_type
|
||||
from fnmatch import fnmatch
|
||||
|
||||
from sphinx.util.osutil import FileAvoidWrite, walk
|
||||
from sphinx import __display_version__
|
||||
from sphinx.quickstart import EXTENSIONS
|
||||
from sphinx.util import rst
|
||||
from sphinx.util.osutil import FileAvoidWrite, walk
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -74,9 +75,11 @@ def write_file(name, text, opts):
|
||||
f.write(text)
|
||||
|
||||
|
||||
def format_heading(level, text):
|
||||
# type: (int, unicode) -> unicode
|
||||
def format_heading(level, text, escape=True):
|
||||
# type: (int, unicode, bool) -> unicode
|
||||
"""Create a heading of <level> [1, 2 or 3 supported]."""
|
||||
if escape:
|
||||
text = rst.escape(text)
|
||||
underlining = ['=', '-', '~', ][level - 1] * len(text)
|
||||
return '%s\n%s\n\n' % (text, underlining)
|
||||
|
||||
@ -161,7 +164,7 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_
|
||||
def create_modules_toc_file(modules, opts, name='modules'):
|
||||
# type: (List[unicode], Any, unicode) -> None
|
||||
"""Create the module's index."""
|
||||
text = format_heading(1, '%s' % opts.header)
|
||||
text = format_heading(1, '%s' % opts.header, escape=False)
|
||||
text += '.. toctree::\n'
|
||||
text += ' :maxdepth: %s\n\n' % opts.maxdepth
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
Gracefully adapted from the TextPress system by Armin.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
@ -17,16 +17,16 @@ import sys
|
||||
import types
|
||||
import warnings
|
||||
import posixpath
|
||||
import traceback
|
||||
from os import path
|
||||
from collections import deque
|
||||
|
||||
from six import iteritems, itervalues
|
||||
from six import iteritems
|
||||
from six.moves import cStringIO
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import convert_directive_function, \
|
||||
directives, roles
|
||||
from pkg_resources import iter_entry_points
|
||||
|
||||
import sphinx
|
||||
from sphinx import package_dir, locale
|
||||
@ -37,7 +37,10 @@ from sphinx.domains import ObjType
|
||||
from sphinx.domains.std import GenericObject, Target, StandardDomain
|
||||
from sphinx.deprecation import RemovedInSphinx17Warning, RemovedInSphinx20Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.events import EventManager
|
||||
from sphinx.extension import load_extension, verify_required_extensions
|
||||
from sphinx.io import SphinxStandaloneReader
|
||||
from sphinx.locale import _
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.util import pycompat # noqa: F401
|
||||
from sphinx.util import import_object
|
||||
@ -57,24 +60,8 @@ if False:
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.domains import Domain, Index # NOQA
|
||||
from sphinx.environment.collectors import EnvironmentCollector # NOQA
|
||||
from sphinx.extension import Extension # NOQA
|
||||
|
||||
# List of all known core events. Maps name to arguments description.
|
||||
events = {
|
||||
'builder-inited': '',
|
||||
'env-get-outdated': 'env, added, changed, removed',
|
||||
'env-get-updated': 'env',
|
||||
'env-purge-doc': 'env, docname',
|
||||
'env-before-read-docs': 'env, docnames',
|
||||
'source-read': 'docname, source text',
|
||||
'doctree-read': 'the doctree before being pickled',
|
||||
'env-merge-info': 'env, read docnames, other env instance',
|
||||
'missing-reference': 'env, node, contnode',
|
||||
'doctree-resolved': 'doctree, docname',
|
||||
'env-updated': 'env',
|
||||
'html-collect-pages': 'builder',
|
||||
'html-page-context': 'pagename, context, doctree or None',
|
||||
'build-finished': 'exception',
|
||||
} # type: Dict[unicode, unicode]
|
||||
builtin_extensions = (
|
||||
'sphinx.builders.applehelp',
|
||||
'sphinx.builders.changes',
|
||||
@ -104,6 +91,7 @@ builtin_extensions = (
|
||||
'sphinx.directives.other',
|
||||
'sphinx.directives.patches',
|
||||
'sphinx.roles',
|
||||
'sphinx.transforms.post_transforms',
|
||||
# collectors should be loaded by specific order
|
||||
'sphinx.environment.collectors.dependencies',
|
||||
'sphinx.environment.collectors.asset',
|
||||
@ -111,15 +99,14 @@ builtin_extensions = (
|
||||
'sphinx.environment.collectors.title',
|
||||
'sphinx.environment.collectors.toctree',
|
||||
'sphinx.environment.collectors.indexentries',
|
||||
# Strictly, alabaster theme is not a builtin extension,
|
||||
# but it is loaded automatically to use it as default theme.
|
||||
'alabaster',
|
||||
) # type: Tuple[unicode, ...]
|
||||
|
||||
CONFIG_FILENAME = 'conf.py'
|
||||
ENV_PICKLE_FILENAME = 'environment.pickle'
|
||||
|
||||
# list of deprecated extensions. Keys are extension name.
|
||||
# Values are Sphinx version that merge the extension.
|
||||
EXTENSION_BLACKLIST = {"sphinxjp.themecore": "1.2"} # type: Dict[unicode, unicode]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -131,18 +118,15 @@ class Sphinx(object):
|
||||
parallel=0):
|
||||
# type: (unicode, unicode, unicode, unicode, unicode, Dict, IO, IO, bool, bool, List[unicode], int, int) -> None # NOQA
|
||||
self.verbosity = verbosity
|
||||
self.next_listener_id = 0
|
||||
self._extensions = {} # type: Dict[unicode, Any]
|
||||
self._extension_metadata = {} # type: Dict[unicode, Dict[unicode, Any]]
|
||||
self.extensions = {} # type: Dict[unicode, Extension]
|
||||
self._additional_source_parsers = {} # type: Dict[unicode, Parser]
|
||||
self._listeners = {} # type: Dict[unicode, Dict[int, Callable]]
|
||||
self._setting_up_extension = ['?'] # type: List[unicode]
|
||||
self.domains = {} # type: Dict[unicode, Type[Domain]]
|
||||
self.buildername = buildername
|
||||
self.builderclasses = {} # type: Dict[unicode, Type[Builder]]
|
||||
self.builder = None # type: Builder
|
||||
self.env = None # type: BuildEnvironment
|
||||
self.enumerable_nodes = {} # type: Dict[nodes.Node, Tuple[unicode, Callable]] # NOQA
|
||||
self.post_transforms = [] # type: List[Transform]
|
||||
|
||||
self.srcdir = srcdir
|
||||
self.confdir = confdir
|
||||
@ -166,10 +150,11 @@ class Sphinx(object):
|
||||
self.warningiserror = warningiserror
|
||||
logging.setup(self, self._status, self._warning)
|
||||
|
||||
self._events = events.copy()
|
||||
self.events = EventManager()
|
||||
self._translators = {} # type: Dict[unicode, nodes.GenericNodeVisitor]
|
||||
|
||||
# keep last few messages for traceback
|
||||
# This will be filled by sphinx.util.logging.LastMessagesWriter
|
||||
self.messagelog = deque(maxlen=10) # type: deque
|
||||
|
||||
# say hello to the world
|
||||
@ -189,14 +174,18 @@ class Sphinx(object):
|
||||
self.config.check_unicode()
|
||||
# defer checking types until i18n has been initialized
|
||||
|
||||
# initialize some limited config variables before loading extensions
|
||||
# initialize some limited config variables before initialize i18n and loading
|
||||
# extensions
|
||||
self.config.pre_init_values()
|
||||
|
||||
# set up translation infrastructure
|
||||
self._init_i18n()
|
||||
|
||||
# check the Sphinx version if requested
|
||||
if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
|
||||
raise VersionRequirementError(
|
||||
'This project needs at least Sphinx v%s and therefore cannot '
|
||||
'be built with this version.' % self.config.needs_sphinx)
|
||||
_('This project needs at least Sphinx v%s and therefore cannot '
|
||||
'be built with this version.') % self.config.needs_sphinx)
|
||||
|
||||
# set confdir to srcdir if -C given (!= no confdir); a few pieces
|
||||
# of code expect a confdir to be set
|
||||
@ -207,12 +196,6 @@ class Sphinx(object):
|
||||
for extension in builtin_extensions:
|
||||
self.setup_extension(extension)
|
||||
|
||||
# extension loading support for alabaster theme
|
||||
# self.config.html_theme is not set from conf.py at here
|
||||
# for now, sphinx always load a 'alabaster' extension.
|
||||
if 'alabaster' not in self.config.extensions:
|
||||
self.config.extensions.append('alabaster')
|
||||
|
||||
# load all user-given extension modules
|
||||
for extension in self.config.extensions:
|
||||
self.setup_extension(extension)
|
||||
@ -224,35 +207,24 @@ class Sphinx(object):
|
||||
self.config.setup(self)
|
||||
else:
|
||||
raise ConfigError(
|
||||
"'setup' that is specified in the conf.py has not been " +
|
||||
"callable. Please provide a callable `setup` function " +
|
||||
"in order to behave as a sphinx extension conf.py itself."
|
||||
_("'setup' that is specified in the conf.py has not been "
|
||||
"callable. Please provide a callable `setup` function "
|
||||
"in order to behave as a sphinx extension conf.py itself.")
|
||||
)
|
||||
|
||||
# now that we know all config values, collect them from conf.py
|
||||
self.config.init_values()
|
||||
|
||||
# check extension versions if requested
|
||||
if self.config.needs_extensions:
|
||||
for extname, needs_ver in self.config.needs_extensions.items():
|
||||
if extname not in self._extensions:
|
||||
logger.warning('needs_extensions config value specifies a '
|
||||
'version requirement for extension %s, but it is '
|
||||
'not loaded', extname)
|
||||
continue
|
||||
has_ver = self._extension_metadata[extname]['version']
|
||||
if has_ver == 'unknown version' or needs_ver > has_ver:
|
||||
raise VersionRequirementError(
|
||||
'This project needs the extension %s at least in '
|
||||
'version %s and therefore cannot be built with the '
|
||||
'loaded version (%s).' % (extname, needs_ver, has_ver))
|
||||
verify_required_extensions(self, self.config.needs_extensions)
|
||||
|
||||
# check primary_domain if requested
|
||||
if self.config.primary_domain and self.config.primary_domain not in self.domains:
|
||||
logger.warning('primary_domain %r not found, ignored.', self.config.primary_domain)
|
||||
logger.warning(_('primary_domain %r not found, ignored.'),
|
||||
self.config.primary_domain)
|
||||
|
||||
# set up translation infrastructure
|
||||
self._init_i18n()
|
||||
# create the builder
|
||||
self.builder = self.create_builder(buildername)
|
||||
# check all configuration values for permissible types
|
||||
self.config.check_types()
|
||||
# set up source_parsers
|
||||
@ -260,7 +232,7 @@ class Sphinx(object):
|
||||
# set up the build environment
|
||||
self._init_env(freshenv)
|
||||
# set up the builder
|
||||
self._init_builder(self.buildername)
|
||||
self._init_builder()
|
||||
# set up the enumerable nodes
|
||||
self._init_enumerable_nodes()
|
||||
|
||||
@ -286,7 +258,7 @@ class Sphinx(object):
|
||||
if self.config.language is not None:
|
||||
if has_translation or self.config.language == 'en':
|
||||
# "en" never needs to be translated
|
||||
logger.info('done')
|
||||
logger.info(_('done'))
|
||||
else:
|
||||
logger.info('not available for built-in messages')
|
||||
|
||||
@ -301,37 +273,47 @@ class Sphinx(object):
|
||||
def _init_env(self, freshenv):
|
||||
# type: (bool) -> None
|
||||
if freshenv:
|
||||
self.env = BuildEnvironment(self.srcdir, self.doctreedir, self.config)
|
||||
self.env.find_files(self.config, self.buildername)
|
||||
self.env = BuildEnvironment(self)
|
||||
self.env.find_files(self.config, self.builder)
|
||||
for domain in self.domains.keys():
|
||||
self.env.domains[domain] = self.domains[domain](self.env)
|
||||
else:
|
||||
try:
|
||||
logger.info(bold('loading pickled environment... '), nonl=True)
|
||||
self.env = BuildEnvironment.frompickle(
|
||||
self.srcdir, self.config, path.join(self.doctreedir, ENV_PICKLE_FILENAME))
|
||||
logger.info(bold(_('loading pickled environment... ')), nonl=True)
|
||||
filename = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
|
||||
self.env = BuildEnvironment.frompickle(filename, self)
|
||||
self.env.domains = {}
|
||||
for domain in self.domains.keys():
|
||||
# this can raise if the data version doesn't fit
|
||||
self.env.domains[domain] = self.domains[domain](self.env)
|
||||
logger.info('done')
|
||||
logger.info(_('done'))
|
||||
except Exception as err:
|
||||
if isinstance(err, IOError) and err.errno == ENOENT:
|
||||
logger.info('not yet created')
|
||||
logger.info(_('not yet created'))
|
||||
else:
|
||||
logger.info('failed: %s', err)
|
||||
logger.info(_('failed: %s'), err)
|
||||
self._init_env(freshenv=True)
|
||||
|
||||
def _init_builder(self, buildername):
|
||||
# type: (unicode) -> None
|
||||
def create_builder(self, buildername):
|
||||
# type: (unicode) -> Builder
|
||||
if buildername is None:
|
||||
print('No builder selected, using default: html', file=self._status)
|
||||
logger.info(_('No builder selected, using default: html'))
|
||||
buildername = 'html'
|
||||
if buildername not in self.builderclasses:
|
||||
raise SphinxError('Builder name %s not registered' % buildername)
|
||||
|
||||
entry_points = iter_entry_points('sphinx.builders', buildername)
|
||||
try:
|
||||
entry_point = next(entry_points)
|
||||
except StopIteration:
|
||||
raise SphinxError('Builder name %s not registered or available'
|
||||
' through entry point' % buildername)
|
||||
load_extension(self, entry_point.module_name)
|
||||
builderclass = self.builderclasses[buildername]
|
||||
self.builder = builderclass(self)
|
||||
return builderclass(self)
|
||||
|
||||
def _init_builder(self):
|
||||
# type: () -> None
|
||||
self.builder.set_environment(self.env)
|
||||
self.builder.init()
|
||||
self.emit('builder-inited')
|
||||
|
||||
def _init_enumerable_nodes(self):
|
||||
@ -339,6 +321,13 @@ class Sphinx(object):
|
||||
for node, settings in iteritems(self.enumerable_nodes):
|
||||
self.env.get_domain('std').enumerable_nodes[node] = settings # type: ignore
|
||||
|
||||
@property
|
||||
def buildername(self):
|
||||
# type: () -> unicode
|
||||
warnings.warn('app.buildername is deprecated. Please use app.builder.name instead',
|
||||
RemovedInSphinx17Warning)
|
||||
return self.builder.name
|
||||
|
||||
# ---- main "build" method -------------------------------------------------
|
||||
|
||||
def build(self, force_all=False, filenames=None):
|
||||
@ -355,13 +344,13 @@ class Sphinx(object):
|
||||
self.builder.build_update()
|
||||
|
||||
status = (self.statuscode == 0 and
|
||||
'succeeded' or 'finished with problems')
|
||||
_('succeeded') or _('finished with problems'))
|
||||
if self._warncount:
|
||||
logger.info(bold('build %s, %s warning%s.' %
|
||||
logger.info(bold(_('build %s, %s warning%s.') %
|
||||
(status, self._warncount,
|
||||
self._warncount != 1 and 's' or '')))
|
||||
else:
|
||||
logger.info(bold('build %s.' % status))
|
||||
logger.info(bold(_('build %s.') % status))
|
||||
except Exception as err:
|
||||
# delete the saved env to force a fresh build next time
|
||||
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
|
||||
@ -465,53 +454,11 @@ class Sphinx(object):
|
||||
|
||||
# ---- general extensibility interface -------------------------------------
|
||||
|
||||
def setup_extension(self, extension):
|
||||
def setup_extension(self, extname):
|
||||
# type: (unicode) -> None
|
||||
"""Import and setup a Sphinx extension module. No-op if called twice."""
|
||||
logger.debug('[app] setting up extension: %r', extension)
|
||||
if extension in self._extensions:
|
||||
return
|
||||
if extension in EXTENSION_BLACKLIST:
|
||||
logger.warning('the extension %r was already merged with Sphinx since version %s; '
|
||||
'this extension is ignored.',
|
||||
extension, EXTENSION_BLACKLIST[extension])
|
||||
return
|
||||
self._setting_up_extension.append(extension)
|
||||
try:
|
||||
mod = __import__(extension, None, None, ['setup'])
|
||||
except ImportError as err:
|
||||
logger.verbose('Original exception:\n' + traceback.format_exc())
|
||||
raise ExtensionError('Could not import extension %s' % extension,
|
||||
err)
|
||||
if not hasattr(mod, 'setup'):
|
||||
logger.warning('extension %r has no setup() function; is it really '
|
||||
'a Sphinx extension module?', extension)
|
||||
ext_meta = None
|
||||
else:
|
||||
try:
|
||||
ext_meta = mod.setup(self)
|
||||
except VersionRequirementError as err:
|
||||
# add the extension name to the version required
|
||||
raise VersionRequirementError(
|
||||
'The %s extension used by this project needs at least '
|
||||
'Sphinx v%s; it therefore cannot be built with this '
|
||||
'version.' % (extension, err))
|
||||
if ext_meta is None:
|
||||
ext_meta = {}
|
||||
# special-case for compatibility
|
||||
if extension == 'rst2pdf.pdfbuilder':
|
||||
ext_meta = {'parallel_read_safe': True}
|
||||
try:
|
||||
if not ext_meta.get('version'):
|
||||
ext_meta['version'] = 'unknown version'
|
||||
except Exception:
|
||||
logger.warning('extension %r returned an unsupported object from '
|
||||
'its setup() function; it should return None or a '
|
||||
'metadata dictionary', extension)
|
||||
ext_meta = {'version': 'unknown version'}
|
||||
self._extensions[extension] = mod
|
||||
self._extension_metadata[extension] = ext_meta
|
||||
self._setting_up_extension.pop()
|
||||
logger.debug('[app] setting up extension: %r', extname)
|
||||
load_extension(self, extname)
|
||||
|
||||
def require_sphinx(self, version):
|
||||
# type: (unicode) -> None
|
||||
@ -525,30 +472,16 @@ class Sphinx(object):
|
||||
return import_object(objname, source=None)
|
||||
|
||||
# event interface
|
||||
|
||||
def _validate_event(self, event):
|
||||
# type: (unicode) -> None
|
||||
if event not in self._events:
|
||||
raise ExtensionError('Unknown event name: %s' % event)
|
||||
|
||||
def connect(self, event, callback):
|
||||
# type: (unicode, Callable) -> int
|
||||
self._validate_event(event)
|
||||
listener_id = self.next_listener_id
|
||||
if event not in self._listeners:
|
||||
self._listeners[event] = {listener_id: callback}
|
||||
else:
|
||||
self._listeners[event][listener_id] = callback
|
||||
self.next_listener_id += 1
|
||||
logger.debug('[app] connecting event %r: %r [id=%s]',
|
||||
event, callback, listener_id)
|
||||
listener_id = self.events.connect(event, callback)
|
||||
logger.debug('[app] connecting event %r: %r', event, callback, listener_id)
|
||||
return listener_id
|
||||
|
||||
def disconnect(self, listener_id):
|
||||
# type: (int) -> None
|
||||
logger.debug('[app] disconnecting event: [id=%s]', listener_id)
|
||||
for event in itervalues(self._listeners):
|
||||
event.pop(listener_id, None)
|
||||
self.events.disconnect(listener_id)
|
||||
|
||||
def emit(self, event, *args):
|
||||
# type: (unicode, Any) -> List
|
||||
@ -558,18 +491,11 @@ class Sphinx(object):
|
||||
# not every object likes to be repr()'d (think
|
||||
# random stuff coming via autodoc)
|
||||
pass
|
||||
results = []
|
||||
if event in self._listeners:
|
||||
for _, callback in iteritems(self._listeners[event]):
|
||||
results.append(callback(self, *args))
|
||||
return results
|
||||
return self.events.emit(event, self, *args)
|
||||
|
||||
def emit_firstresult(self, event, *args):
|
||||
# type: (unicode, Any) -> Any
|
||||
for result in self.emit(event, *args):
|
||||
if result is not None:
|
||||
return result
|
||||
return None
|
||||
return self.events.emit_firstresult(event, self, *args)
|
||||
|
||||
# registering addon parts
|
||||
|
||||
@ -577,12 +503,11 @@ class Sphinx(object):
|
||||
# type: (Type[Builder]) -> None
|
||||
logger.debug('[app] adding builder: %r', builder)
|
||||
if not hasattr(builder, 'name'):
|
||||
raise ExtensionError('Builder class %s has no "name" attribute'
|
||||
raise ExtensionError(_('Builder class %s has no "name" attribute')
|
||||
% builder)
|
||||
if builder.name in self.builderclasses:
|
||||
raise ExtensionError(
|
||||
'Builder %r already exists (in module %s)' % (
|
||||
builder.name, self.builderclasses[builder.name].__module__))
|
||||
raise ExtensionError(_('Builder %r already exists (in module %s)') %
|
||||
(builder.name, self.builderclasses[builder.name].__module__))
|
||||
self.builderclasses[builder.name] = builder
|
||||
|
||||
def add_config_value(self, name, default, rebuild, types=()):
|
||||
@ -590,7 +515,7 @@ class Sphinx(object):
|
||||
logger.debug('[app] adding config value: %r',
|
||||
(name, default, rebuild) + ((types,) if types else ())) # type: ignore
|
||||
if name in self.config:
|
||||
raise ExtensionError('Config value %r already present' % name)
|
||||
raise ExtensionError(_('Config value %r already present') % name)
|
||||
if rebuild in (False, True):
|
||||
rebuild = rebuild and 'env' or ''
|
||||
self.config.add(name, default, rebuild, types)
|
||||
@ -598,13 +523,11 @@ class Sphinx(object):
|
||||
def add_event(self, name):
|
||||
# type: (unicode) -> None
|
||||
logger.debug('[app] adding event: %r', name)
|
||||
if name in self._events:
|
||||
raise ExtensionError('Event %r already present' % name)
|
||||
self._events[name] = ''
|
||||
self.events.add(name)
|
||||
|
||||
def set_translator(self, name, translator_class):
|
||||
# type: (unicode, Any) -> None
|
||||
logger.info(bold('A Translator for the %s builder is changed.' % name))
|
||||
logger.info(bold(_('A Translator for the %s builder is changed.') % name))
|
||||
self._translators[name] = translator_class
|
||||
|
||||
def add_node(self, node, **kwds):
|
||||
@ -612,8 +535,8 @@ class Sphinx(object):
|
||||
logger.debug('[app] adding node: %r', (node, kwds))
|
||||
if not kwds.pop('override', False) and \
|
||||
hasattr(nodes.GenericNodeVisitor, 'visit_' + node.__name__):
|
||||
logger.warning('while setting up extension %s: node class %r is '
|
||||
'already registered, its visitors will be overridden',
|
||||
logger.warning(_('while setting up extension %s: node class %r is '
|
||||
'already registered, its visitors will be overridden'),
|
||||
self._setting_up_extension, node.__name__,
|
||||
type='app', subtype='add_node')
|
||||
nodes._add_node_class_names([node.__name__])
|
||||
@ -621,8 +544,8 @@ class Sphinx(object):
|
||||
try:
|
||||
visit, depart = val
|
||||
except ValueError:
|
||||
raise ExtensionError('Value for key %r must be a '
|
||||
'(visit, depart) function tuple' % key)
|
||||
raise ExtensionError(_('Value for key %r must be a '
|
||||
'(visit, depart) function tuple') % key)
|
||||
translator = self._translators.get(key)
|
||||
translators = []
|
||||
if translator is not None:
|
||||
@ -665,8 +588,8 @@ class Sphinx(object):
|
||||
return convert_directive_function(obj)
|
||||
else:
|
||||
if content or arguments or options:
|
||||
raise ExtensionError('when adding directive classes, no '
|
||||
'additional arguments may be given')
|
||||
raise ExtensionError(_('when adding directive classes, no '
|
||||
'additional arguments may be given'))
|
||||
return obj
|
||||
|
||||
def add_directive(self, name, obj, content=None, arguments=None, **options):
|
||||
@ -674,8 +597,8 @@ class Sphinx(object):
|
||||
logger.debug('[app] adding directive: %r',
|
||||
(name, obj, content, arguments, options))
|
||||
if name in directives._directives:
|
||||
logger.warning('while setting up extension %s: directive %r is '
|
||||
'already registered, it will be overridden',
|
||||
logger.warning(_('while setting up extension %s: directive %r is '
|
||||
'already registered, it will be overridden'),
|
||||
self._setting_up_extension[-1], name,
|
||||
type='app', subtype='add_directive')
|
||||
directives.register_directive(
|
||||
@ -685,8 +608,8 @@ class Sphinx(object):
|
||||
# type: (unicode, Any) -> None
|
||||
logger.debug('[app] adding role: %r', (name, role))
|
||||
if name in roles._roles:
|
||||
logger.warning('while setting up extension %s: role %r is '
|
||||
'already registered, it will be overridden',
|
||||
logger.warning(_('while setting up extension %s: role %r is '
|
||||
'already registered, it will be overridden'),
|
||||
self._setting_up_extension[-1], name,
|
||||
type='app', subtype='add_role')
|
||||
roles.register_local_role(name, role)
|
||||
@ -697,8 +620,8 @@ class Sphinx(object):
|
||||
# register_canonical_role
|
||||
logger.debug('[app] adding generic role: %r', (name, nodeclass))
|
||||
if name in roles._roles:
|
||||
logger.warning('while setting up extension %s: role %r is '
|
||||
'already registered, it will be overridden',
|
||||
logger.warning(_('while setting up extension %s: role %r is '
|
||||
'already registered, it will be overridden'),
|
||||
self._setting_up_extension[-1], name,
|
||||
type='app', subtype='add_generic_role')
|
||||
role = roles.GenericRole(name, nodeclass)
|
||||
@ -708,17 +631,17 @@ class Sphinx(object):
|
||||
# type: (Type[Domain]) -> None
|
||||
logger.debug('[app] adding domain: %r', domain)
|
||||
if domain.name in self.domains:
|
||||
raise ExtensionError('domain %s already registered' % domain.name)
|
||||
raise ExtensionError(_('domain %s already registered') % domain.name)
|
||||
self.domains[domain.name] = domain
|
||||
|
||||
def override_domain(self, domain):
|
||||
# type: (Type[Domain]) -> None
|
||||
logger.debug('[app] overriding domain: %r', domain)
|
||||
if domain.name not in self.domains:
|
||||
raise ExtensionError('domain %s not yet registered' % domain.name)
|
||||
raise ExtensionError(_('domain %s not yet registered') % domain.name)
|
||||
if not issubclass(domain, self.domains[domain.name]):
|
||||
raise ExtensionError('new domain not a subclass of registered %s '
|
||||
'domain' % domain.name)
|
||||
raise ExtensionError(_('new domain not a subclass of registered %s '
|
||||
'domain') % domain.name)
|
||||
self.domains[domain.name] = domain
|
||||
|
||||
def add_directive_to_domain(self, domain, name, obj,
|
||||
@ -727,7 +650,7 @@ class Sphinx(object):
|
||||
logger.debug('[app] adding directive to domain: %r',
|
||||
(domain, name, obj, content, arguments, options))
|
||||
if domain not in self.domains:
|
||||
raise ExtensionError('domain %s not yet registered' % domain)
|
||||
raise ExtensionError(_('domain %s not yet registered') % domain)
|
||||
self.domains[domain].directives[name] = \
|
||||
self._directive_helper(obj, content, arguments, **options)
|
||||
|
||||
@ -735,14 +658,14 @@ class Sphinx(object):
|
||||
# type: (unicode, unicode, Any) -> None
|
||||
logger.debug('[app] adding role to domain: %r', (domain, name, role))
|
||||
if domain not in self.domains:
|
||||
raise ExtensionError('domain %s not yet registered' % domain)
|
||||
raise ExtensionError(_('domain %s not yet registered') % domain)
|
||||
self.domains[domain].roles[name] = role
|
||||
|
||||
def add_index_to_domain(self, domain, index):
|
||||
# type: (unicode, Type[Index]) -> None
|
||||
logger.debug('[app] adding index to domain: %r', (domain, index))
|
||||
if domain not in self.domains:
|
||||
raise ExtensionError('domain %s not yet registered' % domain)
|
||||
raise ExtensionError(_('domain %s not yet registered') % domain)
|
||||
self.domains[domain].indices.append(index)
|
||||
|
||||
def add_object_type(self, directivename, rolename, indextemplate='',
|
||||
@ -782,10 +705,15 @@ class Sphinx(object):
|
||||
StandardDomain.roles[rolename] = XRefRole(innernodeclass=ref_nodeclass)
|
||||
|
||||
def add_transform(self, transform):
|
||||
# type: (Transform) -> None
|
||||
# type: (Type[Transform]) -> None
|
||||
logger.debug('[app] adding transform: %r', transform)
|
||||
SphinxStandaloneReader.transforms.append(transform)
|
||||
|
||||
def add_post_transform(self, transform):
|
||||
# type: (Type[Transform]) -> None
|
||||
logger.debug('[app] adding post transform: %r', transform)
|
||||
self.post_transforms.append(transform)
|
||||
|
||||
def add_javascript(self, filename):
|
||||
# type: (unicode) -> None
|
||||
logger.debug('[app] adding javascript: %r', filename)
|
||||
@ -850,8 +778,8 @@ class Sphinx(object):
|
||||
# type: (unicode, Parser) -> None
|
||||
logger.debug('[app] adding search source_parser: %r, %r', suffix, parser)
|
||||
if suffix in self._additional_source_parsers:
|
||||
logger.warning('while setting up extension %s: source_parser for %r is '
|
||||
'already registered, it will be overridden',
|
||||
logger.warning(_('while setting up extension %s: source_parser for %r is '
|
||||
'already registered, it will be overridden'),
|
||||
self._setting_up_extension[-1], suffix,
|
||||
type='app', subtype='add_source_parser')
|
||||
self._additional_source_parsers[suffix] = parser
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Builder superclass for all builders.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -17,6 +17,7 @@ try:
|
||||
except ImportError:
|
||||
multiprocessing = None
|
||||
|
||||
from six import itervalues
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.util import i18n, path_stabilize, logging, status_iterator
|
||||
@ -48,21 +49,20 @@ class Builder(object):
|
||||
Builds target formats from the reST sources.
|
||||
"""
|
||||
|
||||
# builder's name, for the -b command line options
|
||||
#: The builder's name, for the -b command line option.
|
||||
name = '' # type: unicode
|
||||
# builder's output format, or '' if no document output is produced
|
||||
#: The builder's output format, or '' if no document output is produced.
|
||||
format = '' # type: unicode
|
||||
# doctree versioning method
|
||||
versioning_method = 'none' # type: unicode
|
||||
versioning_compare = False
|
||||
# allow parallel write_doc() calls
|
||||
allow_parallel = False
|
||||
# support translation
|
||||
use_message_catalog = True
|
||||
|
||||
def __init__(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
self.env = app.env # type: BuildEnvironment
|
||||
self.env.set_versioning_method(self.versioning_method,
|
||||
self.versioning_compare)
|
||||
self.srcdir = app.srcdir
|
||||
self.confdir = app.confdir
|
||||
self.outdir = app.outdir
|
||||
@ -71,6 +71,7 @@ class Builder(object):
|
||||
os.makedirs(self.doctreedir)
|
||||
|
||||
self.app = app # type: Sphinx
|
||||
self.env = None # type: BuildEnvironment
|
||||
self.warn = app.warn # type: Callable
|
||||
self.info = app.info # type: Callable
|
||||
self.config = app.config # type: Config
|
||||
@ -97,7 +98,12 @@ class Builder(object):
|
||||
# load default translator class
|
||||
self.translator_class = app._translators.get(self.name)
|
||||
|
||||
self.init()
|
||||
def set_environment(self, env):
|
||||
# type: (BuildEnvironment) -> None
|
||||
"""Store BuildEnvironment object."""
|
||||
self.env = env
|
||||
self.env.set_versioning_method(self.versioning_method,
|
||||
self.versioning_compare)
|
||||
|
||||
# helper methods
|
||||
def init(self):
|
||||
@ -146,6 +152,13 @@ class Builder(object):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_asset_paths(self):
|
||||
# type: () -> List[unicode]
|
||||
"""Return list of paths for assets (ex. templates, CSS, etc.)."""
|
||||
return []
|
||||
|
||||
#: The list of MIME types of image formats supported by the builder.
|
||||
#: Image files are searched in the order in which they appear here.
|
||||
supported_image_types = [] # type: List[unicode]
|
||||
|
||||
def post_process_images(self, doctree):
|
||||
@ -289,8 +302,7 @@ class Builder(object):
|
||||
|
||||
# while reading, collect all warnings from docutils
|
||||
with logging.pending_warnings():
|
||||
updated_docnames = set(self.env.update(self.config, self.srcdir,
|
||||
self.doctreedir, self.app))
|
||||
updated_docnames = set(self.env.update(self.config, self.srcdir, self.doctreedir))
|
||||
|
||||
doccount = len(updated_docnames)
|
||||
logger.info(bold('looking for now-outdated files... '), nonl=1)
|
||||
@ -328,11 +340,10 @@ class Builder(object):
|
||||
self.parallel_ok = False
|
||||
if parallel_available and self.app.parallel > 1 and self.allow_parallel:
|
||||
self.parallel_ok = True
|
||||
for extname, md in self.app._extension_metadata.items():
|
||||
par_ok = md.get('parallel_write_safe', True)
|
||||
if not par_ok:
|
||||
for extension in itervalues(self.app.extensions):
|
||||
if not extension.parallel_write_safe:
|
||||
logger.warning('the %s extension is not safe for parallel '
|
||||
'writing, doing serial write', extname)
|
||||
'writing, doing serial write', extension.name)
|
||||
self.parallel_ok = False
|
||||
break
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Build Apple help books.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Changelog builder.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
.. _Devhelp: http://live.gnome.org/devhelp
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
@ -6,12 +6,13 @@
|
||||
Build epub files.
|
||||
Originally derived from qthelp.py.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import warnings
|
||||
from os import path
|
||||
from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
|
||||
from datetime import datetime
|
||||
@ -30,6 +31,7 @@ from docutils import nodes
|
||||
from sphinx import addnodes
|
||||
from sphinx import package_dir
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.deprecation import RemovedInSphinx17Warning
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import status_iterator
|
||||
from sphinx.util.osutil import ensuredir, copyfile, make_filename
|
||||
@ -713,10 +715,18 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED) # type: ignore
|
||||
|
||||
|
||||
def emit_deprecation_warning(app):
|
||||
# type: (Sphinx) -> None
|
||||
if app.builder.__class__ is EpubBuilder:
|
||||
warnings.warn('epub2 builder is deprecated. Please use epub3 builder instead.',
|
||||
RemovedInSphinx17Warning)
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> Dict[unicode, Any]
|
||||
app.setup_extension('sphinx.builders.html')
|
||||
app.add_builder(EpubBuilder)
|
||||
app.connect('builder-inited', emit_deprecation_warning)
|
||||
|
||||
# config values
|
||||
app.add_config_value('epub_basename', lambda self: make_filename(self.project), None)
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The MessageCatalogBuilder class.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -112,16 +112,15 @@ class I18nBuilder(Builder):
|
||||
"""
|
||||
name = 'i18n'
|
||||
versioning_method = 'text'
|
||||
versioning_compare = None # be set by `gettext_uuid`
|
||||
|
||||
def __init__(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
self.versioning_compare = app.env.config.gettext_uuid
|
||||
super(I18nBuilder, self).__init__(app)
|
||||
versioning_compare = None # type: bool
|
||||
# be set by `gettext_uuid`
|
||||
use_message_catalog = False
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
Builder.init(self)
|
||||
self.env.set_versioning_method(self.versioning_method,
|
||||
self.env.config.gettext_uuid)
|
||||
self.tags = I18nTags()
|
||||
self.catalogs = defaultdict(Catalog) # type: defaultdict[unicode, Catalog]
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Several HTML builders.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -120,9 +120,6 @@ class StandaloneHTMLBuilder(Builder):
|
||||
imgpath = None # type: unicode
|
||||
domain_indices = [] # type: List[Tuple[unicode, Type[Index], List[Tuple[unicode, List[List[Union[unicode, int]]]]], bool]] # NOQA
|
||||
|
||||
default_sidebars = ['localtoc.html', 'relations.html',
|
||||
'sourcelink.html', 'searchbox.html']
|
||||
|
||||
# cached publisher object for snippets
|
||||
_publisher = None
|
||||
|
||||
@ -265,6 +262,10 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# source doesn't exist anymore
|
||||
pass
|
||||
|
||||
def get_asset_paths(self):
|
||||
# type: () -> List[unicode]
|
||||
return self.config.html_extra_path
|
||||
|
||||
def render_partial(self, node):
|
||||
# type: (nodes.Nodes) -> Dict[unicode, unicode]
|
||||
"""Utility: Render a lone doctree node."""
|
||||
@ -1022,7 +1023,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
if 'includehidden' not in kwds:
|
||||
kwds['includehidden'] = False
|
||||
toctree = TocTree(self.env).get_toctree_for(docname, self, collapse, **kwds)
|
||||
self.fix_refuris(toctree)
|
||||
if toctree is not None:
|
||||
self.fix_refuris(toctree)
|
||||
return self.render_partial(toctree)['fragment']
|
||||
|
||||
def assemble_doctree(self):
|
||||
|
@ -6,7 +6,7 @@
|
||||
Build HTML help support files.
|
||||
Parts adapted from Python's Doc/tools/prechm.py.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
LaTeX builder.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The CheckExternalLinksBuilder class.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -182,7 +182,9 @@ class CheckExternalLinksBuilder(Builder):
|
||||
# history contains any redirects, get last
|
||||
if response.history:
|
||||
code = response.history[-1].status_code
|
||||
return 'redirected', new_url, code
|
||||
return 'redirected', new_url, code
|
||||
else:
|
||||
return 'redirected', new_url, 0
|
||||
|
||||
def check():
|
||||
# type: () -> Tuple[unicode, unicode, int]
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Manual pages builder.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Build input files for the Qt collection generator.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Texinfo builder.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Plain-text Sphinx builder.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Builder for the web support package.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Docutils-native XML and pseudo-XML builders.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
sphinx-build command-line handling.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Build configuration file handling.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -16,7 +16,7 @@ from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integ
|
||||
from typing import Any, NamedTuple, Union
|
||||
|
||||
from sphinx.errors import ConfigError
|
||||
from sphinx.locale import l_
|
||||
from sphinx.locale import l_, _
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.osutil import cd
|
||||
@ -56,7 +56,7 @@ class ENUM(object):
|
||||
"""represents the config value should be a one of candidates.
|
||||
|
||||
Example:
|
||||
app.add_config_value('latex_show_urls', 'no', ENUM('no', 'footnote', 'inline'))
|
||||
app.add_config_value('latex_show_urls', 'no', None, ENUM('no', 'footnote', 'inline'))
|
||||
"""
|
||||
def __init__(self, *candidates):
|
||||
# type: (unicode) -> None
|
||||
@ -233,8 +233,8 @@ class Config(object):
|
||||
else:
|
||||
defvalue = self.values[name][0]
|
||||
if isinstance(defvalue, dict):
|
||||
raise ValueError('cannot override dictionary config setting %r, '
|
||||
'ignoring (use %r to set individual elements)' %
|
||||
raise ValueError(_('cannot override dictionary config setting %r, '
|
||||
'ignoring (use %r to set individual elements)') %
|
||||
(name, name + '.key=value'))
|
||||
elif isinstance(defvalue, list):
|
||||
return value.split(',')
|
||||
@ -242,20 +242,22 @@ class Config(object):
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
raise ValueError('invalid number %r for config value %r, ignoring' %
|
||||
raise ValueError(_('invalid number %r for config value %r, ignoring') %
|
||||
(value, name))
|
||||
elif hasattr(defvalue, '__call__'):
|
||||
return value
|
||||
elif defvalue is not None and not isinstance(defvalue, string_types):
|
||||
raise ValueError('cannot override config setting %r with unsupported '
|
||||
'type, ignoring' % name)
|
||||
raise ValueError(_('cannot override config setting %r with unsupported '
|
||||
'type, ignoring') % name)
|
||||
else:
|
||||
return value
|
||||
|
||||
def pre_init_values(self):
|
||||
# type: () -> None
|
||||
"""Initialize some limited config variables before loading extensions"""
|
||||
variables = ['needs_sphinx', 'suppress_warnings']
|
||||
"""
|
||||
Initialize some limited config variables before initialize i18n and loading extensions
|
||||
"""
|
||||
variables = ['needs_sphinx', 'suppress_warnings', 'language', 'locale_dirs']
|
||||
for name in variables:
|
||||
try:
|
||||
if name in self.overrides:
|
||||
@ -275,7 +277,7 @@ class Config(object):
|
||||
config.setdefault(realvalname, {})[key] = value
|
||||
continue
|
||||
elif valname not in self.values:
|
||||
logger.warning('unknown config value %r in override, ignoring', valname)
|
||||
logger.warning(_('unknown config value %r in override, ignoring'), valname)
|
||||
continue
|
||||
if isinstance(value, string_types):
|
||||
config[valname] = self.convert_overrides(valname, value)
|
||||
@ -294,7 +296,7 @@ class Config(object):
|
||||
if name.startswith('_'):
|
||||
raise AttributeError(name)
|
||||
if name not in self.values:
|
||||
raise AttributeError('No such config value: %s' % name)
|
||||
raise AttributeError(_('No such config value: %s') % name)
|
||||
default = self.values[name][0]
|
||||
if hasattr(default, '__call__'):
|
||||
return default(self)
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Sphinx deprecation classes and utilities.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Handlers for additional ReST directives.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
sphinx.directives.code
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -314,6 +314,11 @@ class LiteralIncludeReader(object):
|
||||
self.lineno_start += lineno
|
||||
|
||||
return lines[lineno:]
|
||||
else:
|
||||
if inclusive is True:
|
||||
raise ValueError('start-after pattern not found: %s' % start)
|
||||
else:
|
||||
raise ValueError('start-at pattern not found: %s' % start)
|
||||
|
||||
return lines
|
||||
|
||||
@ -338,6 +343,11 @@ class LiteralIncludeReader(object):
|
||||
return []
|
||||
else:
|
||||
return lines[:lineno]
|
||||
else:
|
||||
if inclusive is True:
|
||||
raise ValueError('end-at pattern not found: %s' % end)
|
||||
else:
|
||||
raise ValueError('end-before pattern not found: %s' % end)
|
||||
|
||||
return lines
|
||||
|
||||
@ -424,7 +434,7 @@ class LiteralInclude(Directive):
|
||||
'lineno-match' in self.options)
|
||||
retnode['classes'] += self.options.get('class', [])
|
||||
extra_args = retnode['highlight_args'] = {}
|
||||
if 'empahsize-lines' in self.options:
|
||||
if 'emphasize-lines' in self.options:
|
||||
hl_lines = parselinenos(self.options['emphasize-lines'], lines)
|
||||
if any(i >= lines for i in hl_lines):
|
||||
logger.warning('line number spec is out of range(1-%d): %r' %
|
||||
|
@ -3,7 +3,7 @@
|
||||
sphinx.directives.other
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
sphinx.directives.patches
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
Support for domains, which are groupings of description directives
|
||||
and roles describing e.g. constructs of one programming language.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -240,6 +240,13 @@ class Domain(object):
|
||||
"""Process a document after it is read by the environment."""
|
||||
pass
|
||||
|
||||
def process_field_xref(self, pnode):
|
||||
# type: (nodes.Node) -> None
|
||||
"""Process a pending xref created in a doc field.
|
||||
For example, attach information about the current scope.
|
||||
"""
|
||||
pass
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder,
|
||||
typ, target, node, contnode):
|
||||
# type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The C language domain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The C++ language domain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -3480,7 +3480,7 @@ class DefinitionParser(object):
|
||||
value = self.matched_text
|
||||
else:
|
||||
# TODO: add handling of more bracket-like things, and quote handling
|
||||
brackets = {'(': ')', '[': ']'} # type: Dict[unicode, unicode]
|
||||
brackets = {'(': ')', '[': ']', '<': '>'} # type: Dict[unicode, unicode]
|
||||
symbols = [] # type: List[unicode]
|
||||
while not self.eof:
|
||||
if (len(symbols) == 0 and self.current_char in end):
|
||||
@ -4552,10 +4552,11 @@ class CPPObject(ObjectDescription):
|
||||
|
||||
def handle_signature(self, sig, signode):
|
||||
# type: (unicode, addnodes.desc_signature) -> Any
|
||||
if 'cpp:parent_symbol' not in self.env.ref_context:
|
||||
if 'cpp:parent_symbol' not in self.env.temp_data:
|
||||
root = self.env.domaindata['cpp']['root_symbol']
|
||||
self.env.ref_context['cpp:parent_symbol'] = root
|
||||
parentSymbol = self.env.ref_context['cpp:parent_symbol']
|
||||
self.env.temp_data['cpp:parent_symbol'] = root
|
||||
self.env.ref_context['cpp:parent_key'] = root.get_lookup_key()
|
||||
parentSymbol = self.env.temp_data['cpp:parent_symbol']
|
||||
|
||||
parser = DefinitionParser(sig, self, self.env.config)
|
||||
try:
|
||||
@ -4567,16 +4568,16 @@ class CPPObject(ObjectDescription):
|
||||
# the possibly inner declarations.
|
||||
name = _make_phony_error_name()
|
||||
symbol = parentSymbol.add_name(name)
|
||||
self.env.ref_context['cpp:last_symbol'] = symbol
|
||||
self.env.temp_data['cpp:last_symbol'] = symbol
|
||||
raise ValueError
|
||||
|
||||
try:
|
||||
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
|
||||
self.env.ref_context['cpp:last_symbol'] = symbol
|
||||
self.env.temp_data['cpp:last_symbol'] = symbol
|
||||
except _DuplicateSymbolError as e:
|
||||
# Assume we are actually in the old symbol,
|
||||
# instead of the newly created duplicate.
|
||||
self.env.ref_context['cpp:last_symbol'] = e.symbol
|
||||
self.env.temp_data['cpp:last_symbol'] = e.symbol
|
||||
|
||||
if ast.objectType == 'enumerator':
|
||||
self._add_enumerator_to_parent(ast)
|
||||
@ -4587,14 +4588,17 @@ class CPPObject(ObjectDescription):
|
||||
|
||||
def before_content(self):
|
||||
# type: () -> None
|
||||
lastSymbol = self.env.ref_context['cpp:last_symbol']
|
||||
lastSymbol = self.env.temp_data['cpp:last_symbol']
|
||||
assert lastSymbol
|
||||
self.oldParentSymbol = self.env.ref_context['cpp:parent_symbol']
|
||||
self.env.ref_context['cpp:parent_symbol'] = lastSymbol
|
||||
self.oldParentSymbol = self.env.temp_data['cpp:parent_symbol']
|
||||
self.oldParentKey = self.env.ref_context['cpp:parent_key']
|
||||
self.env.temp_data['cpp:parent_symbol'] = lastSymbol
|
||||
self.env.ref_context['cpp:parent_key'] = lastSymbol.get_lookup_key()
|
||||
|
||||
def after_content(self):
|
||||
# type: () -> None
|
||||
self.env.ref_context['cpp:parent_symbol'] = self.oldParentSymbol
|
||||
self.env.temp_data['cpp:parent_symbol'] = self.oldParentSymbol
|
||||
self.env.ref_context['cpp:parent_key'] = self.oldParentKey
|
||||
|
||||
|
||||
class CPPTypeObject(CPPObject):
|
||||
@ -4711,8 +4715,9 @@ class CPPNamespaceObject(Directive):
|
||||
ast = ASTNamespace(name, None)
|
||||
symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix)
|
||||
stack = [symbol]
|
||||
env.ref_context['cpp:parent_symbol'] = symbol
|
||||
env.temp_data['cpp:parent_symbol'] = symbol
|
||||
env.temp_data['cpp:namespace_stack'] = stack
|
||||
env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
|
||||
@ -4740,14 +4745,15 @@ class CPPNamespacePushObject(Directive):
|
||||
self.warn(e.description)
|
||||
name = _make_phony_error_name()
|
||||
ast = ASTNamespace(name, None)
|
||||
oldParent = env.ref_context.get('cpp:parent_symbol', None)
|
||||
oldParent = env.temp_data.get('cpp:parent_symbol', None)
|
||||
if not oldParent:
|
||||
oldParent = env.domaindata['cpp']['root_symbol']
|
||||
symbol = oldParent.add_name(ast.nestedName, ast.templatePrefix)
|
||||
stack = env.temp_data.get('cpp:namespace_stack', [])
|
||||
stack.append(symbol)
|
||||
env.ref_context['cpp:parent_symbol'] = symbol
|
||||
env.temp_data['cpp:parent_symbol'] = symbol
|
||||
env.temp_data['cpp:namespace_stack'] = stack
|
||||
env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
|
||||
@ -4775,17 +4781,16 @@ class CPPNamespacePopObject(Directive):
|
||||
symbol = stack[-1]
|
||||
else:
|
||||
symbol = env.domaindata['cpp']['root_symbol']
|
||||
env.ref_context['cpp:parent_symbol'] = symbol
|
||||
env.temp_data['cpp:parent_symbol'] = symbol
|
||||
env.temp_data['cpp:namespace_stack'] = stack
|
||||
env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
|
||||
return []
|
||||
|
||||
|
||||
class CPPXRefRole(XRefRole):
|
||||
def process_link(self, env, refnode, has_explicit_title, title, target):
|
||||
# type: (BuildEnvironment, nodes.Node, bool, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
|
||||
parent = env.ref_context.get('cpp:parent_symbol', None)
|
||||
if parent:
|
||||
refnode['cpp:parent_key'] = parent.get_lookup_key()
|
||||
refnode.attributes.update(env.ref_context)
|
||||
if refnode['reftype'] == 'any':
|
||||
# Assume the removal part of fix_parens for :any: refs.
|
||||
# The addition part is done with the reference is resolved.
|
||||
@ -4866,6 +4871,10 @@ class CPPDomain(Domain):
|
||||
# print(self.data['root_symbol'].dump(0))
|
||||
pass
|
||||
|
||||
def process_field_xref(self, pnode):
|
||||
# type: (nodes.Node) -> None
|
||||
pnode.attributes.update(self.env.ref_context)
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# type: (List[unicode], Dict) -> None
|
||||
self.data['root_symbol'].merge_with(otherdata['root_symbol'],
|
||||
@ -4897,8 +4906,21 @@ class CPPDomain(Domain):
|
||||
ast = parser.parse_xref_object()
|
||||
parser.assert_end()
|
||||
except DefinitionError as e:
|
||||
def findWarning(e): # as arg to stop flake8 from complaining
|
||||
if typ != 'any' and typ != 'func':
|
||||
return target, e
|
||||
# hax on top of the paren hax to try to get correct errors
|
||||
parser2 = DefinitionParser(target[:-2], warner, env.config)
|
||||
try:
|
||||
parser2.parse_xref_object()
|
||||
parser2.assert_end()
|
||||
except DefinitionError as e2:
|
||||
return target[:-2], e2
|
||||
# strange, that we don't get the error now, use the original
|
||||
return target, e
|
||||
t, ex = findWarning(e)
|
||||
warner.warn('Unparseable C++ cross-reference: %r\n%s'
|
||||
% (target, text_type(e.description)))
|
||||
% (t, text_type(ex.description)))
|
||||
return None, None
|
||||
parentKey = node.get("cpp:parent_key", None)
|
||||
rootSymbol = self.data['root_symbol']
|
||||
@ -4991,7 +5013,10 @@ class CPPDomain(Domain):
|
||||
'any', target, node, contnode,
|
||||
emitWarnings=False)
|
||||
if node:
|
||||
return [('cpp:' + self.role_for_objtype(objtype), node)]
|
||||
if objtype == 'templateParam':
|
||||
return [('cpp:templateParam', node)]
|
||||
else:
|
||||
return [('cpp:' + self.role_for_objtype(objtype), node)]
|
||||
return []
|
||||
|
||||
def get_objects(self):
|
||||
|
@ -5,10 +5,13 @@
|
||||
|
||||
The JavaScript domain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.locale import l_, _
|
||||
@ -38,57 +41,68 @@ class JSObject(ObjectDescription):
|
||||
#: what is displayed right before the documentation entry
|
||||
display_prefix = None # type: unicode
|
||||
|
||||
#: If ``allow_nesting`` is ``True``, the object prefixes will be accumulated
|
||||
#: based on directive nesting
|
||||
allow_nesting = False
|
||||
|
||||
def handle_signature(self, sig, signode):
|
||||
# type: (unicode, addnodes.desc_signature) -> Tuple[unicode, unicode]
|
||||
"""Breaks down construct signatures
|
||||
|
||||
Parses out prefix and argument list from construct definition. The
|
||||
namespace and class will be determined by the nesting of domain
|
||||
directives.
|
||||
"""
|
||||
sig = sig.strip()
|
||||
if '(' in sig and sig[-1:] == ')':
|
||||
prefix, arglist = sig.split('(', 1)
|
||||
prefix = prefix.strip()
|
||||
member, arglist = sig.split('(', 1)
|
||||
member = member.strip()
|
||||
arglist = arglist[:-1].strip()
|
||||
else:
|
||||
prefix = sig
|
||||
member = sig
|
||||
arglist = None
|
||||
if '.' in prefix:
|
||||
nameprefix, name = prefix.rsplit('.', 1)
|
||||
else:
|
||||
nameprefix = None
|
||||
name = prefix
|
||||
# If construct is nested, prefix the current prefix
|
||||
prefix = self.env.ref_context.get('js:object', None)
|
||||
mod_name = self.env.ref_context.get('js:module')
|
||||
name = member
|
||||
try:
|
||||
member_prefix, member_name = member.rsplit('.', 1)
|
||||
except ValueError:
|
||||
member_name = name
|
||||
member_prefix = ''
|
||||
finally:
|
||||
name = member_name
|
||||
if prefix and member_prefix:
|
||||
prefix = '.'.join([prefix, member_prefix])
|
||||
elif prefix is None and member_prefix:
|
||||
prefix = member_prefix
|
||||
fullname = name
|
||||
if prefix:
|
||||
fullname = '.'.join([prefix, name])
|
||||
|
||||
objectname = self.env.ref_context.get('js:object')
|
||||
if nameprefix:
|
||||
if objectname:
|
||||
# someone documenting the method of an attribute of the current
|
||||
# object? shouldn't happen but who knows...
|
||||
nameprefix = objectname + '.' + nameprefix
|
||||
fullname = nameprefix + '.' + name
|
||||
elif objectname:
|
||||
fullname = objectname + '.' + name
|
||||
else:
|
||||
# just a function or constructor
|
||||
objectname = ''
|
||||
fullname = name
|
||||
|
||||
signode['object'] = objectname
|
||||
signode['module'] = mod_name
|
||||
signode['object'] = prefix
|
||||
signode['fullname'] = fullname
|
||||
|
||||
if self.display_prefix:
|
||||
signode += addnodes.desc_annotation(self.display_prefix,
|
||||
self.display_prefix)
|
||||
if nameprefix:
|
||||
signode += addnodes.desc_addname(nameprefix + '.', nameprefix + '.')
|
||||
if prefix:
|
||||
signode += addnodes.desc_addname(prefix + '.', prefix + '.')
|
||||
elif mod_name:
|
||||
signode += addnodes.desc_addname(mod_name + '.', mod_name + '.')
|
||||
signode += addnodes.desc_name(name, name)
|
||||
if self.has_arguments:
|
||||
if not arglist:
|
||||
signode += addnodes.desc_parameterlist()
|
||||
else:
|
||||
_pseudo_parse_arglist(signode, arglist)
|
||||
return fullname, nameprefix
|
||||
return fullname, prefix
|
||||
|
||||
def add_target_and_index(self, name_obj, sig, signode):
|
||||
# type: (Tuple[unicode, unicode], unicode, addnodes.desc_signature) -> None
|
||||
objectname = self.options.get(
|
||||
'object', self.env.ref_context.get('js:object'))
|
||||
fullname = name_obj[0]
|
||||
mod_name = self.env.ref_context.get('js:module')
|
||||
fullname = (mod_name and mod_name + '.' or '') + name_obj[0]
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
signode['ids'].append(fullname.replace('$', '_S_'))
|
||||
@ -103,7 +117,7 @@ class JSObject(ObjectDescription):
|
||||
line=self.lineno)
|
||||
objects[fullname] = self.env.docname, self.objtype
|
||||
|
||||
indextext = self.get_index_text(objectname, name_obj)
|
||||
indextext = self.get_index_text(mod_name, name_obj)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext,
|
||||
fullname.replace('$', '_S_'),
|
||||
@ -124,6 +138,63 @@ class JSObject(ObjectDescription):
|
||||
return _('%s (%s attribute)') % (name, obj)
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
# type: () -> None
|
||||
"""Handle object nesting before content
|
||||
|
||||
:py:class:`JSObject` represents JavaScript language constructs. For
|
||||
constructs that are nestable, this method will build up a stack of the
|
||||
nesting heirarchy so that it can be later de-nested correctly, in
|
||||
:py:meth:`after_content`.
|
||||
|
||||
For constructs that aren't nestable, the stack is bypassed, and instead
|
||||
only the most recent object is tracked. This object prefix name will be
|
||||
removed with :py:meth:`after_content`.
|
||||
|
||||
The following keys are used in ``self.env.ref_context``:
|
||||
|
||||
js:objects
|
||||
Stores the object prefix history. With each nested element, we
|
||||
add the object prefix to this list. When we exit that object's
|
||||
nesting level, :py:meth:`after_content` is triggered and the
|
||||
prefix is removed from the end of the list.
|
||||
|
||||
js:object
|
||||
Current object prefix. This should generally reflect the last
|
||||
element in the prefix history
|
||||
"""
|
||||
prefix = None
|
||||
if self.names:
|
||||
(obj_name, obj_name_prefix) = self.names.pop()
|
||||
prefix = obj_name_prefix.strip('.') if obj_name_prefix else None
|
||||
if self.allow_nesting:
|
||||
prefix = obj_name
|
||||
if prefix:
|
||||
self.env.ref_context['js:object'] = prefix
|
||||
if self.allow_nesting:
|
||||
objects = self.env.ref_context.setdefault('js:objects', [])
|
||||
objects.append(prefix)
|
||||
|
||||
def after_content(self):
|
||||
# type: () -> None
|
||||
"""Handle object de-nesting after content
|
||||
|
||||
If this class is a nestable object, removing the last nested class prefix
|
||||
ends further nesting in the object.
|
||||
|
||||
If this class is not a nestable object, the list of classes should not
|
||||
be altered as we didn't affect the nesting levels in
|
||||
:py:meth:`before_content`.
|
||||
"""
|
||||
objects = self.env.ref_context.setdefault('js:objects', [])
|
||||
if self.allow_nesting:
|
||||
try:
|
||||
objects.pop()
|
||||
except IndexError:
|
||||
pass
|
||||
self.env.ref_context['js:object'] = (objects[-1] if len(objects) > 0
|
||||
else None)
|
||||
|
||||
|
||||
class JSCallable(JSObject):
|
||||
"""Description of a JavaScript function, method or constructor."""
|
||||
@ -146,6 +217,57 @@ class JSCallable(JSObject):
|
||||
class JSConstructor(JSCallable):
|
||||
"""Like a callable but with a different prefix."""
|
||||
display_prefix = 'class '
|
||||
allow_nesting = True
|
||||
|
||||
|
||||
class JSModule(Directive):
|
||||
"""
|
||||
Directive to mark description of a new JavaScript module.
|
||||
|
||||
This directive specifies the module name that will be used by objects that
|
||||
follow this directive.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
noindex
|
||||
If the ``noindex`` option is specified, no linkable elements will be
|
||||
created, and the module won't be added to the global module index. This
|
||||
is useful for splitting up the module definition across multiple
|
||||
sections or files.
|
||||
|
||||
:param mod_name: Module name
|
||||
"""
|
||||
|
||||
has_content = False
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
'noindex': directives.flag
|
||||
}
|
||||
|
||||
def run(self):
|
||||
# type: () -> List[nodes.Node]
|
||||
env = self.state.document.settings.env
|
||||
mod_name = self.arguments[0].strip()
|
||||
env.ref_context['js:module'] = mod_name
|
||||
noindex = 'noindex' in self.options
|
||||
ret = []
|
||||
if not noindex:
|
||||
env.domaindata['js']['modules'][mod_name] = env.docname
|
||||
# Make a duplicate entry in 'objects' to facilitate searching for
|
||||
# the module in JavaScriptDomain.find_obj()
|
||||
env.domaindata['js']['objects'][mod_name] = (env.docname, 'module')
|
||||
targetnode = nodes.target('', '', ids=['module-' + mod_name],
|
||||
ismod=True)
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
ret.append(targetnode)
|
||||
indextext = _('%s (module)') % mod_name
|
||||
inode = addnodes.index(entries=[('single', indextext,
|
||||
'module-' + mod_name, '', None)])
|
||||
ret.append(inode)
|
||||
return ret
|
||||
|
||||
|
||||
class JSXRefRole(XRefRole):
|
||||
@ -153,6 +275,7 @@ class JSXRefRole(XRefRole):
|
||||
# type: (BuildEnvironment, nodes.Node, bool, unicode, unicode) -> Tuple[unicode, unicode] # NOQA
|
||||
# basically what sphinx.domains.python.PyXRefRole does
|
||||
refnode['js:object'] = env.ref_context.get('js:object')
|
||||
refnode['js:module'] = env.ref_context.get('js:module')
|
||||
if not has_explicit_title:
|
||||
title = title.lstrip('.')
|
||||
target = target.lstrip('~')
|
||||
@ -174,31 +297,41 @@ class JavaScriptDomain(Domain):
|
||||
# if you add a new object type make sure to edit JSObject.get_index_string
|
||||
object_types = {
|
||||
'function': ObjType(l_('function'), 'func'),
|
||||
'method': ObjType(l_('method'), 'meth'),
|
||||
'class': ObjType(l_('class'), 'class'),
|
||||
'data': ObjType(l_('data'), 'data'),
|
||||
'attribute': ObjType(l_('attribute'), 'attr'),
|
||||
'module': ObjType(l_('module'), 'mod'),
|
||||
}
|
||||
directives = {
|
||||
'function': JSCallable,
|
||||
'method': JSCallable,
|
||||
'class': JSConstructor,
|
||||
'data': JSObject,
|
||||
'attribute': JSObject,
|
||||
'module': JSModule,
|
||||
}
|
||||
roles = {
|
||||
'func': JSXRefRole(fix_parens=True),
|
||||
'meth': JSXRefRole(fix_parens=True),
|
||||
'class': JSXRefRole(fix_parens=True),
|
||||
'data': JSXRefRole(),
|
||||
'attr': JSXRefRole(),
|
||||
'mod': JSXRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
'modules': {}, # mod_name -> docname
|
||||
} # type: Dict[unicode, Dict[unicode, Tuple[unicode, unicode]]]
|
||||
|
||||
def clear_doc(self, docname):
|
||||
# type: (unicode) -> None
|
||||
for fullname, (fn, _l) in list(self.data['objects'].items()):
|
||||
if fn == docname:
|
||||
for fullname, (pkg_docname, _l) in list(self.data['objects'].items()):
|
||||
if pkg_docname == docname:
|
||||
del self.data['objects'][fullname]
|
||||
for mod_name, pkg_docname in list(self.data['modules'].items()):
|
||||
if pkg_docname == docname:
|
||||
del self.data['modules'][mod_name]
|
||||
|
||||
def merge_domaindata(self, docnames, otherdata):
|
||||
# type: (List[unicode], Dict) -> None
|
||||
@ -206,31 +339,42 @@ class JavaScriptDomain(Domain):
|
||||
for fullname, (fn, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
self.data['objects'][fullname] = (fn, objtype)
|
||||
for mod_name, pkg_docname in otherdata['modules'].items():
|
||||
if pkg_docname in docnames:
|
||||
self.data['modules'][mod_name] = pkg_docname
|
||||
|
||||
def find_obj(self, env, obj, name, typ, searchorder=0):
|
||||
# type: (BuildEnvironment, unicode, unicode, unicode, int) -> Tuple[unicode, Tuple[unicode, unicode]] # NOQA
|
||||
def find_obj(self, env, mod_name, prefix, name, typ, searchorder=0):
|
||||
# type: (BuildEnvironment, unicode, unicode, unicode, unicode, int) -> Tuple[unicode, Tuple[unicode, unicode]] # NOQA
|
||||
if name[-2:] == '()':
|
||||
name = name[:-2]
|
||||
objects = self.data['objects']
|
||||
|
||||
searches = []
|
||||
if mod_name and prefix:
|
||||
searches.append('.'.join([mod_name, prefix, name]))
|
||||
if mod_name:
|
||||
searches.append('.'.join([mod_name, name]))
|
||||
if prefix:
|
||||
searches.append('.'.join([prefix, name]))
|
||||
searches.append(name)
|
||||
|
||||
if searchorder == 0:
|
||||
searches.reverse()
|
||||
|
||||
newname = None
|
||||
if searchorder == 1:
|
||||
if obj and obj + '.' + name in objects:
|
||||
newname = obj + '.' + name
|
||||
else:
|
||||
newname = name
|
||||
else:
|
||||
if name in objects:
|
||||
newname = name
|
||||
elif obj and obj + '.' + name in objects:
|
||||
newname = obj + '.' + name
|
||||
for search_name in searches:
|
||||
if search_name in objects:
|
||||
newname = search_name
|
||||
|
||||
return newname, objects.get(newname)
|
||||
|
||||
def resolve_xref(self, env, fromdocname, builder, typ, target, node,
|
||||
contnode):
|
||||
# type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node # NOQA
|
||||
objectname = node.get('js:object')
|
||||
mod_name = node.get('js:module')
|
||||
prefix = node.get('js:object')
|
||||
searchorder = node.hasattr('refspecific') and 1 or 0
|
||||
name, obj = self.find_obj(env, objectname, target, typ, searchorder)
|
||||
name, obj = self.find_obj(env, mod_name, prefix, target, typ, searchorder)
|
||||
if not obj:
|
||||
return None
|
||||
return make_refnode(builder, fromdocname, obj[0],
|
||||
@ -239,8 +383,9 @@ class JavaScriptDomain(Domain):
|
||||
def resolve_any_xref(self, env, fromdocname, builder, target, node,
|
||||
contnode):
|
||||
# type: (BuildEnvironment, unicode, Builder, unicode, nodes.Node, nodes.Node) -> List[Tuple[unicode, nodes.Node]] # NOQA
|
||||
objectname = node.get('js:object')
|
||||
name, obj = self.find_obj(env, objectname, target, None, 1)
|
||||
mod_name = node.get('js:module')
|
||||
prefix = node.get('js:object')
|
||||
name, obj = self.find_obj(env, mod_name, prefix, target, None, 1)
|
||||
if not obj:
|
||||
return []
|
||||
return [('js:' + self.role_for_objtype(obj[1]),
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The Python domain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -96,11 +96,17 @@ def _pseudo_parse_arglist(signode, arglist):
|
||||
# This override allows our inline type specifiers to behave like :class: link
|
||||
# when it comes to handling "." and "~" prefixes.
|
||||
class PyXrefMixin(object):
|
||||
def make_xref(self, rolename, domain, target, innernode=nodes.emphasis,
|
||||
contnode=None):
|
||||
# type: (unicode, unicode, unicode, nodes.Node, nodes.Node) -> nodes.Node
|
||||
def make_xref(self,
|
||||
rolename, # type: unicode
|
||||
domain, # type: unicode
|
||||
target, # type: unicode
|
||||
innernode=nodes.emphasis, # type: nodes.Node
|
||||
contnode=None, # type: nodes.Node
|
||||
env=None, # type: BuildEnvironment
|
||||
):
|
||||
# type: (...) -> nodes.Node
|
||||
result = super(PyXrefMixin, self).make_xref(rolename, domain, target, # type: ignore
|
||||
innernode, contnode)
|
||||
innernode, contnode, env)
|
||||
result['refspecific'] = True
|
||||
if target.startswith(('.', '~')):
|
||||
prefix, result['reftarget'] = target[0], target[1:]
|
||||
@ -113,9 +119,15 @@ class PyXrefMixin(object):
|
||||
break
|
||||
return result
|
||||
|
||||
def make_xrefs(self, rolename, domain, target, innernode=nodes.emphasis,
|
||||
contnode=None):
|
||||
# type: (unicode, unicode, unicode, nodes.Node, nodes.Node) -> List[nodes.Node]
|
||||
def make_xrefs(self,
|
||||
rolename, # type: unicode
|
||||
domain, # type: unicode
|
||||
target, # type: unicode
|
||||
innernode=nodes.emphasis, # type: nodes.Node
|
||||
contnode=None, # type: nodes.Node
|
||||
env=None, # type: BuildEnvironment
|
||||
):
|
||||
# type: (...) -> List[nodes.Node]
|
||||
delims = r'(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+)'
|
||||
delims_re = re.compile(delims)
|
||||
sub_targets = re.split(delims, target)
|
||||
@ -131,7 +143,7 @@ class PyXrefMixin(object):
|
||||
results.append(contnode or innernode(sub_target, sub_target))
|
||||
else:
|
||||
results.append(self.make_xref(rolename, domain, sub_target,
|
||||
innernode, contnode))
|
||||
innernode, contnode, env))
|
||||
|
||||
return results
|
||||
|
||||
@ -151,6 +163,9 @@ class PyTypedField(PyXrefMixin, TypedField):
|
||||
class PyObject(ObjectDescription):
|
||||
"""
|
||||
Description of a general Python object.
|
||||
|
||||
:cvar allow_nesting: Class is an object that allows for nested namespaces
|
||||
:vartype allow_nesting: bool
|
||||
"""
|
||||
option_spec = {
|
||||
'noindex': directives.flag,
|
||||
@ -177,6 +192,8 @@ class PyObject(ObjectDescription):
|
||||
names=('rtype',), bodyrolename='obj'),
|
||||
]
|
||||
|
||||
allow_nesting = False
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
# type: (unicode) -> unicode
|
||||
"""May return a prefix to put before the object name in the
|
||||
@ -304,13 +321,53 @@ class PyObject(ObjectDescription):
|
||||
|
||||
def before_content(self):
|
||||
# type: () -> None
|
||||
# needed for automatic qualification of members (reset in subclasses)
|
||||
self.clsname_set = False
|
||||
"""Handle object nesting before content
|
||||
|
||||
:py:class:`PyObject` represents Python language constructs. For
|
||||
constructs that are nestable, such as a Python classes, this method will
|
||||
build up a stack of the nesting heirarchy so that it can be later
|
||||
de-nested correctly, in :py:meth:`after_content`.
|
||||
|
||||
For constructs that aren't nestable, the stack is bypassed, and instead
|
||||
only the most recent object is tracked. This object prefix name will be
|
||||
removed with :py:meth:`after_content`.
|
||||
"""
|
||||
prefix = None
|
||||
if self.names:
|
||||
# fullname and name_prefix come from the `handle_signature` method.
|
||||
# fullname represents the full object name that is constructed using
|
||||
# object nesting and explicit prefixes. `name_prefix` is the
|
||||
# explicit prefix given in a signature
|
||||
(fullname, name_prefix) = self.names[-1]
|
||||
if self.allow_nesting:
|
||||
prefix = fullname
|
||||
elif name_prefix:
|
||||
prefix = name_prefix.strip('.')
|
||||
if prefix:
|
||||
self.env.ref_context['py:class'] = prefix
|
||||
if self.allow_nesting:
|
||||
classes = self.env.ref_context.setdefault('py:classes', [])
|
||||
classes.append(prefix)
|
||||
|
||||
def after_content(self):
|
||||
# type: () -> None
|
||||
if self.clsname_set:
|
||||
self.env.ref_context.pop('py:class', None)
|
||||
"""Handle object de-nesting after content
|
||||
|
||||
If this class is a nestable object, removing the last nested class prefix
|
||||
ends further nesting in the object.
|
||||
|
||||
If this class is not a nestable object, the list of classes should not
|
||||
be altered as we didn't affect the nesting levels in
|
||||
:py:meth:`before_content`.
|
||||
"""
|
||||
classes = self.env.ref_context.setdefault('py:classes', [])
|
||||
if self.allow_nesting:
|
||||
try:
|
||||
classes.pop()
|
||||
except IndexError:
|
||||
pass
|
||||
self.env.ref_context['py:class'] = (classes[-1] if len(classes) > 0
|
||||
else None)
|
||||
|
||||
|
||||
class PyModulelevel(PyObject):
|
||||
@ -341,6 +398,8 @@ class PyClasslike(PyObject):
|
||||
Description of a class-like object (classes, interfaces, exceptions).
|
||||
"""
|
||||
|
||||
allow_nesting = True
|
||||
|
||||
def get_signature_prefix(self, sig):
|
||||
# type: (unicode) -> unicode
|
||||
return self.objtype + ' '
|
||||
@ -356,13 +415,6 @@ class PyClasslike(PyObject):
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
# type: () -> None
|
||||
PyObject.before_content(self)
|
||||
if self.names:
|
||||
self.env.ref_context['py:class'] = self.names[0][0]
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class PyClassmember(PyObject):
|
||||
"""
|
||||
@ -438,14 +490,6 @@ class PyClassmember(PyObject):
|
||||
else:
|
||||
return ''
|
||||
|
||||
def before_content(self):
|
||||
# type: () -> None
|
||||
PyObject.before_content(self)
|
||||
lastname = self.names and self.names[-1][1]
|
||||
if lastname and not self.env.ref_context.get('py:class'):
|
||||
self.env.ref_context['py:class'] = lastname.strip('.')
|
||||
self.clsname_set = True
|
||||
|
||||
|
||||
class PyDecoratorMixin(object):
|
||||
"""
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The reStructuredText domain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The standard domain.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -571,7 +571,7 @@ class StandardDomain(Domain):
|
||||
if label in self.data['citations']:
|
||||
path = env.doc2path(self.data['citations'][label][0])
|
||||
logger.warning('duplicate citation %s, other instance in %s', label, path,
|
||||
location=node)
|
||||
location=node, type='ref', subtype='citation')
|
||||
self.data['citations'][label] = (docname, node['ids'][0])
|
||||
|
||||
def note_labels(self, env, docname, document):
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Global creation environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -20,10 +20,9 @@ import warnings
|
||||
from os import path
|
||||
from collections import defaultdict
|
||||
|
||||
from six import itervalues, class_types, next
|
||||
from six import StringIO, itervalues, class_types, next
|
||||
from six.moves import cPickle as pickle
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.io import NullOutput
|
||||
from docutils.core import Publisher
|
||||
from docutils.utils import Reporter, get_source_line
|
||||
@ -35,7 +34,7 @@ from sphinx import addnodes
|
||||
from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator
|
||||
from sphinx.util.nodes import WarningStream, is_translatable, process_only_nodes
|
||||
from sphinx.util.nodes import WarningStream, is_translatable
|
||||
from sphinx.util.osutil import SEP, ensuredir
|
||||
from sphinx.util.i18n import find_catalog_files
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
@ -44,14 +43,17 @@ from sphinx.util.matching import compile_matchers
|
||||
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks
|
||||
from sphinx.util.websupport import is_commentable
|
||||
from sphinx.errors import SphinxError, ExtensionError
|
||||
from sphinx.locale import _
|
||||
from sphinx.transforms import SphinxTransformer
|
||||
from sphinx.versioning import add_uids, merge_doctrees
|
||||
from sphinx.deprecation import RemovedInSphinx20Warning
|
||||
from sphinx.deprecation import RemovedInSphinx17Warning, RemovedInSphinx20Warning
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, Iterator, List, Pattern, Set, Tuple, Type, Union # NOQA
|
||||
from typing import Any, Callable, Dict, IO, Iterator, List, Pattern, Set, Tuple, Type, Union # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.config import Config # NOQA
|
||||
@ -104,52 +106,78 @@ class BuildEnvironment(object):
|
||||
# --------- ENVIRONMENT PERSISTENCE ----------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def frompickle(srcdir, config, filename):
|
||||
# type: (unicode, Config, unicode) -> BuildEnvironment
|
||||
with open(filename, 'rb') as picklefile:
|
||||
env = pickle.load(picklefile)
|
||||
def load(f, app=None):
|
||||
# type: (IO, Sphinx) -> BuildEnvironment
|
||||
env = pickle.load(f)
|
||||
if env.version != ENV_VERSION:
|
||||
raise IOError('build environment version not current')
|
||||
if env.srcdir != srcdir:
|
||||
raise IOError('source directory has changed')
|
||||
env.config.values = config.values
|
||||
if app:
|
||||
env.app = app
|
||||
env.config.values = app.config.values
|
||||
if env.srcdir != app.srcdir:
|
||||
raise IOError('source directory has changed')
|
||||
return env
|
||||
|
||||
def topickle(self, filename):
|
||||
# type: (unicode) -> None
|
||||
@classmethod
|
||||
def loads(cls, string, app=None):
|
||||
# type: (unicode, Sphinx) -> BuildEnvironment
|
||||
io = StringIO(string)
|
||||
return cls.load(io, app)
|
||||
|
||||
@classmethod
|
||||
def frompickle(cls, filename, app):
|
||||
# type: (unicode, Sphinx) -> BuildEnvironment
|
||||
with open(filename, 'rb') as f:
|
||||
return cls.load(f, app)
|
||||
|
||||
@staticmethod
|
||||
def dump(env, f):
|
||||
# type: (BuildEnvironment, IO) -> None
|
||||
# remove unpicklable attributes
|
||||
values = self.config.values
|
||||
del self.config.values
|
||||
domains = self.domains
|
||||
del self.domains
|
||||
app = env.app
|
||||
del env.app
|
||||
values = env.config.values
|
||||
del env.config.values
|
||||
domains = env.domains
|
||||
del env.domains
|
||||
# remove potentially pickling-problematic values from config
|
||||
for key, val in list(vars(self.config).items()):
|
||||
for key, val in list(vars(env.config).items()):
|
||||
if key.startswith('_') or \
|
||||
isinstance(val, types.ModuleType) or \
|
||||
isinstance(val, types.FunctionType) or \
|
||||
isinstance(val, class_types):
|
||||
del self.config[key]
|
||||
with open(filename, 'wb') as picklefile:
|
||||
pickle.dump(self, picklefile, pickle.HIGHEST_PROTOCOL)
|
||||
del env.config[key]
|
||||
pickle.dump(env, f, pickle.HIGHEST_PROTOCOL)
|
||||
# reset attributes
|
||||
self.domains = domains
|
||||
self.config.values = values
|
||||
env.domains = domains
|
||||
env.config.values = values
|
||||
env.app = app
|
||||
|
||||
@classmethod
|
||||
def dumps(cls, env):
|
||||
# type: (BuildEnvironment) -> unicode
|
||||
io = StringIO()
|
||||
cls.dump(env, io)
|
||||
return io.getvalue()
|
||||
|
||||
def topickle(self, filename):
|
||||
# type: (unicode) -> None
|
||||
with open(filename, 'wb') as f:
|
||||
self.dump(self, f)
|
||||
|
||||
# --------- ENVIRONMENT INITIALIZATION -------------------------------------
|
||||
|
||||
def __init__(self, srcdir, doctreedir, config):
|
||||
# type: (unicode, unicode, Config) -> None
|
||||
self.doctreedir = doctreedir
|
||||
self.srcdir = srcdir # type: unicode
|
||||
self.config = config # type: Config
|
||||
def __init__(self, app):
|
||||
# type: (Sphinx) -> None
|
||||
self.app = app
|
||||
self.doctreedir = app.doctreedir
|
||||
self.srcdir = app.srcdir
|
||||
self.config = app.config
|
||||
|
||||
# the method of doctree versioning; see set_versioning_method
|
||||
self.versioning_condition = None # type: Union[bool, Callable]
|
||||
self.versioning_compare = None # type: bool
|
||||
|
||||
# the application object; only set while update() runs
|
||||
self.app = None # type: Sphinx
|
||||
|
||||
# all the registered domains, set by the application
|
||||
self.domains = {}
|
||||
|
||||
@ -378,15 +406,15 @@ class BuildEnvironment(object):
|
||||
enc_rel_fn = rel_fn.encode(sys.getfilesystemencoding())
|
||||
return rel_fn, path.abspath(path.join(self.srcdir, enc_rel_fn))
|
||||
|
||||
def find_files(self, config, buildername):
|
||||
# type: (Config, unicode) -> None
|
||||
def find_files(self, config, builder):
|
||||
# type: (Config, Builder) -> None
|
||||
"""Find all source files in the source dir and put them in
|
||||
self.found_docs.
|
||||
"""
|
||||
matchers = compile_matchers(
|
||||
config.exclude_patterns[:] +
|
||||
config.templates_path +
|
||||
config.html_extra_path +
|
||||
builder.get_asset_paths() +
|
||||
['**/_sources', '.#*', '**/.#*', '*.lproj/**']
|
||||
)
|
||||
self.found_docs = set()
|
||||
@ -403,7 +431,7 @@ class BuildEnvironment(object):
|
||||
# is set for the doc source and the mo file, it is processed again from
|
||||
# the reading phase when mo is updated. In the future, we would like to
|
||||
# move i18n process into the writing phase, and remove these lines.
|
||||
if buildername != 'gettext':
|
||||
if builder.use_message_catalog:
|
||||
# add catalog mo file dependency
|
||||
for docname in self.found_docs:
|
||||
catalog_files = find_catalog_files(
|
||||
@ -466,8 +494,8 @@ class BuildEnvironment(object):
|
||||
|
||||
return added, changed, removed
|
||||
|
||||
def update(self, config, srcdir, doctreedir, app):
|
||||
# type: (Config, unicode, unicode, Sphinx) -> List[unicode]
|
||||
def update(self, config, srcdir, doctreedir):
|
||||
# type: (Config, unicode, unicode) -> List[unicode]
|
||||
"""(Re-)read all files new or changed since last update.
|
||||
|
||||
Store all environment docnames in the canonical format (ie using SEP as
|
||||
@ -495,7 +523,7 @@ class BuildEnvironment(object):
|
||||
# the source and doctree directories may have been relocated
|
||||
self.srcdir = srcdir
|
||||
self.doctreedir = doctreedir
|
||||
self.find_files(config, app.buildername)
|
||||
self.find_files(config, self.app.builder)
|
||||
self.config = config
|
||||
|
||||
# this cache also needs to be updated every time
|
||||
@ -506,7 +534,7 @@ class BuildEnvironment(object):
|
||||
added, changed, removed = self.get_outdated_files(config_changed)
|
||||
|
||||
# allow user intervention as well
|
||||
for docs in app.emit('env-get-outdated', self, added, changed, removed):
|
||||
for docs in self.app.emit('env-get-outdated', self, added, changed, removed):
|
||||
changed.update(set(docs) & self.found_docs)
|
||||
|
||||
# if files were added or removed, all documents with globbed toctrees
|
||||
@ -519,49 +547,43 @@ class BuildEnvironment(object):
|
||||
len(removed))
|
||||
logger.info(msg)
|
||||
|
||||
self.app = app
|
||||
|
||||
# clear all files no longer present
|
||||
for docname in removed:
|
||||
app.emit('env-purge-doc', self, docname)
|
||||
self.app.emit('env-purge-doc', self, docname)
|
||||
self.clear_doc(docname)
|
||||
|
||||
# read all new and changed files
|
||||
docnames = sorted(added | changed)
|
||||
# allow changing and reordering the list of docs to read
|
||||
app.emit('env-before-read-docs', self, docnames)
|
||||
self.app.emit('env-before-read-docs', self, docnames)
|
||||
|
||||
# check if we should do parallel or serial read
|
||||
par_ok = False
|
||||
if parallel_available and len(docnames) > 5 and app.parallel > 1:
|
||||
par_ok = True
|
||||
for extname, md in app._extension_metadata.items():
|
||||
ext_ok = md.get('parallel_read_safe')
|
||||
if ext_ok:
|
||||
continue
|
||||
if ext_ok is None:
|
||||
logger.warning('the %s extension does not declare if it '
|
||||
'is safe for parallel reading, assuming it '
|
||||
'isn\'t - please ask the extension author to '
|
||||
'check and make it explicit', extname)
|
||||
if parallel_available and len(docnames) > 5 and self.app.parallel > 1:
|
||||
for ext in itervalues(self.app.extensions):
|
||||
if ext.parallel_read_safe is None:
|
||||
logger.warning(_('the %s extension does not declare if it is safe '
|
||||
'for parallel reading, assuming it isn\'t - please '
|
||||
'ask the extension author to check and make it '
|
||||
'explicit'), ext.name)
|
||||
logger.warning('doing serial read')
|
||||
else:
|
||||
logger.warning('the %s extension is not safe for parallel '
|
||||
'reading, doing serial read', extname)
|
||||
par_ok = False
|
||||
break
|
||||
break
|
||||
elif ext.parallel_read_safe is False:
|
||||
break
|
||||
else:
|
||||
# all extensions support parallel-read
|
||||
par_ok = True
|
||||
|
||||
if par_ok:
|
||||
self._read_parallel(docnames, app, nproc=app.parallel)
|
||||
self._read_parallel(docnames, self.app, nproc=self.app.parallel)
|
||||
else:
|
||||
self._read_serial(docnames, app)
|
||||
self._read_serial(docnames, self.app)
|
||||
|
||||
if config.master_doc not in self.all_docs:
|
||||
raise SphinxError('master file %s not found' %
|
||||
self.doc2path(config.master_doc))
|
||||
|
||||
self.app = None
|
||||
|
||||
for retval in app.emit('env-updated', self):
|
||||
for retval in self.app.emit('env-updated', self):
|
||||
if retval is not None:
|
||||
docnames.extend(retval)
|
||||
|
||||
@ -584,20 +606,17 @@ class BuildEnvironment(object):
|
||||
self.clear_doc(docname)
|
||||
|
||||
def read_process(docs):
|
||||
# type: (List[unicode]) -> BuildEnvironment
|
||||
# type: (List[unicode]) -> unicode
|
||||
self.app = app
|
||||
for docname in docs:
|
||||
self.read_doc(docname, app)
|
||||
# allow pickling self to send it back
|
||||
del self.app
|
||||
del self.domains
|
||||
del self.config.values
|
||||
del self.config
|
||||
return self
|
||||
return BuildEnvironment.dumps(self)
|
||||
|
||||
def merge(docs, otherenv):
|
||||
# type: (List[unicode], BuildEnvironment) -> None
|
||||
self.merge_info_from(docs, otherenv, app)
|
||||
# type: (List[unicode], unicode) -> None
|
||||
env = BuildEnvironment.loads(otherenv)
|
||||
self.merge_info_from(docs, env, app)
|
||||
|
||||
tasks = ParallelTasks(nproc)
|
||||
chunks = make_chunks(docnames, nproc)
|
||||
@ -748,18 +767,18 @@ class BuildEnvironment(object):
|
||||
def currmodule(self):
|
||||
# type: () -> None
|
||||
"""Backwards compatible alias. Will be removed."""
|
||||
logger.warning('env.currmodule is being referenced by an '
|
||||
'extension; this API will be removed in the future',
|
||||
location=self.docname)
|
||||
warnings.warn('env.currmodule is deprecated. '
|
||||
'Use env.ref_context["py:module"] instead.',
|
||||
RemovedInSphinx17Warning)
|
||||
return self.ref_context.get('py:module')
|
||||
|
||||
@property
|
||||
def currclass(self):
|
||||
# type: () -> None
|
||||
"""Backwards compatible alias. Will be removed."""
|
||||
logger.warning('env.currclass is being referenced by an '
|
||||
'extension; this API will be removed in the future',
|
||||
location=self.docname)
|
||||
warnings.warn('env.currclass is deprecated. '
|
||||
'Use env.ref_context["py:class"] instead.',
|
||||
RemovedInSphinx17Warning)
|
||||
return self.ref_context.get('py:class')
|
||||
|
||||
def new_serialno(self, category=''):
|
||||
@ -867,7 +886,7 @@ class BuildEnvironment(object):
|
||||
doctree = self.get_doctree(docname)
|
||||
|
||||
# resolve all pending cross-references
|
||||
self.resolve_references(doctree, docname, builder)
|
||||
self.apply_post_transforms(doctree, docname)
|
||||
|
||||
# now, resolve all toctree nodes
|
||||
for toctreenode in doctree.traverse(addnodes.toctree):
|
||||
@ -901,113 +920,25 @@ class BuildEnvironment(object):
|
||||
|
||||
def resolve_references(self, doctree, fromdocname, builder):
|
||||
# type: (nodes.Node, unicode, Builder) -> None
|
||||
for node in doctree.traverse(addnodes.pending_xref):
|
||||
contnode = node[0].deepcopy()
|
||||
newnode = None
|
||||
self.apply_post_transforms(doctree, fromdocname)
|
||||
|
||||
typ = node['reftype']
|
||||
target = node['reftarget']
|
||||
refdoc = node.get('refdoc', fromdocname)
|
||||
domain = None
|
||||
def apply_post_transforms(self, doctree, docname):
|
||||
# type: (nodes.Node, unicode) -> None
|
||||
"""Apply all post-transforms."""
|
||||
try:
|
||||
# set env.docname during applying post-transforms
|
||||
self.temp_data['docname'] = docname
|
||||
if hasattr(doctree, 'settings'):
|
||||
doctree.settings.env = self
|
||||
|
||||
try:
|
||||
if 'refdomain' in node and node['refdomain']:
|
||||
# let the domain try to resolve the reference
|
||||
try:
|
||||
domain = self.domains[node['refdomain']]
|
||||
except KeyError:
|
||||
raise NoUri
|
||||
newnode = domain.resolve_xref(self, refdoc, builder,
|
||||
typ, target, node, contnode)
|
||||
# really hardwired reference types
|
||||
elif typ == 'any':
|
||||
newnode = self._resolve_any_reference(builder, refdoc, node, contnode)
|
||||
# no new node found? try the missing-reference event
|
||||
if newnode is None:
|
||||
newnode = builder.app.emit_firstresult(
|
||||
'missing-reference', self, node, contnode)
|
||||
# still not found? warn if node wishes to be warned about or
|
||||
# we are in nit-picky mode
|
||||
if newnode is None:
|
||||
self._warn_missing_reference(refdoc, typ, target, node, domain)
|
||||
except NoUri:
|
||||
newnode = contnode
|
||||
node.replace_self(newnode or contnode)
|
||||
|
||||
# remove only-nodes that do not belong to our builder
|
||||
process_only_nodes(doctree, builder.tags)
|
||||
transformer = SphinxTransformer(doctree)
|
||||
transformer.add_transforms(self.app.post_transforms)
|
||||
transformer.apply_transforms()
|
||||
finally:
|
||||
self.temp_data.clear()
|
||||
|
||||
# allow custom references to be resolved
|
||||
builder.app.emit('doctree-resolved', doctree, fromdocname)
|
||||
|
||||
def _warn_missing_reference(self, refdoc, typ, target, node, domain):
|
||||
# type: (unicode, unicode, unicode, nodes.Node, Domain) -> None
|
||||
warn = node.get('refwarn')
|
||||
if self.config.nitpicky:
|
||||
warn = True
|
||||
if self._nitpick_ignore:
|
||||
dtype = domain and '%s:%s' % (domain.name, typ) or typ
|
||||
if (dtype, target) in self._nitpick_ignore:
|
||||
warn = False
|
||||
# for "std" types also try without domain name
|
||||
if (not domain or domain.name == 'std') and \
|
||||
(typ, target) in self._nitpick_ignore:
|
||||
warn = False
|
||||
if not warn:
|
||||
return
|
||||
if domain and typ in domain.dangling_warnings:
|
||||
msg = domain.dangling_warnings[typ]
|
||||
elif node.get('refdomain', 'std') not in ('', 'std'):
|
||||
msg = '%s:%s reference target not found: %%(target)s' % \
|
||||
(node['refdomain'], typ)
|
||||
else:
|
||||
msg = '%r reference target not found: %%(target)s' % typ
|
||||
logger.warning(msg % {'target': target},
|
||||
location=node, type='ref', subtype=typ)
|
||||
|
||||
def _resolve_any_reference(self, builder, refdoc, node, contnode):
|
||||
# type: (Builder, unicode, nodes.Node, nodes.Node) -> nodes.Node
|
||||
"""Resolve reference generated by the "any" role."""
|
||||
target = node['reftarget']
|
||||
results = [] # type: List[Tuple[unicode, nodes.Node]]
|
||||
# first, try resolving as :doc:
|
||||
doc_ref = self.domains['std'].resolve_xref(self, refdoc, builder, 'doc',
|
||||
target, node, contnode)
|
||||
if doc_ref:
|
||||
results.append(('doc', doc_ref))
|
||||
# next, do the standard domain (makes this a priority)
|
||||
results.extend(self.domains['std'].resolve_any_xref(
|
||||
self, refdoc, builder, target, node, contnode))
|
||||
for domain in self.domains.values():
|
||||
if domain.name == 'std':
|
||||
continue # we did this one already
|
||||
try:
|
||||
results.extend(domain.resolve_any_xref(self, refdoc, builder,
|
||||
target, node, contnode))
|
||||
except NotImplementedError:
|
||||
# the domain doesn't yet support the new interface
|
||||
# we have to manually collect possible references (SLOW)
|
||||
for role in domain.roles:
|
||||
res = domain.resolve_xref(self, refdoc, builder, role, target,
|
||||
node, contnode)
|
||||
if res and isinstance(res[0], nodes.Element):
|
||||
results.append(('%s:%s' % (domain.name, role), res))
|
||||
# now, see how many matches we got...
|
||||
if not results:
|
||||
return None
|
||||
if len(results) > 1:
|
||||
nice_results = ' or '.join(':%s:' % r[0] for r in results)
|
||||
logger.warning('more than one target found for \'any\' cross-'
|
||||
'reference %r: could be %s', target, nice_results,
|
||||
location=node)
|
||||
res_role, newnode = results[0]
|
||||
# Override "any" class with the actual role type to get the styling
|
||||
# approximately correct.
|
||||
res_domain = res_role.split(':')[0]
|
||||
if newnode and newnode[0].get('classes'):
|
||||
newnode[0]['classes'].append(res_domain)
|
||||
newnode[0]['classes'].append(res_role.replace(':', '-'))
|
||||
return newnode
|
||||
self.app.emit('doctree-resolved', doctree, docname)
|
||||
|
||||
def create_index(self, builder, group_entries=True,
|
||||
_fixre=re.compile(r'(.*) ([(][^()]*[)])')):
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
Sphinx environment adapters
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Index entries adapters for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import re
|
||||
@ -13,10 +13,10 @@ import bisect
|
||||
import unicodedata
|
||||
from itertools import groupby
|
||||
|
||||
from six import text_type
|
||||
from six import text_type, iteritems
|
||||
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import iteritems, split_into, logging
|
||||
from sphinx.util import split_into, logging
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Toctree adapter for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -15,7 +15,7 @@ from docutils import nodes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.util import url_re, logging
|
||||
from sphinx.util.nodes import clean_astext, process_only_nodes
|
||||
from sphinx.util.nodes import clean_astext
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -158,7 +158,7 @@ class TocTree(object):
|
||||
maxdepth = self.env.metadata[ref].get('tocdepth', 0)
|
||||
if ref not in toctree_ancestors or (prune and maxdepth > 0):
|
||||
self._toctree_prune(toc, 2, maxdepth, collapse)
|
||||
process_only_nodes(toc, builder.tags)
|
||||
self.process_only_nodes(toc)
|
||||
if title and toc.children and len(toc.children) == 1:
|
||||
child = toc.children[0]
|
||||
for refnode in child.traverse(nodes.reference):
|
||||
@ -298,7 +298,7 @@ class TocTree(object):
|
||||
# the document does not exist anymore: return a dummy node that
|
||||
# renders to nothing
|
||||
return nodes.paragraph()
|
||||
process_only_nodes(toc, builder.tags)
|
||||
self.process_only_nodes(toc)
|
||||
for node in toc.traverse(nodes.reference):
|
||||
node['refuri'] = node['anchorname'] or '#'
|
||||
return toc
|
||||
@ -323,3 +323,14 @@ class TocTree(object):
|
||||
for toctree in toctrees[1:]:
|
||||
result.extend(toctree.children)
|
||||
return result
|
||||
|
||||
def process_only_nodes(self, doctree):
|
||||
# type: (nodes.Node) -> None
|
||||
# Lazy loading
|
||||
from sphinx.transforms import SphinxTransformer
|
||||
from sphinx.transforms.post_transforms import OnlyNodeTransform
|
||||
|
||||
transformer = SphinxTransformer(doctree)
|
||||
transformer.set_environment(self.env)
|
||||
transformer.add_transform(OnlyNodeTransform)
|
||||
transformer.apply_transforms()
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The data collector components for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The image collector for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -143,6 +143,12 @@ class DownloadFileCollector(EnvironmentCollector):
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> None
|
||||
# type: (Sphinx) -> Dict
|
||||
app.add_env_collector(ImageCollector)
|
||||
app.add_env_collector(DownloadFileCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The dependencies collector components for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -18,7 +18,7 @@ from sphinx.environment.collectors import EnvironmentCollector
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Set # NOQA
|
||||
from typing import Dict, Set # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.sphinx import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
@ -56,5 +56,11 @@ class DependenciesCollector(EnvironmentCollector):
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> None
|
||||
# type: (Sphinx) -> Dict
|
||||
app.add_env_collector(DependenciesCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Index entries collector for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -15,7 +15,7 @@ from sphinx.environment.collectors import EnvironmentCollector
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Set # NOQA
|
||||
from typing import Dict, Set # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.applicatin import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
@ -56,5 +56,11 @@ class IndexEntriesCollector(EnvironmentCollector):
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> None
|
||||
# type: (Sphinx) -> Dict
|
||||
app.add_env_collector(IndexEntriesCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The metadata collector components for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -15,7 +15,7 @@ from sphinx.environment.collectors import EnvironmentCollector
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Set # NOQA
|
||||
from typing import Dict, Set # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.sphinx import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
@ -69,5 +69,11 @@ class MetadataCollector(EnvironmentCollector):
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> None
|
||||
# type: (Sphinx) -> Dict
|
||||
app.add_env_collector(MetadataCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
The title collector components for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -16,7 +16,7 @@ from sphinx.transforms import SphinxContentsFilter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Set # NOQA
|
||||
from typing import Dict, Set # NOQA
|
||||
from docutils import nodes # NOQA
|
||||
from sphinx.sphinx import Sphinx # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
@ -62,5 +62,11 @@ class TitleCollector(EnvironmentCollector):
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> None
|
||||
# type: (Sphinx) -> Dict
|
||||
app.add_env_collector(TitleCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Toctree collector for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -284,5 +284,11 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
|
||||
|
||||
def setup(app):
|
||||
# type: (Sphinx) -> None
|
||||
# type: (Sphinx) -> Dict
|
||||
app.add_env_collector(TocTreeCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
Contains SphinxError and a few subclasses (in an extra module to avoid
|
||||
circular import problems).
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
86
sphinx/events.py
Normal file
86
sphinx/events.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.events
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Sphinx core events.
|
||||
|
||||
Gracefully adapted from the TextPress system by Armin.
|
||||
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from collections import OrderedDict, defaultdict
|
||||
|
||||
from six import itervalues
|
||||
|
||||
from sphinx.errors import ExtensionError
|
||||
from sphinx.locale import _
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, List # NOQA
|
||||
|
||||
|
||||
# List of all known core events. Maps name to arguments description.
|
||||
core_events = {
|
||||
'builder-inited': '',
|
||||
'env-get-outdated': 'env, added, changed, removed',
|
||||
'env-get-updated': 'env',
|
||||
'env-purge-doc': 'env, docname',
|
||||
'env-before-read-docs': 'env, docnames',
|
||||
'source-read': 'docname, source text',
|
||||
'doctree-read': 'the doctree before being pickled',
|
||||
'env-merge-info': 'env, read docnames, other env instance',
|
||||
'missing-reference': 'env, node, contnode',
|
||||
'doctree-resolved': 'doctree, docname',
|
||||
'env-updated': 'env',
|
||||
'html-collect-pages': 'builder',
|
||||
'html-page-context': 'pagename, context, doctree or None',
|
||||
'build-finished': 'exception',
|
||||
} # type: Dict[unicode, unicode]
|
||||
|
||||
|
||||
class EventManager(object):
|
||||
def __init__(self):
|
||||
# type: () -> None
|
||||
self.events = core_events.copy()
|
||||
self.listeners = defaultdict(OrderedDict) # type: Dict[unicode, Dict[int, Callable]]
|
||||
self.next_listener_id = 0
|
||||
|
||||
def add(self, name):
|
||||
# type: (unicode) -> None
|
||||
if name in self.events:
|
||||
raise ExtensionError(_('Event %r already present') % name)
|
||||
self.events[name] = ''
|
||||
|
||||
def connect(self, name, callback):
|
||||
# type: (unicode, Callable) -> int
|
||||
if name not in self.events:
|
||||
raise ExtensionError(_('Unknown event name: %s') % name)
|
||||
|
||||
listener_id = self.next_listener_id
|
||||
self.next_listener_id += 1
|
||||
self.listeners[name][listener_id] = callback
|
||||
return listener_id
|
||||
|
||||
def disconnect(self, listener_id):
|
||||
# type: (int) -> None
|
||||
for event in itervalues(self.listeners):
|
||||
event.pop(listener_id, None)
|
||||
|
||||
def emit(self, name, *args):
|
||||
# type: (unicode, Any) -> List
|
||||
results = []
|
||||
for callback in itervalues(self.listeners[name]):
|
||||
results.append(callback(*args))
|
||||
return results
|
||||
|
||||
def emit_firstresult(self, name, *args):
|
||||
# type: (unicode, Any) -> Any
|
||||
for result in self.emit(name, *args):
|
||||
if result is not None:
|
||||
return result
|
||||
return None
|
@ -5,6 +5,6 @@
|
||||
|
||||
Contains Sphinx features not activated by default.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
@ -7,7 +7,7 @@
|
||||
the doctree, thus avoiding duplication between docstrings and documentation
|
||||
for those who like elaborate docstrings.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Allow reference sections by :ref: role using its title.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
resolved to a Python object, and otherwise it becomes simple emphasis.
|
||||
This can be used as the default role to make links 'smart'.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
generate:
|
||||
sphinx-autogen -o source/generated source/*.rst
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
@ -34,6 +34,7 @@ from sphinx.ext.autosummary import import_by_name, get_documenter
|
||||
from sphinx.jinja2glue import BuiltinTemplateLoader
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.inspect import safe_getattr
|
||||
from sphinx.util.rst import escape as rst_escape
|
||||
|
||||
# Add documenters to AutoDirective registry
|
||||
from sphinx.ext.autodoc import add_documenter, \
|
||||
@ -95,6 +96,12 @@ def _simple_warn(msg):
|
||||
print('WARNING: ' + msg, file=sys.stderr)
|
||||
|
||||
|
||||
def _underline(title, line='='):
|
||||
if '\n' in title:
|
||||
raise ValueError('Can only underline single lines')
|
||||
return title + '\n' + line * len(title)
|
||||
|
||||
|
||||
# -- Generating output ---------------------------------------------------------
|
||||
|
||||
def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
@ -130,6 +137,11 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
template_dirs.insert(0, template_dir)
|
||||
template_loader = FileSystemLoader(template_dirs) # type: ignore
|
||||
template_env = SandboxedEnvironment(loader=template_loader)
|
||||
template_env.filters['underline'] = _underline
|
||||
|
||||
# replace the builtin html filters
|
||||
template_env.filters['escape'] = rst_escape
|
||||
template_env.filters['e'] = rst_escape
|
||||
|
||||
# read
|
||||
items = find_autosummary_in_files(sources)
|
||||
|
@ -1,5 +1,4 @@
|
||||
{{ fullname }}
|
||||
{{ underline }}
|
||||
{{ fullname | escape | underline}}
|
||||
|
||||
.. currentmodule:: {{ module }}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
{{ fullname }}
|
||||
{{ underline }}
|
||||
{{ fullname | escape | underline}}
|
||||
|
||||
.. currentmodule:: {{ module }}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
{{ fullname }}
|
||||
{{ underline }}
|
||||
{{ fullname | escape | underline}}
|
||||
|
||||
.. automodule:: {{ fullname }}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
Check Python modules and C API for coverage. Mostly written by Josip
|
||||
Dzolonga for the Google Highly Open Participation contest.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
Mimic doctest by automatically executing code snippets and checking
|
||||
their results.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
You can also give an explicit caption, e.g. :exmpl:`Foo <foo>`.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
To publish HTML docs at GitHub Pages, create .nojekyll file.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
Allow graphviz-formatted graphs to be included in Sphinx-generated
|
||||
documents inline.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
namespace of the project configuration (that is, all variables from
|
||||
``conf.py`` are available.)
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Render math in HTML via dvipng or dvisvgm.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -32,7 +32,7 @@ r"""
|
||||
The graph is inserted as a PNG+image map into HTML and a PDF in
|
||||
LaTeX.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -20,12 +20,13 @@
|
||||
also be specified individually, e.g. if the docs should be buildable
|
||||
without Internet access.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import time
|
||||
import functools
|
||||
import posixpath
|
||||
@ -340,17 +341,27 @@ def setup(app):
|
||||
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# debug functionality to print out an inventory
|
||||
import sys
|
||||
def debug(argv):
|
||||
# type: (List[unicode]) -> None
|
||||
"""Debug functionality to print out an inventory"""
|
||||
if len(argv) < 2:
|
||||
print("Print out an inventory file.\n"
|
||||
"Error: must specify local path or URL to an inventory file.",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
class MockConfig(object):
|
||||
intersphinx_timeout = None # type: int
|
||||
tls_verify = False
|
||||
|
||||
class MockApp(object):
|
||||
srcdir = ''
|
||||
config = MockConfig()
|
||||
|
||||
def warn(self, msg):
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
filename = sys.argv[1]
|
||||
filename = argv[1]
|
||||
invdata = fetch_inventory(MockApp(), '', filename) # type: ignore
|
||||
for key in sorted(invdata or {}):
|
||||
print(key)
|
||||
@ -358,3 +369,10 @@ if __name__ == '__main__':
|
||||
print('\t%-40s %s%s' % (entry,
|
||||
einfo[3] != '-' and '%-40s: ' % einfo[3] or '',
|
||||
einfo[2]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import logging # type: ignore
|
||||
logging.basicConfig()
|
||||
|
||||
debug(argv=sys.argv) # type: ignore
|
||||
|
@ -6,7 +6,7 @@
|
||||
Set up everything for use of JSMath to display math in HTML
|
||||
via JavaScript.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Add external links to module code in Python object descriptions.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Set up math support in source files and LaTeX/text output.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
Sphinx's HTML writer -- requires the MathJax JavaScript library on your
|
||||
webserver/computer.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
@ -74,7 +74,7 @@ def setup(app):
|
||||
# more information for mathjax secure url is here:
|
||||
# http://docs.mathjax.org/en/latest/start.html#secure-access-to-the-cdn
|
||||
app.add_config_value('mathjax_path',
|
||||
'https://cdn.mathjax.org/mathjax/latest/MathJax.js?'
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?'
|
||||
'config=TeX-AMS-MML_HTMLorMML', False)
|
||||
app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
|
||||
app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Support for NumPy and Google style docstrings.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
Classes for docstring parsing and formatting.
|
||||
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
A collection of helpful iterators.
|
||||
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
Render math in HTML via dvipng. This extension has been deprecated; please
|
||||
use sphinx.ext.imgmath instead.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
all todos of your project and lists them along with a backlink to the
|
||||
original location.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Add links to module code in Python object descriptions.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
120
sphinx/extension.py
Normal file
120
sphinx/extension.py
Normal file
@ -0,0 +1,120 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
sphinx.extension
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Utilities for Sphinx extensions.
|
||||
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import traceback
|
||||
|
||||
from six import iteritems
|
||||
|
||||
from sphinx.errors import ExtensionError, VersionRequirementError
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import logging
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict # NOQA
|
||||
from sphinx.application import Sphinx # NOQA
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# list of deprecated extensions. Keys are extension name.
|
||||
# Values are Sphinx version that merge the extension.
|
||||
EXTENSION_BLACKLIST = {
|
||||
"sphinxjp.themecore": "1.2"
|
||||
} # type: Dict[unicode, unicode]
|
||||
|
||||
|
||||
class Extension(object):
|
||||
def __init__(self, name, module, **kwargs):
|
||||
self.name = name
|
||||
self.module = module
|
||||
self.metadata = kwargs
|
||||
self.version = kwargs.pop('version', 'unknown version')
|
||||
|
||||
# The extension supports parallel read or not. The default value
|
||||
# is ``None``. It means the extension does not tell the status.
|
||||
# It will be warned on parallel reading.
|
||||
self.parallel_read_safe = kwargs.pop('parallel_read_safe', None)
|
||||
|
||||
# The extension supports parallel write or not. The default value
|
||||
# is ``True``. Sphinx writes parallelly documents even if
|
||||
# the extension does not tell its status.
|
||||
self.parallel_write_safe = kwargs.pop('parallel_read_safe', True)
|
||||
|
||||
|
||||
def load_extension(app, extname):
|
||||
# type: (Sphinx, unicode) -> None
|
||||
"""Load a Sphinx extension."""
|
||||
if extname in app.extensions: # alread loaded
|
||||
return
|
||||
if extname in EXTENSION_BLACKLIST:
|
||||
logger.warning(_('the extension %r was already merged with Sphinx since '
|
||||
'version %s; this extension is ignored.'),
|
||||
extname, EXTENSION_BLACKLIST[extname])
|
||||
return
|
||||
|
||||
# update loading context
|
||||
app._setting_up_extension.append(extname)
|
||||
|
||||
try:
|
||||
mod = __import__(extname, None, None, ['setup'])
|
||||
except ImportError as err:
|
||||
logger.verbose(_('Original exception:\n') + traceback.format_exc())
|
||||
raise ExtensionError(_('Could not import extension %s') % extname, err)
|
||||
|
||||
if not hasattr(mod, 'setup'):
|
||||
logger.warning(_('extension %r has no setup() function; is it really '
|
||||
'a Sphinx extension module?'), extname)
|
||||
metadata = {} # type: Dict[unicode, Any]
|
||||
else:
|
||||
try:
|
||||
metadata = mod.setup(app)
|
||||
except VersionRequirementError as err:
|
||||
# add the extension name to the version required
|
||||
raise VersionRequirementError(
|
||||
_('The %s extension used by this project needs at least '
|
||||
'Sphinx v%s; it therefore cannot be built with this '
|
||||
'version.') % (extname, err)
|
||||
)
|
||||
|
||||
if metadata is None:
|
||||
metadata = {}
|
||||
if extname == 'rst2pdf.pdfbuilder':
|
||||
metadata['parallel_read_safe'] = True
|
||||
elif not isinstance(metadata, dict):
|
||||
logger.warning(_('extension %r returned an unsupported object from '
|
||||
'its setup() function; it should return None or a '
|
||||
'metadata dictionary'), extname)
|
||||
|
||||
app.extensions[extname] = Extension(extname, mod, **metadata)
|
||||
app._setting_up_extension.pop()
|
||||
|
||||
|
||||
def verify_required_extensions(app, requirements):
|
||||
# type: (Sphinx, Dict[unicode, unicode]) -> None
|
||||
"""Verify the required Sphinx extensions are loaded."""
|
||||
if requirements is None:
|
||||
return
|
||||
|
||||
for extname, reqversion in iteritems(requirements):
|
||||
extension = app.extensions.get(extname)
|
||||
if extension is None:
|
||||
logger.warning(_('needs_extensions config value specifies a '
|
||||
'version requirement for extension %s, but it is '
|
||||
'not loaded'), extname)
|
||||
continue
|
||||
|
||||
if extension.version == 'unknown version' or reqversion > extension.version:
|
||||
raise VersionRequirementError(_('This project needs the extension %s at least in '
|
||||
'version %s and therefore cannot be built with '
|
||||
'the loaded version (%s).') %
|
||||
(extname, reqversion, extension.version))
|
@ -5,7 +5,7 @@
|
||||
|
||||
Highlight code blocks using Pygments.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Input/Output files
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from docutils.io import FileInput
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
Glue code for the jinja2 templating engine.
|
||||
|
||||
:copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
|
||||
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user