Merge branch 'master' into body-width

This commit is contained in:
Takeshi KOMIYA 2018-01-15 10:19:01 +09:00 committed by GitHub
commit 1d0a087f75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
122 changed files with 1863 additions and 1168 deletions

View File

@ -6,19 +6,12 @@ environment:
matrix: matrix:
- PYTHON: 27 - PYTHON: 27
DOCUTILS: 0.13.1
TEST_IGNORE: --ignore py35
- PYTHON: 27
DOCUTILS: 0.14
TEST_IGNORE: --ignore py35 TEST_IGNORE: --ignore py35
- PYTHON: 36 - PYTHON: 36
DOCUTILS: 0.14
- PYTHON: 36-x64 - PYTHON: 36-x64
DOCUTILS: 0.14
install: install:
- C:\Python%PYTHON%\python.exe -m pip install -U pip setuptools - C:\Python%PYTHON%\python.exe -m pip install -U pip setuptools
- C:\Python%PYTHON%\python.exe -m pip install docutils==%DOCUTILS% mock
- C:\Python%PYTHON%\python.exe -m pip install .[test,websupport] - C:\Python%PYTHON%\python.exe -m pip install .[test,websupport]
# No automatic build, just run python tests # No automatic build, just run python tests

View File

@ -6,7 +6,6 @@ cache: pip
env: env:
global: global:
- PYTHONFAULTHANDLER=x - PYTHONFAULTHANDLER=x
- PYTHONWARNINGS=all
- SKIP_LATEX_BUILD=1 - SKIP_LATEX_BUILD=1
matrix: matrix:

View File

@ -18,6 +18,7 @@ Other co-maintainers:
Other contributors, listed alphabetically, are: Other contributors, listed alphabetically, are:
* Alastair Houghton -- Apple Help builder * Alastair Houghton -- Apple Help builder
* Alexander Todorov -- inheritance_diagram tests and improvements
* Andi Albrecht -- agogo theme * Andi Albrecht -- agogo theme
* Jakob Lykke Andersen -- Rewritten C++ domain * Jakob Lykke Andersen -- Rewritten C++ domain
* Henrique Bastos -- SVG support for graphviz extension * Henrique Bastos -- SVG support for graphviz extension
@ -68,6 +69,7 @@ Other contributors, listed alphabetically, are:
* Barry Warsaw -- setup command improvements * Barry Warsaw -- setup command improvements
* Sebastian Wiesner -- image handling, distutils support * Sebastian Wiesner -- image handling, distutils support
* Michael Wilson -- Intersphinx HTTP basic auth support * Michael Wilson -- Intersphinx HTTP basic auth support
* Matthew Woodcraft -- text output improvements
* Joel Wurtz -- cellspanning support in LaTeX * Joel Wurtz -- cellspanning support in LaTeX
* Hong Xu -- svg support in imgmath extension and various bug fixes * Hong Xu -- svg support in imgmath extension and various bug fixes
* Stephen Finucane -- setup command improvements and documentation * Stephen Finucane -- setup command improvements and documentation

71
CHANGES
View File

@ -1,6 +1,11 @@
Release 1.7 (in development) Release 1.7 (in development)
============================ ============================
Dependencies
------------
* Add ``packaging`` package
Incompatible changes Incompatible changes
-------------------- --------------------
@ -13,6 +18,15 @@ Incompatible changes
* #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc * #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc
* #4226: apidoc: Generate new style makefile (make-mode) * #4226: apidoc: Generate new style makefile (make-mode)
* #4274: sphinx-build returns 2 as an exit code on argument error * #4274: sphinx-build returns 2 as an exit code on argument error
* #4389: output directory will be created after loading extensions
* autodoc does not generate warnings messages to the generated document even if
:confval:`keep_warnings` is True. They are only emitted to stderr.
* shebang line is removed from generated conf.py
* #2557: autodoc: :confval:`autodoc_mock_imports` only mocks specified modules
with their descendants. It does not mock their ancestors. If you want to
mock them, please specify the name of ancestors implicitly.
* #3620: html theme: move DOCUMENTATION_OPTIONS to independent JavaScript file
(refs: #4295)
* #4246: Limit width of text body for all themes. Conifigurable via theme * #4246: Limit width of text body for all themes. Conifigurable via theme
options ``body_min_width`` and ``body_max_width``. options ``body_min_width`` and ``body_max_width``.
@ -23,6 +37,12 @@ Deprecated
values will be accepted at 2.0. values will be accepted at 2.0.
* ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use * ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use
``sphinx.util.inspect.Signature`` instead. ``sphinx.util.inspect.Signature`` instead.
* ``sphinx.ext.autodoc.AutodocReporter`` is replaced by ``sphinx.util.docutils.
switch_source_input()`` and now deprecated. It will be removed in Sphinx-2.0.
* ``sphinx.ext.autodoc.add_documenter()`` and ``AutoDirective._register`` is now
deprecated. Please use ``app.add_autodocumenter()`` instead.
* ``AutoDirective._special_attrgetters`` is now deprecated. Please use
``app.add_autodoc_attrgetter()`` instead.
Features added Features added
-------------- --------------
@ -57,7 +77,21 @@ Features added
code-blocks code-blocks
* #947: autodoc now supports ignore-module-all to ignore a module's ``__all__`` * #947: autodoc now supports ignore-module-all to ignore a module's ``__all__``
* #4332: Let LaTeX obey :confval:`math_numfig` for equation numbering * #4332: Let LaTeX obey :confval:`math_numfig` for equation numbering
* #4093: sphinx-build creates empty directories for unknown targets/builders
* Add ``top-classes`` option for the ``sphinx.ext.inheritance_diagram``
extension to limit the scope of inheritance graphs.
* #4183: doctest: ``:pyversion:`` option also follows PEP-440 specification
* #4235: html: Add :confval:`manpages_url` to make manpage roles to hyperlinks
* #3570: autodoc: Do not display 'typing.' module for type hints
* #4354: sphinx-build now emits finish message. Builders can modify it through
``Builder.epilog`` attribute
* #4245: html themes: Add ``language`` to javascript vars list
* #4079: html: Add ``notranslate`` class to each code-blocks, literals and maths
to let Google Translate know they are not translatable
* #4137: doctest: doctest block is always highlighted as python console (pycon)
* #4137: doctest: testcode block is always highlighted as python
* #3998: text: Assign section numbers by default. You can control it using
:confval:`text_add_secnumbers` and :confval:`text_secnumber_suffix`
Features removed Features removed
---------------- ----------------
@ -88,6 +122,8 @@ Features removed
* LaTeX environment ``notice``, use ``sphinxadmonition`` instead * LaTeX environment ``notice``, use ``sphinxadmonition`` instead
* LaTeX ``\sphinxstylethead``, use ``\sphinxstyletheadfamily`` * LaTeX ``\sphinxstylethead``, use ``\sphinxstyletheadfamily``
* C++, support of function concepts. Thanks to mickk-on-cpp. * C++, support of function concepts. Thanks to mickk-on-cpp.
* Not used and previously not documented LaTeX macros ``\shortversion``
and ``\setshortversion``
Bugs fixed Bugs fixed
@ -103,13 +139,18 @@ Bugs fixed
one of figures and tables one of figures and tables
* #4330: PDF 'howto' documents have an incoherent default LaTeX tocdepth counter * #4330: PDF 'howto' documents have an incoherent default LaTeX tocdepth counter
setting setting
* #4198: autosummary emits multiple 'autodoc-process-docstring' event. Thanks
to Joel Nothman.
* #4081: Warnings and errors colored the same when building
* latex: Do not display 'Release' label if :confval:`release` is not set
Testing Testing
-------- --------
* Add support for docutils 0.14 * Add support for docutils 0.14
* Add tests for the ``sphinx.ext.inheritance_diagram`` extension.
Release 1.6.6 (in development) Release 1.6.7 (in development)
============================== ==============================
Dependencies Dependencies
@ -124,14 +165,35 @@ Deprecated
Features added Features added
-------------- --------------
Bugs fixed
----------
* #1922: html search: Upper characters problem in French
Testing
--------
Release 1.6.6 (released Jan 08, 2018)
=====================================
Features added
--------------
* #4181: autodoc: Sort dictionary keys when possible * #4181: autodoc: Sort dictionary keys when possible
* ``VerbatimHighlightColor`` is a new * ``VerbatimHighlightColor`` is a new
:ref:`LaTeX 'sphinxsetup' <latexsphinxsetup>` key (refs: #4285) :ref:`LaTeX 'sphinxsetup' <latexsphinxsetup>` key (refs: #4285)
* Easier customizability of LaTeX macros involved in rendering of code-blocks * Easier customizability of LaTeX macros involved in rendering of code-blocks
* Show traceback if conf.py raises an exception (refs: #4369)
* Add :confval:`smartquotes` to disable smart quotes through ``conf.py``
(refs: #3967)
* Add :confval:`smartquotes_action` and :confval:`smartquotes_excludes`
(refs: #4142, #4357)
Bugs fixed Bugs fixed
---------- ----------
* #4334: sphinx-apidoc: Don't generate references to non-existing files in TOC
* #4206: latex: reST label between paragraphs loses paragraph break * #4206: latex: reST label between paragraphs loses paragraph break
* #4231: html: Apply fixFirefoxAnchorBug only under Firefox * #4231: html: Apply fixFirefoxAnchorBug only under Firefox
* #4221: napoleon depends on autodoc, but users need to load it manually * #4221: napoleon depends on autodoc, but users need to load it manually
@ -148,9 +210,8 @@ Bugs fixed
* #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates * #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates
``\chapter`` commands ``\chapter`` commands
* #4214: Two todolist directives break sphinx-1.6.5 * #4214: Two todolist directives break sphinx-1.6.5
* Fix links to external option docs with intersphinx (refs: #3769)
Testing * #4091: Private members not documented without :undoc-members:
--------
Release 1.6.5 (released Oct 23, 2017) Release 1.6.5 (released Oct 23, 2017)
===================================== =====================================

View File

@ -93,7 +93,7 @@ Documentation using the classic theme
* simuPOP: http://simupop.sourceforge.net/manual_release/build/userGuide.html (customized) * simuPOP: http://simupop.sourceforge.net/manual_release/build/userGuide.html (customized)
* Sprox: http://sprox.org/ (customized) * Sprox: http://sprox.org/ (customized)
* SymPy: http://docs.sympy.org/ * SymPy: http://docs.sympy.org/
* TurboGears: https://turbogears.readthedocs.org/ (customized) * TurboGears: https://turbogears.readthedocs.io/ (customized)
* tvtk: http://docs.enthought.com/mayavi/tvtk/ * tvtk: http://docs.enthought.com/mayavi/tvtk/
* Varnish: https://www.varnish-cache.org/docs/ (customized, alabaster for index) * Varnish: https://www.varnish-cache.org/docs/ (customized, alabaster for index)
* Waf: https://waf.io/apidocs/ * Waf: https://waf.io/apidocs/
@ -259,7 +259,7 @@ Documentation using sphinx_bootstrap_theme
* Bootstrap Theme: https://ryan-roemer.github.io/sphinx-bootstrap-theme/ * Bootstrap Theme: https://ryan-roemer.github.io/sphinx-bootstrap-theme/
* C/C++ Software Development with Eclipse: http://eclipsebook.in/ * C/C++ Software Development with Eclipse: http://eclipsebook.in/
* Dataverse: http://guides.dataverse.org/ * Dataverse: http://guides.dataverse.org/
* e-cidadania: http://e-cidadania.readthedocs.org/ * e-cidadania: https://e-cidadania.readthedocs.io/
* Hangfire: http://docs.hangfire.io/ * Hangfire: http://docs.hangfire.io/
* Hedge: https://documen.tician.de/hedge/ * Hedge: https://documen.tician.de/hedge/
* ObsPy: https://docs.obspy.org/ * ObsPy: https://docs.obspy.org/

View File

@ -74,9 +74,9 @@
<p>{%trans%} <p>{%trans%}
You can also download PDF/EPUB versions of the Sphinx documentation: You can also download PDF/EPUB versions of the Sphinx documentation:
a <a href="http://readthedocs.org/projects/sphinx/downloads/pdf/stable/">PDF version</a> generated from a <a href="https://media.readthedocs.org/pdf/sphinx/stable/sphinx.pdf">PDF version</a> generated from
the LaTeX Sphinx produces, and the LaTeX Sphinx produces, and
a <a href="http://readthedocs.org/projects/sphinx/downloads/epub/stable/">EPUB version</a>. a <a href="https://media.readthedocs.org/epub/sphinx/stable/sphinx.epub">EPUB version</a>.
{%endtrans%} {%endtrans%}
</p> </p>
@ -106,7 +106,7 @@
<h2>{%trans%}Hosting{%endtrans%}</h2> <h2>{%trans%}Hosting{%endtrans%}</h2>
<p>{%trans%}Need a place to host your Sphinx docs? <p>{%trans%}Need a place to host your Sphinx docs?
<a href="http://readthedocs.org">readthedocs.org</a> hosts a lot of Sphinx docs <a href="https://readthedocs.org/">readthedocs.org</a> hosts a lot of Sphinx docs
already, and integrates well with projects' source control. It also features a already, and integrates well with projects' source control. It also features a
powerful built-in search that exceeds the possibilities of Sphinx' JavaScript-based powerful built-in search that exceeds the possibilities of Sphinx' JavaScript-based
offline search.{%endtrans%}</p> offline search.{%endtrans%}</p>

View File

@ -20,12 +20,14 @@ Index</a>, or install it with:{%endtrans%}</p>
<h3>{%trans%}Questions? Suggestions?{%endtrans%}</h3> <h3>{%trans%}Questions? Suggestions?{%endtrans%}</h3>
<p>{%trans%}Join the <a href="http://groups.google.com/group/sphinx-users">sphinx-users</a> mailing list on Google Groups:{%endtrans%}</p> <p>{%trans%}Join the <a href="http://groups.google.com/group/sphinx-users">sphinx-users</a> mailing list on Google Groups:{%endtrans%}</p>
<div class="subscribeformwrapper">
<form action="http://groups.google.com/group/sphinx-users/boxsubscribe" <form action="http://groups.google.com/group/sphinx-users/boxsubscribe"
style="padding-left: 0.5em"> class="subscribeform">
<input type="text" name="email" value="your@email" style="font-size: 90%; width: 120px" <input type="text" name="email" value="your@email"
onfocus="$(this).val('');" /> onfocus="$(this).val('');" />
<input type="submit" name="sub" value="Subscribe" style="font-size: 90%; width: 70px"/> <input type="submit" name="sub" value="Subscribe" />
</form> </form>
</div>
<p>{%trans%}or come to the <tt>#sphinx-doc</tt> channel on FreeNode.{%endtrans%}</p> <p>{%trans%}or come to the <tt>#sphinx-doc</tt> channel on FreeNode.{%endtrans%}</p>
<p>{%trans%}You can also open an issue at the <p>{%trans%}You can also open an issue at the
<a href="https://github.com/sphinx-doc/sphinx/issues">tracker</a>.{%endtrans%}</p> <a href="https://github.com/sphinx-doc/sphinx/issues">tracker</a>.{%endtrans%}</p>

View File

@ -140,11 +140,37 @@ div.sphinxsidebar .logo img {
vertical-align: middle; vertical-align: middle;
} }
div.subscribeformwrapper {
display: block;
overflow: auto;
margin-bottom: 1.2em;
}
div.sphinxsidebar input { div.sphinxsidebar input {
border: 1px solid #aaa; border: 1px solid #aaa;
font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif; 'Verdana', sans-serif;
font-size: 1em; }
div.sphinxsidebar .subscribeform {
margin-top: 0;
}
div.sphinxsidebar .subscribeform input {
border: 1px solid #aaa;
font-size: 0.9em;
float: left;
padding: 0.25em 0.5em;
box-sizing: border-box;
}
div.sphinxsidebar .subscribeform input[type="text"] {
width: 60%;
}
div.sphinxsidebar .subscribeform input[type="submit"] {
width: 40%;
border-left: none;
} }
div.sphinxsidebar h3 { div.sphinxsidebar h3 {
@ -281,7 +307,7 @@ tt {
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 2px; border-radius: 2px;
color: #333; color: #333;
padding: 1px; padding: 1px 0.2em;
} }
tt.descname, tt.descclassname, tt.xref { tt.descname, tt.descclassname, tt.xref {

View File

@ -293,6 +293,24 @@ General configuration
.. versionadded:: 1.3 .. versionadded:: 1.3
.. confval:: manpages_url
A URL to cross-reference :rst:role:`manpage` directives. If this is
defined to ``https://manpages.debian.org/{path}``, the
:literal:`:manpage:`man(1)`` role will like to
<https://manpages.debian.org/man(1)>. The patterns available are:
* ``page`` - the manual page (``man``)
* ``section`` - the manual section (``1``)
* ``path`` - the original manual page and section specified (``man(1)``)
This also supports manpages specified as ``man.1``.
.. note:: This currently affects only HTML writers but could be
expanded in the future.
.. versionadded:: 1.7
.. confval:: nitpicky .. confval:: nitpicky
If true, Sphinx will warn about *all* references where the target cannot be If true, Sphinx will warn about *all* references where the target cannot be
@ -354,6 +372,63 @@ General configuration
The LaTeX builder obeys this setting (if :confval:`numfig` is set to The LaTeX builder obeys this setting (if :confval:`numfig` is set to
``True``). ``True``).
.. confval:: smartquotes
If true, the `Docutils Smart Quotes transform`__, originally based on
`SmartyPants`__ (limited to English) and currently applying to many
languages, will be used to convert quotes and dashes to typographically
correct entities. Default: ``True``.
__ http://docutils.sourceforge.net/docs/user/smartquotes.html
__ https://daringfireball.net/projects/smartypants/
.. versionadded:: 1.6.6
It replaces deprecated :confval:`html_use_smartypants`.
It applies by default to all builders except ``man`` and ``text``
(see :confval:`smartquotes_excludes`.)
A `docutils.conf`__ file located in the configuration directory (or a
global :file:`~/.docutils` file) is obeyed unconditionally if it
*deactivates* smart quotes via the corresponding `Docutils option`__. But
if it *activates* them, then :confval:`smartquotes` does prevail.
__ http://docutils.sourceforge.net/docs/user/config.html
__ http://docutils.sourceforge.net/docs/user/config.html#smart-quotes
.. confval:: smartquotes_action
This string, for use with Docutils ``0.14`` or later, customizes the Smart
Quotes transform. See the file :file:`smartquotes.py` at the `Docutils
repository`__ for details. The default ``'qDe'`` educates normal **q**\
uote characters ``"``, ``'``, em- and en-**D**\ ashes ``---``, ``--``, and
**e**\ llipses ``...``.
.. versionadded:: 1.6.6
__ https://sourceforge.net/p/docutils/code/HEAD/tree/trunk/docutils/
.. confval:: smartquotes_excludes
This is a ``dict`` whose default is::
{'languages': ['ja'], 'builders': ['man', 'text']}
Each entry gives a sufficient condition to ignore the
:confval:`smartquotes` setting and deactivate the Smart Quotes transform.
Accepted keys are as above ``'builders'`` or ``'languages'``.
The values are lists.
.. note:: Currently, in case of invocation of :program:`make` with multiple
targets, the first target name is the only one which is tested against
the ``'builders'`` entry and it decides for all. Also, a ``make text``
following ``make html`` needs to be issued in the form ``make text
O="-E"`` to force re-parsing of source files, as the cached ones are
already transformed. On the other hand the issue does not arise with
direct usage of :program:`sphinx-build` as it caches
(in its default usage) the parsed source files in per builder locations.
.. versionadded:: 1.6.6
.. confval:: tls_verify .. confval:: tls_verify
If true, Sphinx verifies server certifications. Default is ``True``. If true, Sphinx verifies server certifications. Default is ``True``.
@ -785,15 +860,11 @@ that use Sphinx's HTMLWriter class.
.. confval:: html_use_smartypants .. confval:: html_use_smartypants
If true, `SmartyPants <https://daringfireball.net/projects/smartypants/>`_ If true, quotes and dashes are converted to typographically correct
will be used to convert quotes and dashes to typographically correct
entities. Default: ``True``. entities. Default: ``True``.
.. deprecated:: 1.6 .. deprecated:: 1.6
To disable or customize smart quotes, use the Docutils configuration file To disable smart quotes, use rather :confval:`smartquotes`.
(``docutils.conf``) instead to set there its `smart_quotes option`_.
.. _`smart_quotes option`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes
.. confval:: html_add_permalinks .. confval:: html_add_permalinks
@ -1968,6 +2039,20 @@ These options influence text output.
.. versionadded:: 1.1 .. versionadded:: 1.1
.. confval:: text_add_secnumbers
A boolean that decides whether section numbers are included in text output.
Default is ``True``.
.. versionadded:: 1.7
.. confval:: text_secnumber_suffix
Suffix for section numbers in text output. Default: ``". "``. Set to ``" "``
to suppress the final dot on section numbers.
.. versionadded:: 1.7
.. _man-options: .. _man-options:

View File

@ -138,7 +138,7 @@ own extensions.
.. _cmakedomain: https://bitbucket.org/klorenz/sphinxcontrib-cmakedomain .. _cmakedomain: https://bitbucket.org/klorenz/sphinxcontrib-cmakedomain
.. _GNU Make: http://www.gnu.org/software/make/ .. _GNU Make: http://www.gnu.org/software/make/
.. _makedomain: https://bitbucket.org/klorenz/sphinxcontrib-makedomain .. _makedomain: https://bitbucket.org/klorenz/sphinxcontrib-makedomain
.. _inlinesyntaxhighlight: http://sphinxcontrib-inlinesyntaxhighlight.readthedocs.org .. _inlinesyntaxhighlight: https://sphinxcontrib-inlinesyntaxhighlight.readthedocs.io/
.. _CMake: https://cmake.org .. _CMake: https://cmake.org
.. _domaintools: https://bitbucket.org/klorenz/sphinxcontrib-domaintools .. _domaintools: https://bitbucket.org/klorenz/sphinxcontrib-domaintools
.. _restbuilder: https://pypi.python.org/pypi/sphinxcontrib-restbuilder .. _restbuilder: https://pypi.python.org/pypi/sphinxcontrib-restbuilder

View File

@ -80,12 +80,24 @@ a comma-separated list of group names.
.. doctest:: .. doctest::
:pyversion: > 3.3 :pyversion: > 3.3
The supported operands are ``<``, ``<=``, ``==``, ``>=``, ``>``, and The following operands are supported:
comparison is performed by `distutils.version.LooseVersion
<https://www.python.org/dev/peps/pep-0386/#distutils>`__. * ``~=``: Compatible release clause
* ``==``: Version matching clause
* ``!=``: Version exclusion clause
* ``<=``, ``>=``: Inclusive ordered comparison clause
* ``<``, ``>``: Exclusive ordered comparison clause
* ``===``: Arbitrary equality clause.
``pyversion`` option is followed `PEP-440: Version Specifiers
<https://www.python.org/dev/peps/pep-0440/#version-specifiers>`__.
.. versionadded:: 1.6 .. versionadded:: 1.6
.. versionchanged:: 1.7
Supported PEP-440 operands and notations
Note that like with standard doctests, you have to use ``<BLANKLINE>`` to Note that like with standard doctests, you have to use ``<BLANKLINE>`` to
signal a blank line in the expected output. The ``<BLANKLINE>`` is removed signal a blank line in the expected output. The ``<BLANKLINE>`` is removed
when building presentation output (HTML, LaTeX etc.). when building presentation output (HTML, LaTeX etc.).

View File

@ -42,6 +42,54 @@ It adds this directive:
.. versionchanged:: 1.5 .. versionchanged:: 1.5
Added ``caption`` option Added ``caption`` option
It also supports a ``top-classes`` option which requires one or more class
names separated by comma. If specified inheritance traversal will stop at the
specified class names. Given the following Python module::
"""
A
/ \
B C
/ \ / \
E D F
"""
class A(object):
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E(B):
pass
class F(C):
pass
If you have specified a module in the inheritance diagram like this::
.. inheritance-diagram:: dummy.test
:top-classes: dummy.test.B, dummy.test.C
any base classes which are ancestors to ``top-classes`` and are also defined
in the same module will be rendered as stand alone nodes. In this example
class A will be rendered as stand alone node in the graph. This is a known
issue due to how this extension works internally.
If you don't want class A (or any other ancestors) to be visible then specify
only the classes you would like to generate the diagram for like this::
.. inheritance-diagram:: dummy.test.D dummy.test.E dummy.test.F
:top-classes: dummy.test.B, dummy.test.C
.. versionchanged:: 1.7
Added ``top-classes`` option to limit the scope of inheritance graphs.
New config values are: New config values are:

View File

@ -6,7 +6,7 @@ repository. It is open for anyone who wants to maintain an extension
publicly; just send a short message asking for write permissions. publicly; just send a short message asking for write permissions.
There are also several extensions hosted elsewhere. The `Sphinx extension There are also several extensions hosted elsewhere. The `Sphinx extension
survey <http://sphinxext-survey.readthedocs.org/en/latest/>`__ contains a survey <https://sphinxext-survey.readthedocs.io/>`__ contains a
comprehensive list. comprehensive list.
If you write an extension that you think others will find useful or you think If you write an extension that you think others will find useful or you think

View File

@ -15,6 +15,7 @@ Builder API
.. autoattribute:: name .. autoattribute:: name
.. autoattribute:: format .. autoattribute:: format
.. autoattribute:: epilog
.. autoattribute:: supported_image_types .. autoattribute:: supported_image_types
These methods are predefined and will be called from the application: These methods are predefined and will be called from the application:

View File

@ -117,12 +117,30 @@ Both APIs parse the content into a given node. They are used like this::
node = docutils.nodes.paragraph() node = docutils.nodes.paragraph()
# either # either
from sphinx.ext.autodoc import AutodocReporter
self.state.memo.reporter = AutodocReporter(self.result, self.state.memo.reporter) # override reporter to avoid errors from "include" directive
nested_parse_with_titles(self.state, self.result, node) nested_parse_with_titles(self.state, self.result, node)
# or # or
self.state.nested_parse(self.result, 0, node) self.state.nested_parse(self.result, 0, node)
.. note::
``sphinx.util.docutils.switch_source_input()`` allows to change a target file
during nested_parse. It is useful to mixed contents. For example, ``sphinx.
ext.autodoc`` uses it to parse docstrings::
from sphinx.util.docutils import switch_source_input
# Switch source_input between parsing content.
# Inside this context, all parsing errors and warnings are reported as
# happened in new source_input (in this case, ``self.result``).
with switch_source_input(self.state, self.result):
node = docutils.nodes.paragraph()
self.state.nested_parse(self.result, 0, node)
.. deprecated:: 1.7
Until Sphinx-1.6, ``sphinx.ext.autodoc.AutodocReporter`` is used for this purpose.
For now, it is replaced by ``switch_source_input()``.
If you don't need the wrapping node, you can use any concrete node type and If you don't need the wrapping node, you can use any concrete node type and
return ``node.children`` from the Directive. return ``node.children`` from the Directive.

View File

@ -58,7 +58,7 @@ Read the Docs
Sphinx. They will host sphinx documentation, along with supporting a number Sphinx. They will host sphinx documentation, along with supporting a number
of other features including version support, PDF generation, and more. The of other features including version support, PDF generation, and more. The
`Getting Started `Getting Started
<http://read-the-docs.readthedocs.org/en/latest/getting_started.html>`_ <https://read-the-docs.readthedocs.io/en/latest/getting_started.html>`_
guide is a good place to start. guide is a good place to start.
Epydoc Epydoc

View File

@ -3,7 +3,7 @@ Introduction
This is the documentation for the Sphinx documentation builder. Sphinx is a This is the documentation for the Sphinx documentation builder. Sphinx is a
tool that translates a set of reStructuredText_ source files into various output tool that translates a set of reStructuredText_ source files into various output
formats, automatically producing cross-references, indices etc. That is, if formats, automatically producing cross-references, indices, etc. That is, if
you have a directory containing a bunch of reST-formatted documents (and you have a directory containing a bunch of reST-formatted documents (and
possibly subdirectories of docs in there as well), Sphinx can generate a possibly subdirectories of docs in there as well), Sphinx can generate a
nicely-organized arrangement of HTML files (in some other directory) for easy nicely-organized arrangement of HTML files (in some other directory) for easy
@ -17,7 +17,7 @@ docs have a look at `Epydoc <http://epydoc.sourceforge.net/>`_, which also
understands reST. understands reST.
For a great "introduction" to writing docs in general -- the whys and hows, see For a great "introduction" to writing docs in general -- the whys and hows, see
also `Write the docs <http://write-the-docs.readthedocs.org/>`_, written by Eric also `Write the docs <https://write-the-docs.readthedocs.io/>`_, written by Eric
Holscher. Holscher.
.. _rinohtype: https://github.com/brechtm/rinohtype .. _rinohtype: https://github.com/brechtm/rinohtype
@ -38,7 +38,7 @@ to reStructuredText/Sphinx from other documentation systems.
code to convert Python-doc-style LaTeX markup to Sphinx reST. code to convert Python-doc-style LaTeX markup to Sphinx reST.
* Marcin Wojdyr has written a script to convert Docbook to reST with Sphinx * Marcin Wojdyr has written a script to convert Docbook to reST with Sphinx
markup; it is at `Google Code <https://github.com/wojdyr/db2rst>`_. markup; it is at `GitHub <https://github.com/wojdyr/db2rst>`_.
* Christophe de Vienne wrote a tool to convert from Open/LibreOffice documents * Christophe de Vienne wrote a tool to convert from Open/LibreOffice documents
to Sphinx: `odt2sphinx <https://pypi.python.org/pypi/odt2sphinx/>`_. to Sphinx: `odt2sphinx <https://pypi.python.org/pypi/odt2sphinx/>`_.

View File

@ -355,7 +355,8 @@ in a different style:
.. rst:role:: manpage .. rst:role:: manpage
A reference to a Unix manual page including the section, A reference to a Unix manual page including the section,
e.g. ``:manpage:`ls(1)```. e.g. ``:manpage:`ls(1)```. Creates a hyperlink to an external site
rendering the manpage if :confval:`manpages_url` is defined.
.. rst:role:: menuselection .. rst:role:: menuselection

View File

@ -323,6 +323,11 @@ following directive exists:
Sphinx's merged cells interact well with ``p{width}``, ``\X{a}{b}``, ``Y{f}`` Sphinx's merged cells interact well with ``p{width}``, ``\X{a}{b}``, ``Y{f}``
and tabulary's columns. and tabulary's columns.
.. note::
:rst:dir:`tabularcolumns` conflicts with ``:widths:`` option of table
directives. If both are specified, ``:widths:`` option will be ignored.
Math Math
---- ----

View File

@ -44,6 +44,10 @@ incremental = True
check_untyped_defs = True check_untyped_defs = True
warn_unused_ignores = True warn_unused_ignores = True
[tool:pytest]
filterwarnings =
ignore::DeprecationWarning:docutils.io
[coverage:run] [coverage:run]
branch = True branch = True
source = sphinx source = sphinx

View File

@ -26,6 +26,7 @@ requires = [
'imagesize', 'imagesize',
'requests>=2.0.0', 'requests>=2.0.0',
'setuptools', 'setuptools',
'packaging',
'sphinxcontrib-websupport', 'sphinxcontrib-websupport',
] ]

View File

@ -157,10 +157,6 @@ class Sphinx(object):
# status code for command-line application # status code for command-line application
self.statuscode = 0 self.statuscode = 0
if not path.isdir(outdir):
logger.info('making output directory...')
ensuredir(outdir)
# read config # read config
self.tags = Tags(tags) self.tags = Tags(tags)
self.config = Config(confdir, CONFIG_FILENAME, self.config = Config(confdir, CONFIG_FILENAME,
@ -197,6 +193,10 @@ class Sphinx(object):
# preload builder module (before init config values) # preload builder module (before init config values)
self.preload_builder(buildername) self.preload_builder(buildername)
if not path.isdir(outdir):
logger.info('making output directory...')
ensuredir(outdir)
# the config file itself can be an extension # the config file itself can be an extension
if self.config.setup: if self.config.setup:
self._setting_up_extension = ['conf.py'] self._setting_up_extension = ['conf.py']
@ -338,6 +338,13 @@ class Sphinx(object):
(status, self._warncount))) (status, self._warncount)))
else: else:
logger.info(bold(__('build %s.') % status)) logger.info(bold(__('build %s.') % status))
if self.statuscode == 0 and self.builder.epilog:
logger.info('')
logger.info(self.builder.epilog % {
'outdir': path.relpath(self.outdir),
'project': self.config.project
})
except Exception as err: except Exception as err:
# delete the saved env to force a fresh build next time # delete the saved env to force a fresh build next time
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME) envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
@ -642,15 +649,14 @@ class Sphinx(object):
def add_autodocumenter(self, cls): def add_autodocumenter(self, cls):
# type: (Any) -> None # type: (Any) -> None
logger.debug('[app] adding autodocumenter: %r', cls) logger.debug('[app] adding autodocumenter: %r', cls)
from sphinx.ext import autodoc from sphinx.ext.autodoc.directive import AutodocDirective
autodoc.add_documenter(cls) self.registry.add_documenter(cls.objtype, cls)
self.add_directive('auto' + cls.objtype, autodoc.AutoDirective) self.add_directive('auto' + cls.objtype, AutodocDirective)
def add_autodoc_attrgetter(self, type, getter): def add_autodoc_attrgetter(self, typ, getter):
# type: (Any, Callable) -> None # type: (Type, Callable[[Any, unicode, Any], Any]) -> None
logger.debug('[app] adding autodoc attrgetter: %r', (type, getter)) logger.debug('[app] adding autodoc attrgetter: %r', (typ, getter))
from sphinx.ext import autodoc self.registry.add_autodoc_attrgetter(typ, getter)
autodoc.AutoDirective._special_attrgetters[type] = getter
def add_search_language(self, cls): def add_search_language(self, cls):
# type: (Any) -> None # type: (Any) -> None

View File

@ -54,6 +54,11 @@ class Builder(object):
name = '' # type: unicode name = '' # type: unicode
#: The 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 format = '' # type: unicode
#: The message emitted upon successful build completion. This can be a
#: printf-style template string with the following keys: ``outdir``,
#: ``project``
epilog = '' # type: unicode
# default translator class for the builder. This will be overrided by # default translator class for the builder. This will be overrided by
# ``app.set_translator()``. # ``app.set_translator()``.
default_translator_class = None # type: nodes.NodeVisitor default_translator_class = None # type: nodes.NodeVisitor

View File

@ -75,6 +75,10 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
on the ``hiutil`` command line tool. on the ``hiutil`` command line tool.
""" """
name = 'applehelp' name = 'applehelp'
epilog = ('The help book is in %(outdir)s.\n'
'Note that won\'t be able to view it unless you put it in '
'~/Library/Documentation/Help or install it in your application '
'bundle.')
# don't copy the reST source # don't copy the reST source
copysource = False copysource = False

View File

@ -38,6 +38,7 @@ class ChangesBuilder(Builder):
Write a summary with all versionadded/changed directives. Write a summary with all versionadded/changed directives.
""" """
name = 'changes' name = 'changes'
epilog = 'The overview file is in %(outdir)s.'
def init(self): def init(self):
# type: () -> None # type: () -> None

View File

@ -43,6 +43,10 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
Builder that also outputs GNOME Devhelp file. Builder that also outputs GNOME Devhelp file.
""" """
name = 'devhelp' name = 'devhelp'
epilog = ('To view the help file:\n'
'$ mkdir -p $HOME/.local/share/devhelp/%(project)s\n'
'$ ln -s %(outdir)s $HOME/.local/share/devhelp/%(project)s\n'
'$ devhelp')
# don't copy the reST source # don't copy the reST source
copysource = False copysource = False

View File

@ -21,6 +21,8 @@ if False:
class DummyBuilder(Builder): class DummyBuilder(Builder):
name = 'dummy' name = 'dummy'
epilog = 'The dummy builder generates no files.'
allow_parallel = True allow_parallel = True
def init(self): def init(self):

View File

@ -63,6 +63,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
an epub file. an epub file.
""" """
name = 'epub' name = 'epub'
epilog = 'The ePub file is in %(outdir)s.'
supported_remote_images = False supported_remote_images = False
template_dir = path.join(package_dir, 'templates', 'epub3') template_dir = path.join(package_dir, 'templates', 'epub3')

View File

@ -214,6 +214,7 @@ class MessageCatalogBuilder(I18nBuilder):
Builds gettext-style message catalogs (.pot files). Builds gettext-style message catalogs (.pot files).
""" """
name = 'gettext' name = 'gettext'
epilog = 'The message catalogs are in %(outdir)s.'
def init(self): def init(self):
# type: () -> None # type: () -> None

View File

@ -153,6 +153,8 @@ class StandaloneHTMLBuilder(Builder):
""" """
name = 'html' name = 'html'
format = 'html' format = 'html'
epilog = 'The HTML pages are in %(outdir)s.'
copysource = True copysource = True
allow_parallel = True allow_parallel = True
out_suffix = '.html' out_suffix = '.html'
@ -1066,6 +1068,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
HTML page. HTML page.
""" """
name = 'singlehtml' name = 'singlehtml'
epilog = 'The HTML page is in %(outdir)s.'
copysource = False copysource = False
def get_outdated_docs(self): # type: ignore def get_outdated_docs(self): # type: ignore
@ -1328,12 +1332,14 @@ class PickleHTMLBuilder(SerializingHTMLBuilder):
""" """
A Builder that dumps the generated HTML into pickle files. A Builder that dumps the generated HTML into pickle files.
""" """
name = 'pickle'
epilog = 'You can now process the pickle files in %(outdir)s.'
implementation = pickle implementation = pickle
implementation_dumps_unicode = False implementation_dumps_unicode = False
additional_dump_args = (pickle.HIGHEST_PROTOCOL,) additional_dump_args = (pickle.HIGHEST_PROTOCOL,)
indexer_format = pickle indexer_format = pickle
indexer_dumps_unicode = False indexer_dumps_unicode = False
name = 'pickle'
out_suffix = '.fpickle' out_suffix = '.fpickle'
globalcontext_filename = 'globalcontext.pickle' globalcontext_filename = 'globalcontext.pickle'
searchindex_filename = 'searchindex.pickle' searchindex_filename = 'searchindex.pickle'
@ -1347,11 +1353,13 @@ class JSONHTMLBuilder(SerializingHTMLBuilder):
""" """
A builder that dumps the generated HTML into JSON files. A builder that dumps the generated HTML into JSON files.
""" """
name = 'json'
epilog = 'You can now process the JSON files in %(outdir)s.'
implementation = jsonimpl implementation = jsonimpl
implementation_dumps_unicode = True implementation_dumps_unicode = True
indexer_format = jsonimpl indexer_format = jsonimpl
indexer_dumps_unicode = True indexer_dumps_unicode = True
name = 'json'
out_suffix = '.fjson' out_suffix = '.fjson'
globalcontext_filename = 'globalcontext.json' globalcontext_filename = 'globalcontext.json'
searchindex_filename = 'searchindex.json' searchindex_filename = 'searchindex.json'

View File

@ -174,6 +174,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
index files. Adapted from the original Doc/tools/prechm.py. index files. Adapted from the original Doc/tools/prechm.py.
""" """
name = 'htmlhelp' name = 'htmlhelp'
epilog = ('You can now run HTML Help Workshop with the .htp file in '
'%(outdir)s.')
# don't copy the reST source # don't copy the reST source
copysource = False copysource = False

View File

@ -49,6 +49,12 @@ class LaTeXBuilder(Builder):
""" """
name = 'latex' name = 'latex'
format = 'latex' format = 'latex'
epilog = 'The LaTeX files are in %(outdir)s.'
if os.name == 'posix':
epilog += ("\nRun 'make' in that directory to run these through "
"(pdf)latex\n"
"(use `make latexpdf' here to do that automatically).")
supported_image_types = ['application/pdf', 'image/png', 'image/jpeg'] supported_image_types = ['application/pdf', 'image/png', 'image/jpeg']
supported_remote_images = False supported_remote_images = False
default_translator_class = LaTeXTranslator default_translator_class = LaTeXTranslator

View File

@ -90,6 +90,8 @@ class CheckExternalLinksBuilder(Builder):
Checks for broken external links. Checks for broken external links.
""" """
name = 'linkcheck' name = 'linkcheck'
epilog = ('Look for any errors in the above output or in '
'%(outdir)s/output.txt')
def init(self): def init(self):
# type: () -> None # type: () -> None

View File

@ -40,6 +40,8 @@ class ManualPageBuilder(Builder):
""" """
name = 'man' name = 'man'
format = 'man' format = 'man'
epilog = 'The manual pages are in %(outdir)s.'
default_translator_class = ManualPageTranslator default_translator_class = ManualPageTranslator
supported_image_types = [] # type: List[unicode] supported_image_types = [] # type: List[unicode]

View File

@ -108,6 +108,11 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
Builder that also outputs Qt help project, contents and index files. Builder that also outputs Qt help project, contents and index files.
""" """
name = 'qthelp' name = 'qthelp'
epilog = ('You can now run "qcollectiongenerator" with the .qhcp '
'project file in %(outdir)s, like this:\n'
'$ qcollectiongenerator %(outdir)s/%(project)s.qhcp\n'
'To view the help file:\n'
'$ assistant -collectionFile %(outdir)s/%(project)s.qhc')
# don't copy the reST source # don't copy the reST source
copysource = False copysource = False

View File

@ -9,6 +9,7 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import os
from os import path from os import path
from docutils import nodes from docutils import nodes
@ -97,6 +98,12 @@ class TexinfoBuilder(Builder):
""" """
name = 'texinfo' name = 'texinfo'
format = 'texinfo' format = 'texinfo'
epilog = 'The Texinfo files are in %(outdir)s.'
if os.name == 'posix':
epilog += ("\nRun 'make' in that directory to run these through "
"makeinfo\n"
"(use 'make info' here to do that automatically).")
supported_image_types = ['image/png', 'image/jpeg', supported_image_types = ['image/png', 'image/jpeg',
'image/gif'] 'image/gif']
default_translator_class = TexinfoTranslator default_translator_class = TexinfoTranslator

View File

@ -21,7 +21,7 @@ from sphinx.writers.text import TextWriter, TextTranslator
if False: if False:
# For type annotation # For type annotation
from typing import Any, Dict, Iterator, Set # NOQA from typing import Any, Dict, Iterator, Set, Tuple # NOQA
from docutils import nodes # NOQA from docutils import nodes # NOQA
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
@ -31,6 +31,8 @@ logger = logging.getLogger(__name__)
class TextBuilder(Builder): class TextBuilder(Builder):
name = 'text' name = 'text'
format = 'text' format = 'text'
epilog = 'The text files are in %(outdir)s.'
out_suffix = '.txt' out_suffix = '.txt'
allow_parallel = True allow_parallel = True
default_translator_class = TextTranslator default_translator_class = TextTranslator
@ -39,7 +41,8 @@ class TextBuilder(Builder):
def init(self): def init(self):
# type: () -> None # type: () -> None
pass # section numbers for headings in the currently visited document
self.secnumbers = {} # type: Dict[unicode, Tuple[int, ...]]
def get_outdated_docs(self): def get_outdated_docs(self):
# type: () -> Iterator[unicode] # type: () -> Iterator[unicode]
@ -72,6 +75,7 @@ class TextBuilder(Builder):
def write_doc(self, docname, doctree): def write_doc(self, docname, doctree):
# type: (unicode, nodes.Node) -> None # type: (unicode, nodes.Node) -> None
self.current_docname = docname self.current_docname = docname
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
destination = StringOutput(encoding='utf-8') destination = StringOutput(encoding='utf-8')
self.writer.write(doctree, destination) self.writer.write(doctree, destination)
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix) outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
@ -93,6 +97,8 @@ def setup(app):
app.add_config_value('text_sectionchars', '*=-~"+`', 'env') app.add_config_value('text_sectionchars', '*=-~"+`', 'env')
app.add_config_value('text_newlines', 'unix', 'env') app.add_config_value('text_newlines', 'unix', 'env')
app.add_config_value('text_add_secnumbers', True, 'env')
app.add_config_value('text_secnumber_suffix', '. ', 'env')
return { return {
'version': 'builtin', 'version': 'builtin',

View File

@ -35,6 +35,8 @@ class XMLBuilder(Builder):
""" """
name = 'xml' name = 'xml'
format = 'xml' format = 'xml'
epilog = 'The XML files are in %(outdir)s.'
out_suffix = '.xml' out_suffix = '.xml'
allow_parallel = True allow_parallel = True
@ -108,6 +110,8 @@ class PseudoXMLBuilder(XMLBuilder):
""" """
name = 'pseudoxml' name = 'pseudoxml'
format = 'pseudoxml' format = 'pseudoxml'
epilog = 'The pseudo-XML files are in %(outdir)s.'
out_suffix = '.pseudoxml' out_suffix = '.pseudoxml'
_writer_class = PseudoXMLWriter _writer_class = PseudoXMLWriter

View File

@ -10,6 +10,7 @@
""" """
import re import re
import traceback
from os import path, getenv from os import path, getenv
from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types from six import PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types
@ -35,6 +36,7 @@ copyright_year_re = re.compile(r'^((\d{4}-)?)(\d{4})(?=[ ,])')
CONFIG_SYNTAX_ERROR = "There is a syntax error in your configuration file: %s" CONFIG_SYNTAX_ERROR = "There is a syntax error in your configuration file: %s"
if PY3: if PY3:
CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?" CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?"
CONFIG_ERROR = "There is a programable error in your configuration file:\n\n%s"
CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \ CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \
"called sys.exit()" "called sys.exit()"
CONFIG_ENUM_WARNING = "The config value `{name}` has to be a one of {candidates}, " \ CONFIG_ENUM_WARNING = "The config value `{name}` has to be a one of {candidates}, " \
@ -123,6 +125,7 @@ class Config(object):
primary_domain = ('py', 'env', [NoneType]), primary_domain = ('py', 'env', [NoneType]),
needs_sphinx = (None, None, string_classes), needs_sphinx = (None, None, string_classes),
needs_extensions = ({}, None), needs_extensions = ({}, None),
manpages_url = (None, 'env'),
nitpicky = (False, None), nitpicky = (False, None),
nitpick_ignore = ([], None), nitpick_ignore = ([], None),
numfig = (False, 'env'), numfig = (False, 'env'),
@ -135,6 +138,11 @@ class Config(object):
tls_verify = (True, 'env'), tls_verify = (True, 'env'),
tls_cacerts = (None, 'env'), tls_cacerts = (None, 'env'),
smartquotes = (True, 'env'),
smartquotes_action = ('qDe', 'env'),
smartquotes_excludes = ({'languages': ['ja'],
'builders': ['man', 'text']},
'env'),
) # type: Dict[unicode, Tuple] ) # type: Dict[unicode, Tuple]
def __init__(self, dirname, filename, overrides, tags): def __init__(self, dirname, filename, overrides, tags):
@ -155,6 +163,8 @@ class Config(object):
raise ConfigError(CONFIG_SYNTAX_ERROR % err) raise ConfigError(CONFIG_SYNTAX_ERROR % err)
except SystemExit: except SystemExit:
raise ConfigError(CONFIG_EXIT_ERROR) raise ConfigError(CONFIG_EXIT_ERROR)
except Exception:
raise ConfigError(CONFIG_ERROR % traceback.format_exc())
self._raw_config = config self._raw_config = config
# these two must be preinitialized because extensions can add their # these two must be preinitialized because extensions can add their

View File

@ -959,12 +959,18 @@ class StandardDomain(Domain):
def get_full_qualified_name(self, node): def get_full_qualified_name(self, node):
# type: (nodes.Node) -> unicode # type: (nodes.Node) -> unicode
if node.get('reftype') == 'option':
progname = node.get('std:program') progname = node.get('std:program')
target = node.get('reftarget') command = ws_re.split(node.get('reftarget'))
if progname is None or target is None: if progname:
command.insert(0, progname)
option = command.pop()
if command:
return '.'.join(['-'.join(command), option])
else:
return None return None
else: else:
return '.'.join([progname, target]) return None
def setup(app): def setup(app):

View File

@ -23,8 +23,7 @@ from collections import defaultdict
from six import BytesIO, itervalues, class_types, next from six import BytesIO, itervalues, class_types, next
from six.moves import cPickle as pickle from six.moves import cPickle as pickle
from docutils.utils import Reporter, get_source_line, normalize_language_tag from docutils.utils import Reporter, get_source_line
from docutils.utils.smartquotes import smartchars
from docutils.frontend import OptionParser from docutils.frontend import OptionParser
from sphinx import addnodes, versioning from sphinx import addnodes, versioning
@ -47,7 +46,7 @@ from sphinx.environment.adapters.toctree import TocTree
if False: if False:
# For type annotation # For type annotation
from typing import Any, Callable, Dict, IO, Iterator, List, Pattern, Set, Tuple, Type, Union # NOQA from typing import Any, Callable, Dict, IO, Iterator, List, Pattern, Set, Tuple, Type, Union, Generator # NOQA
from docutils import nodes # NOQA from docutils import nodes # NOQA
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
from sphinx.builders import Builder # NOQA from sphinx.builders import Builder # NOQA
@ -66,6 +65,7 @@ default_settings = {
'sectsubtitle_xform': False, 'sectsubtitle_xform': False,
'halt_level': 5, 'halt_level': 5,
'file_insertion_enabled': True, 'file_insertion_enabled': True,
'smartquotes_locales': [],
} }
# This is increased every time an environment attribute is added # This is increased every time an environment attribute is added
@ -642,17 +642,10 @@ class BuildEnvironment(object):
self.config.trim_footnote_reference_space self.config.trim_footnote_reference_space
self.settings['gettext_compact'] = self.config.gettext_compact self.settings['gettext_compact'] = self.config.gettext_compact
language = self.config.language or 'en' self.settings['language_code'] = self.config.language or 'en'
self.settings['language_code'] = language
if 'smart_quotes' not in self.settings:
self.settings['smart_quotes'] = True
# confirm selected language supports smart_quotes or not # Allow to disable by 3rd party extension (workaround)
for tag in normalize_language_tag(language): self.settings.setdefault('smart_quotes', True)
if tag in smartchars.quotes:
break
else:
self.settings['smart_quotes'] = False
def read_doc(self, docname, app=None): def read_doc(self, docname, app=None):
# type: (unicode, Sphinx) -> None # type: (unicode, Sphinx) -> None

View File

@ -117,7 +117,11 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_
text += '\n' text += '\n'
# build a list of directories that are szvpackages (contain an INITPY file) # build a list of directories that are szvpackages (contain an INITPY file)
subs = [sub for sub in subs if path.isfile(path.join(root, sub, INITPY))] # and also checks the INITPY file is not empty, or there are other python
# source files in that folder.
# (depending on settings - but shall_skip() takes care of that)
subs = [sub for sub in subs if not
shall_skip(path.join(root, sub, INITPY), opts)]
# if there are some package directories, add a TOC for theses subpackages # if there are some package directories, add a TOC for theses subpackages
if subs: if subs:
text += format_heading(2, 'Subpackages') text += format_heading(2, 'Subpackages')

View File

@ -14,17 +14,15 @@
import re import re
import sys import sys
import inspect import inspect
import traceback import warnings
from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, string_types from six import iteritems, itervalues, text_type, class_types, string_types
from docutils import nodes
from docutils.utils import assemble_option_dict
from docutils.parsers.rst import Directive
from docutils.statemachine import ViewList from docutils.statemachine import ViewList
import sphinx import sphinx
from sphinx.ext.autodoc.importer import mock, import_module from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.ext.autodoc.importer import mock, import_object, get_object_members
from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA from sphinx.ext.autodoc.importer import _MockImporter # to keep compatibility # NOQA
from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA from sphinx.ext.autodoc.inspector import format_annotation, formatargspec # to keep compatibility # NOQA
from sphinx.util import rpartition, force_decode from sphinx.util import rpartition, force_decode
@ -32,21 +30,23 @@ from sphinx.locale import _
from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.application import ExtensionError from sphinx.application import ExtensionError
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.nodes import nested_parse_with_titles
from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \ from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \
safe_getattr, object_description, is_builtin_class_method, \ safe_getattr, object_description, is_builtin_class_method, \
isenumclass, isenumattribute, getdoc isenumattribute, getdoc
from sphinx.util.docstrings import prepare_docstring from sphinx.util.docstrings import prepare_docstring
if False: if False:
# For type annotation # For type annotation
from types import ModuleType # NOQA from types import ModuleType # NOQA
from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union # NOQA from typing import Any, Callable, Dict, Iterator, List, Sequence, Set, Tuple, Type, Union # NOQA
from docutils import nodes # NOQA
from docutils.utils import Reporter # NOQA from docutils.utils import Reporter # NOQA
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
from sphinx.ext.autodoc.directive import DocumenterBridge # NOQA
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# This type isn't exposed directly in any modules, but can be found # This type isn't exposed directly in any modules, but can be found
# here in most Python versions # here in most Python versions
MethodDescriptorType = type(type.__subclasses__) MethodDescriptorType = type(type.__subclasses__)
@ -63,42 +63,11 @@ py_ext_sig_re = re.compile(
''', re.VERBOSE) ''', re.VERBOSE)
class DefDict(dict):
"""A dict that returns a default on nonexisting keys."""
def __init__(self, default):
# type: (Any) -> None
dict.__init__(self)
self.default = default
def __getitem__(self, key):
# type: (Any) -> Any
try:
return dict.__getitem__(self, key)
except KeyError:
return self.default
def __bool__(self):
# type: () -> bool
# docutils check "if option_spec"
return True
__nonzero__ = __bool__ # for python2 compatibility
def identity(x): def identity(x):
# type: (Any) -> Any # type: (Any) -> Any
return x return x
class Options(dict):
"""A dict/attribute hybrid that returns None on nonexisting keys."""
def __getattr__(self, name):
# type: (unicode) -> Any
try:
return self[name.replace('_', '-')]
except KeyError:
return None
ALL = object() ALL = object()
INSTANCEATTR = object() INSTANCEATTR = object()
@ -146,6 +115,9 @@ class AutodocReporter(object):
""" """
def __init__(self, viewlist, reporter): def __init__(self, viewlist, reporter):
# type: (ViewList, Reporter) -> None # type: (ViewList, Reporter) -> None
warnings.warn('AutodocReporter is now deprecated. '
'Use sphinx.util.docutils.switch_source_input() instead.',
RemovedInSphinx20Warning)
self.viewlist = viewlist self.viewlist = viewlist
self.reporter = reporter self.reporter = reporter
@ -284,14 +256,10 @@ class Documenter(object):
option_spec = {'noindex': bool_option} # type: Dict[unicode, Callable] option_spec = {'noindex': bool_option} # type: Dict[unicode, Callable]
@staticmethod def get_attr(self, obj, name, *defargs):
def get_attr(obj, name, *defargs):
# type: (Any, unicode, Any) -> Any # type: (Any, unicode, Any) -> Any
"""getattr() override for types such as Zope interfaces.""" """getattr() override for types such as Zope interfaces."""
for typ, func in iteritems(AutoDirective._special_attrgetters): return autodoc_attrgetter(self.env.app, obj, name, *defargs)
if isinstance(obj, typ):
return func(obj, name, *defargs)
return safe_getattr(obj, name, *defargs)
@classmethod @classmethod
def can_document_member(cls, member, membername, isattr, parent): def can_document_member(cls, member, membername, isattr, parent):
@ -300,7 +268,7 @@ class Documenter(object):
raise NotImplementedError('must be implemented in subclasses') raise NotImplementedError('must be implemented in subclasses')
def __init__(self, directive, name, indent=u''): def __init__(self, directive, name, indent=u''):
# type: (Directive, unicode, unicode) -> None # type: (DocumenterBridge, unicode, unicode) -> None
self.directive = directive self.directive = directive
self.env = directive.env self.env = directive.env
self.options = directive.genopt self.options = directive.genopt
@ -324,6 +292,12 @@ class Documenter(object):
# the module analyzer to get at attribute docs, or None # the module analyzer to get at attribute docs, or None
self.analyzer = None # type: Any self.analyzer = None # type: Any
@property
def documenters(self):
# type: () -> Dict[unicode, Type[Documenter]]
"""Returns registered Documenter classes"""
return get_documenters(self.env.app)
def add_line(self, line, source, *lineno): def add_line(self, line, source, *lineno):
# type: (unicode, unicode, int) -> None # type: (unicode, unicode, int) -> None
"""Append one line of generated reST to the output.""" """Append one line of generated reST to the output."""
@ -354,8 +328,7 @@ class Documenter(object):
explicit_modname, path, base, args, retann = \ explicit_modname, path, base, args, retann = \
py_ext_sig_re.match(self.name).groups() # type: ignore py_ext_sig_re.match(self.name).groups() # type: ignore
except AttributeError: except AttributeError:
self.directive.warn('invalid signature for auto%s (%r)' % logger.warning('invalid signature for auto%s (%r)' % (self.objtype, self.name))
(self.objtype, self.name))
return False return False
# support explicit module and class name separation via :: # support explicit module and class name separation via ::
@ -384,56 +357,15 @@ class Documenter(object):
Returns True if successful, False if an error occurred. Returns True if successful, False if an error occurred.
""" """
if self.objpath:
logger.debug('[autodoc] from %s import %s',
self.modname, '.'.join(self.objpath))
# always enable mock import hook
# it will do nothing if autodoc_mock_imports is empty
with mock(self.env.config.autodoc_mock_imports): with mock(self.env.config.autodoc_mock_imports):
try: try:
logger.debug('[autodoc] import %s', self.modname) ret = import_object(self.modname, self.objpath, self.objtype,
obj = import_module(self.modname, self.env.config.autodoc_warningiserror) attrgetter=self.get_attr,
parent = None warningiserror=self.env.config.autodoc_warningiserror)
self.module = obj self.module, self.parent, self.object_name, self.object = ret
logger.debug('[autodoc] => %r', obj)
for part in self.objpath:
parent = obj
logger.debug('[autodoc] getattr(_, %r)', part)
obj = self.get_attr(obj, part)
logger.debug('[autodoc] => %r', obj)
self.object_name = part
self.parent = parent
self.object = obj
return True return True
except (AttributeError, ImportError) as exc: except ImportError as exc:
if self.objpath: logger.warning(exc.args[0])
errmsg = 'autodoc: failed to import %s %r from module %r' % \
(self.objtype, '.'.join(self.objpath), self.modname)
else:
errmsg = 'autodoc: failed to import %s %r' % \
(self.objtype, self.fullname)
if isinstance(exc, ImportError):
# import_module() raises ImportError having real exception obj and
# traceback
real_exc, traceback_msg = exc.args
if isinstance(real_exc, SystemExit):
errmsg += ('; the module executes module level statement ' +
'and it might call sys.exit().')
elif isinstance(real_exc, ImportError):
errmsg += ('; the following exception was raised:\n%s' %
real_exc.args[0])
else:
errmsg += ('; the following exception was raised:\n%s' %
traceback_msg)
else:
errmsg += ('; the following exception was raised:\n%s' %
traceback.format_exc())
if PY2:
errmsg = errmsg.decode('utf-8') # type: ignore
logger.debug(errmsg)
self.directive.warn(errmsg)
self.env.note_reread() self.env.note_reread()
return False return False
@ -493,8 +425,8 @@ class Documenter(object):
try: try:
args = self.format_args() args = self.format_args()
except Exception as err: except Exception as err:
self.directive.warn('error while formatting arguments for ' logger.warning('error while formatting arguments for %s: %s' %
'%s: %s' % (self.fullname, err)) (self.fullname, err))
args = None args = None
retann = self.retann retann = self.retann
@ -606,57 +538,24 @@ class Documenter(object):
If *want_all* is True, return all members. Else, only return those If *want_all* is True, return all members. Else, only return those
members given by *self.options.members* (which may also be none). members given by *self.options.members* (which may also be none).
""" """
analyzed_member_names = set() members = get_object_members(self.object, self.objpath, self.get_attr, self.analyzer)
if self.analyzer:
attr_docs = self.analyzer.find_attr_docs()
namespace = '.'.join(self.objpath)
for item in iteritems(attr_docs):
if item[0][0] == namespace:
analyzed_member_names.add(item[0][1])
if not want_all: if not want_all:
if not self.options.members: if not self.options.members:
return False, [] return False, []
# specific members given # specific members given
members = [] selected = []
for mname in self.options.members: for name in self.options.members:
try: if name in members:
members.append((mname, self.get_attr(self.object, mname))) selected.append((name, members[name].value))
except AttributeError: else:
if mname not in analyzed_member_names: logger.warning('missing attribute %s in object %s' %
self.directive.warn('missing attribute %s in object %s' (name, self.fullname))
% (mname, self.fullname)) return False, sorted(selected)
elif self.options.inherited_members: elif self.options.inherited_members:
# safe_getmembers() uses dir() which pulls in members from all return False, sorted((m.name, m.value) for m in itervalues(members))
# base classes
members = safe_getmembers(self.object, attr_getter=self.get_attr)
else: else:
# __dict__ contains only the members directly defined in return False, sorted((m.name, m.value) for m in itervalues(members)
# the class (but get them via getattr anyway, to e.g. get if m.directly_defined)
# unbound method objects instead of function objects);
# using list(iterkeys()) because apparently there are objects for which
# __dict__ changes while getting attributes
try:
obj_dict = self.get_attr(self.object, '__dict__')
except AttributeError:
members = []
else:
members = [(mname, self.get_attr(self.object, mname, None))
for mname in list(iterkeys(obj_dict))]
# Py34 doesn't have enum members in __dict__.
if isenumclass(self.object):
members.extend(
item for item in self.object.__members__.items()
if item not in members
)
membernames = set(m[0] for m in members)
# add instance attributes from the analyzer
for aname in analyzed_member_names:
if aname not in membernames and \
(want_all or aname in self.options.members):
members.append((aname, INSTANCEATTR))
return False, sorted(members)
def filter_members(self, members, want_all): def filter_members(self, members, want_all):
# type: (List[Tuple[unicode, Any]], bool) -> List[Tuple[unicode, Any, bool]] # type: (List[Tuple[unicode, Any]], bool) -> List[Tuple[unicode, Any, bool]]
@ -715,8 +614,7 @@ class Documenter(object):
elif (namespace, membername) in attr_docs: elif (namespace, membername) in attr_docs:
if want_all and membername.startswith('_'): if want_all and membername.startswith('_'):
# ignore members whose name starts with _ by default # ignore members whose name starts with _ by default
keep = self.options.private_members and \ keep = self.options.private_members
(has_doc or self.options.undoc_members)
else: else:
# keep documented attributes # keep documented attributes
keep = True keep = True
@ -769,7 +667,7 @@ class Documenter(object):
# document non-skipped members # document non-skipped members
memberdocumenters = [] # type: List[Tuple[Documenter, bool]] memberdocumenters = [] # type: List[Tuple[Documenter, bool]]
for (mname, member, isattr) in self.filter_members(members, want_all): for (mname, member, isattr) in self.filter_members(members, want_all):
classes = [cls for cls in itervalues(AutoDirective._registry) classes = [cls for cls in itervalues(self.documenters)
if cls.can_document_member(member, mname, isattr, self)] if cls.can_document_member(member, mname, isattr, self)]
if not classes: if not classes:
# don't know how to document this member # don't know how to document this member
@ -820,11 +718,11 @@ class Documenter(object):
""" """
if not self.parse_name(): if not self.parse_name():
# need a module to import # need a module to import
self.directive.warn( logger.warning(
'don\'t know which module to import for autodocumenting ' 'don\'t know which module to import for autodocumenting '
'%r (try placing a "module" or "currentmodule" directive ' '%r (try placing a "module" or "currentmodule" directive '
'in the document, or giving an explicit module name)' 'in the document, or giving an explicit module name)' %
% self.name) self.name)
return return
# now, import the module and get object to document # now, import the module and get object to document
@ -910,14 +808,14 @@ class ModuleDocumenter(Documenter):
def resolve_name(self, modname, parents, path, base): def resolve_name(self, modname, parents, path, base):
# type: (str, Any, str, Any) -> Tuple[str, List[unicode]] # type: (str, Any, str, Any) -> Tuple[str, List[unicode]]
if modname is not None: if modname is not None:
self.directive.warn('"::" in automodule name doesn\'t make sense') logger.warning('"::" in automodule name doesn\'t make sense')
return (path or '') + base, [] return (path or '') + base, []
def parse_name(self): def parse_name(self):
# type: () -> bool # type: () -> bool
ret = Documenter.parse_name(self) ret = Documenter.parse_name(self)
if self.args or self.retann: if self.args or self.retann:
self.directive.warn('signature arguments or return annotation ' logger.warning('signature arguments or return annotation '
'given for automodule %s' % self.fullname) 'given for automodule %s' % self.fullname)
return ret return ret
@ -950,7 +848,7 @@ class ModuleDocumenter(Documenter):
# Sometimes __all__ is broken... # Sometimes __all__ is broken...
if not isinstance(memberlist, (list, tuple)) or not \ if not isinstance(memberlist, (list, tuple)) or not \
all(isinstance(entry, string_types) for entry in memberlist): all(isinstance(entry, string_types) for entry in memberlist):
self.directive.warn( logger.warning(
'__all__ should be a list of strings, not %r ' '__all__ should be a list of strings, not %r '
'(in module %s) -- ignoring __all__' % '(in module %s) -- ignoring __all__' %
(memberlist, self.fullname)) (memberlist, self.fullname))
@ -963,10 +861,10 @@ class ModuleDocumenter(Documenter):
try: try:
ret.append((mname, safe_getattr(self.object, mname))) ret.append((mname, safe_getattr(self.object, mname)))
except AttributeError: except AttributeError:
self.directive.warn( logger.warning(
'missing attribute mentioned in :members: or __all__: ' 'missing attribute mentioned in :members: or __all__: '
'module %s, attribute %s' % ( 'module %s, attribute %s' %
safe_getattr(self.object, '__name__', '???'), mname)) (safe_getattr(self.object, '__name__', '???'), mname))
return False, ret return False, ret
@ -1505,118 +1403,56 @@ class InstanceAttributeDocumenter(AttributeDocumenter):
AttributeDocumenter.add_content(self, more_content, no_docstring=True) AttributeDocumenter.add_content(self, more_content, no_docstring=True)
class AutoDirective(Directive): class DeprecatedDict(dict):
""" def __init__(self, message):
The AutoDirective class is used for all autodoc directives. It dispatches self.message = message
most of the work to one of the Documenters, which it selects through its super(DeprecatedDict, self).__init__()
*_registry* dictionary.
The *_special_attrgetters* attribute is used to customize ``getattr()`` def __setitem__(self, key, value):
calls that the Documenters make; its entries are of the form ``type: warnings.warn(self.message, RemovedInSphinx20Warning)
getattr_function``. super(DeprecatedDict, self).__setitem__(key, value)
def setdefault(self, key, default=None):
warnings.warn(self.message, RemovedInSphinx20Warning)
super(DeprecatedDict, self).setdefault(key, default)
def update(self, other=None):
warnings.warn(self.message, RemovedInSphinx20Warning)
super(DeprecatedDict, self).update(other)
class AutodocRegistry(object):
"""
A registry of Documenters and attrgetters.
Note: When importing an object, all items along the import chain are Note: When importing an object, all items along the import chain are
accessed using the descendant's *_special_attrgetters*, thus this accessed using the descendant's *_special_attrgetters*, thus this
dictionary should include all necessary functions for accessing dictionary should include all necessary functions for accessing
attributes of the parents. attributes of the parents.
""" """
# a registry of objtype -> documenter class # a registry of objtype -> documenter class (Deprecated)
_registry = {} # type: Dict[unicode, Type[Documenter]] _registry = DeprecatedDict(
'AutoDirective._registry has been deprecated. '
'Please use app.add_autodocumenter() instead.'
) # type: Dict[unicode, Type[Documenter]]
# a registry of type -> getattr function # a registry of type -> getattr function
_special_attrgetters = {} # type: Dict[Type, Callable] _special_attrgetters = DeprecatedDict(
'AutoDirective._special_attrgetters has been deprecated. '
'Please use app.add_autodoc_attrgetter() instead.'
) # type: Dict[Type, Callable]
# flags that can be given in autodoc_default_flags
_default_flags = set([
'members', 'undoc-members', 'inherited-members', 'show-inheritance',
'private-members', 'special-members', 'ignore-module-all'
])
# standard docutils directive settings AutoDirective = AutodocRegistry # for backward compatibility
has_content = True
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
# allow any options to be passed; the options are parsed further
# by the selected Documenter
option_spec = DefDict(identity)
def warn(self, msg):
# type: (unicode) -> None
self.warnings.append(self.reporter.warning(msg, line=self.lineno))
def run(self):
# type: () -> List[nodes.Node]
self.filename_set = set() # type: Set[unicode]
# a set of dependent filenames
self.reporter = self.state.document.reporter
self.env = self.state.document.settings.env
self.warnings = [] # type: List[unicode]
self.result = ViewList()
try:
source, lineno = self.reporter.get_source_and_line(self.lineno)
except AttributeError:
source = lineno = None
logger.debug('[autodoc] %s:%s: input:\n%s',
source, lineno, self.block_text)
# find out what documenter to call
objtype = self.name[4:]
doc_class = self._registry[objtype]
# add default flags
for flag in self._default_flags:
if flag not in doc_class.option_spec:
continue
negated = self.options.pop('no-' + flag, 'not given') is None
if flag in self.env.config.autodoc_default_flags and \
not negated:
self.options[flag] = None
# process the options with the selected documenter's option_spec
try:
self.genopt = Options(assemble_option_dict(
self.options.items(), doc_class.option_spec))
except (KeyError, ValueError, TypeError) as err:
# an option is either unknown or has a wrong type
msg = self.reporter.error('An option to %s is either unknown or '
'has an invalid value: %s' % (self.name, err),
line=self.lineno)
return [msg]
# generate the output
documenter = doc_class(self, self.arguments[0])
documenter.generate(more_content=self.content)
if not self.result:
return self.warnings
logger.debug('[autodoc] output:\n%s', '\n'.join(self.result))
# record all filenames as dependencies -- this will at least
# partially make automatic invalidation possible
for fn in self.filename_set:
self.state.document.settings.record_dependencies.add(fn)
# use a custom reporter that correctly assigns lines to source
# filename/description and lineno
old_reporter = self.state.memo.reporter
self.state.memo.reporter = AutodocReporter(self.result,
self.state.memo.reporter)
if documenter.titles_allowed:
node = nodes.section()
# necessary so that the child nodes get the right source/line set
node.document = self.state.document
nested_parse_with_titles(self.state, self.result, node)
else:
node = nodes.paragraph()
node.document = self.state.document
self.state.nested_parse(self.result, 0, node)
self.state.memo.reporter = old_reporter
return self.warnings + node.children
def add_documenter(cls): def add_documenter(cls):
# type: (Type[Documenter]) -> None # type: (Type[Documenter]) -> None
"""Register a new Documenter.""" """Register a new Documenter."""
warnings.warn('sphinx.ext.autodoc.add_documenter() has been deprecated. '
'Please use app.add_autodocumenter() instead.',
RemovedInSphinx20Warning)
if not issubclass(cls, Documenter): if not issubclass(cls, Documenter):
raise ExtensionError('autodoc documenter %r must be a subclass ' raise ExtensionError('autodoc documenter %r must be a subclass '
'of Documenter' % cls) 'of Documenter' % cls)
@ -1627,6 +1463,29 @@ def add_documenter(cls):
AutoDirective._registry[cls.objtype] = cls AutoDirective._registry[cls.objtype] = cls
def get_documenters(app):
# type: (Sphinx) -> Dict[unicode, Type[Documenter]]
"""Returns registered Documenter classes"""
classes = dict(AutoDirective._registry) # registered directly
if app:
classes.update(app.registry.documenters) # registered by API
return classes
def autodoc_attrgetter(app, obj, name, *defargs):
# type: (Sphinx, Any, unicode, Any) -> Any
"""Alternative getattr() for types"""
candidates = dict(AutoDirective._special_attrgetters)
if app:
candidates.update(app.registry.autodoc_attrgettrs)
for typ, func in iteritems(candidates):
if isinstance(obj, typ):
return func(obj, name, *defargs)
return safe_getattr(obj, name, *defargs)
def setup(app): def setup(app):
# type: (Sphinx) -> Dict[unicode, Any] # type: (Sphinx) -> Dict[unicode, Any]
app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ModuleDocumenter)

View File

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
"""
sphinx.ext.autodoc.directive
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
: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
from docutils.statemachine import ViewList
from docutils.utils import assemble_option_dict
from sphinx.ext.autodoc import get_documenters
from sphinx.util import logging
from sphinx.util.docutils import switch_source_input
from sphinx.util.nodes import nested_parse_with_titles
if False:
# For type annotation
from typing import Any, Dict, List, Set, Type # NOQA
from docutils.statemachine import State, StateMachine, StringList # NOQA
from docutils.utils import Reporter # NOQA
from sphinx.config import Config # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc import Documenter # NOQA
logger = logging.getLogger(__name__)
# common option names for autodoc directives
AUTODOC_DEFAULT_OPTIONS = ['members', 'undoc-members', 'inherited-members',
'show-inheritance', 'private-members', 'special-members',
'ignore-module-all']
class DummyOptionSpec(object):
"""An option_spec allows any options."""
def __getitem__(self, key):
# type: (Any) -> Any
return lambda x: x
class Options(dict):
"""A dict/attribute hybrid that returns None on nonexisting keys."""
def __getattr__(self, name):
# type: (unicode) -> Any
try:
return self[name.replace('_', '-')]
except KeyError:
return None
class DocumenterBridge(object):
"""A parameters container for Documenters."""
def __init__(self, env, reporter, options, lineno):
# type: (BuildEnvironment, Reporter, Options, int) -> None
self.env = env
self.reporter = reporter
self.genopt = options
self.lineno = lineno
self.filename_set = set() # type: Set[unicode]
self.result = ViewList()
def warn(self, msg):
# type: (unicode) -> None
logger.warning(msg, line=self.lineno)
def process_documenter_options(documenter, config, options):
# type: (Type[Documenter], Config, Dict) -> Options
"""Recognize options of Documenter from user input."""
for name in AUTODOC_DEFAULT_OPTIONS:
if name not in documenter.option_spec:
continue
else:
negated = options.pop('no-' + name, True) is None
if name in config.autodoc_default_flags and not negated:
options[name] = None
return Options(assemble_option_dict(options.items(), documenter.option_spec))
def parse_generated_content(state, content, documenter):
# type: (State, StringList, Documenter) -> List[nodes.Node]
"""Parse a generated content by Documenter."""
with switch_source_input(state, content):
if documenter.titles_allowed:
node = nodes.section()
# necessary so that the child nodes get the right source/line set
node.document = state.document
nested_parse_with_titles(state, content, node)
else:
node = nodes.paragraph()
node.document = state.document
state.nested_parse(content, 0, node)
return node.children
class AutodocDirective(Directive):
"""A directive class for all autodoc directives. It works as a dispatcher of Documenters.
It invokes a Documenter on running. After the processing, it parses and returns
the generated content by Documenter.
"""
option_spec = DummyOptionSpec()
has_content = True
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
def run(self):
# type: () -> List[nodes.Node]
env = self.state.document.settings.env
reporter = self.state.document.reporter
try:
source, lineno = reporter.get_source_and_line(self.lineno)
except AttributeError:
source, lineno = (None, None)
logger.debug('[autodoc] %s:%s: input:\n%s', source, lineno, self.block_text)
# look up target Documenter
objtype = self.name[4:] # strip prefix (auto-).
doccls = get_documenters(env.app)[objtype]
# process the options with the selected documenter's option_spec
try:
documenter_options = process_documenter_options(doccls, env.config, self.options)
except (KeyError, ValueError, TypeError) as exc:
# an option is either unknown or has a wrong type
logger.error('An option to %s is either unknown or has an invalid value: %s' %
(self.name, exc), line=lineno)
return []
# generate the output
params = DocumenterBridge(env, reporter, documenter_options, lineno)
documenter = doccls(params, self.arguments[0])
documenter.generate(more_content=self.content)
if not params.result:
return []
logger.debug('[autodoc] output:\n%s', '\n'.join(params.result))
# record all filenames as dependencies -- this will at least
# partially make automatic invalidation possible
for fn in params.filename_set:
self.state.document.settings.record_dependencies.add(fn)
result = parse_generated_content(self.state, params.result, documenter)
return result

View File

@ -13,13 +13,17 @@ import sys
import warnings import warnings
import traceback import traceback
import contextlib import contextlib
from collections import namedtuple
from types import FunctionType, MethodType, ModuleType from types import FunctionType, MethodType, ModuleType
from six import PY2
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.inspect import isenumclass, safe_getattr
if False: if False:
# For type annotation # For type annotation
from typing import Any, Generator, List, Set # NOQA from typing import Any, Callable, Dict, Generator, List, Optional # NOQA
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -80,13 +84,7 @@ class _MockModule(ModuleType):
class _MockImporter(object): class _MockImporter(object):
def __init__(self, names): def __init__(self, names):
# type: (List[str]) -> None # type: (List[str]) -> None
self.base_packages = set() # type: Set[str] self.names = names
for n in names:
# Convert module names:
# ['a.b.c', 'd.e']
# to a set of base packages:
# set(['a', 'd'])
self.base_packages.add(n.split('.')[0])
self.mocked_modules = [] # type: List[str] self.mocked_modules = [] # type: List[str]
# enable hook by adding itself to meta_path # enable hook by adding itself to meta_path
sys.meta_path = sys.meta_path + [self] sys.meta_path = sys.meta_path + [self]
@ -102,8 +100,9 @@ class _MockImporter(object):
def find_module(self, name, path=None): def find_module(self, name, path=None):
# type: (str, str) -> Any # type: (str, str) -> Any
base_package = name.split('.')[0] # check if name is (or is a descendant of) one of our base_packages
if base_package in self.base_packages: for n in self.names:
if n == name or name.startswith(n + '.'):
return self return self
return None return None
@ -144,3 +143,86 @@ def import_module(modname, warningiserror=False):
# Importing modules may cause any side effects, including # Importing modules may cause any side effects, including
# SystemExit, so we need to catch all errors. # SystemExit, so we need to catch all errors.
raise ImportError(exc, traceback.format_exc()) raise ImportError(exc, traceback.format_exc())
def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warningiserror=False):
# type: (str, List[unicode], str, Callable[[Any, unicode], Any], bool) -> Any
if objpath:
logger.debug('[autodoc] from %s import %s', modname, '.'.join(objpath))
else:
logger.debug('[autodoc] import %s', modname)
try:
module = import_module(modname, warningiserror=warningiserror)
logger.debug('[autodoc] => %r', module)
obj = module
parent = None
object_name = None
for attrname in objpath:
parent = obj
logger.debug('[autodoc] getattr(_, %r)', attrname)
obj = attrgetter(obj, attrname)
logger.debug('[autodoc] => %r', obj)
object_name = attrname
return [module, parent, object_name, obj]
except (AttributeError, ImportError) as exc:
if objpath:
errmsg = ('autodoc: failed to import %s %r from module %r' %
(objtype, '.'.join(objpath), modname))
else:
errmsg = 'autodoc: failed to import %s %r' % (objtype, modname)
if isinstance(exc, ImportError):
# import_module() raises ImportError having real exception obj and
# traceback
real_exc, traceback_msg = exc.args
if isinstance(real_exc, SystemExit):
errmsg += ('; the module executes module level statement '
'and it might call sys.exit().')
elif isinstance(real_exc, ImportError):
errmsg += '; the following exception was raised:\n%s' % real_exc.args[0]
else:
errmsg += '; the following exception was raised:\n%s' % traceback_msg
else:
errmsg += '; the following exception was raised:\n%s' % traceback.format_exc()
if PY2:
errmsg = errmsg.decode('utf-8') # type: ignore
logger.debug(errmsg)
raise ImportError(errmsg)
Attribute = namedtuple('Attribute', ['name', 'directly_defined', 'value'])
def get_object_members(subject, objpath, attrgetter, analyzer=None):
# type: (Any, List[unicode], Callable, Any) -> Dict[str, Attribute] # NOQA
"""Get members and attributes of target object."""
# the members directly defined in the class
obj_dict = attrgetter(subject, '__dict__', {})
# Py34 doesn't have enum members in __dict__.
if sys.version_info[:2] == (3, 4) and isenumclass(subject):
obj_dict = dict(obj_dict)
for name, value in subject.__members__.items():
obj_dict[name] = value
members = {}
for name in dir(subject):
try:
value = attrgetter(subject, name)
directly_defined = name in obj_dict
members[name] = Attribute(name, directly_defined, value)
except AttributeError:
continue
if analyzer:
# append instance attributes (cf. self.attr1) if analyzer knows
from sphinx.ext.autodoc import INSTANCEATTR
namespace = '.'.join(objpath)
for (ns, name) in analyzer.find_attr_docs():
if namespace == ns and name not in members:
members[name] = Attribute(name, True, INSTANCEATTR)
return members

View File

@ -72,7 +72,8 @@ from sphinx import addnodes
from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.adapters.toctree import TocTree
from sphinx.util import import_object, rst, logging from sphinx.util import import_object, rst, logging
from sphinx.pycode import ModuleAnalyzer, PycodeError from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.ext.autodoc import Options from sphinx.ext.autodoc import get_documenters
from sphinx.ext.autodoc.directive import DocumenterBridge, Options
from sphinx.ext.autodoc.importer import import_module from sphinx.ext.autodoc.importer import import_module
if False: if False:
@ -153,13 +154,13 @@ def autosummary_table_visit_html(self, node):
# -- autodoc integration ------------------------------------------------------- # -- autodoc integration -------------------------------------------------------
class FakeDirective(object): class FakeDirective(DocumenterBridge):
env = {} # type: Dict def __init__(self):
genopt = Options() super(FakeDirective, self).__init__({}, None, Options(), 0) # type: ignore
def get_documenter(obj, parent): def get_documenter(app, obj, parent):
# type: (Any, Any) -> Type[Documenter] # type: (Sphinx, Any, Any) -> Type[Documenter]
"""Get an autodoc.Documenter class suitable for documenting the given """Get an autodoc.Documenter class suitable for documenting the given
object. object.
@ -167,8 +168,7 @@ def get_documenter(obj, parent):
another Python object (e.g. a module or a class) to which *obj* another Python object (e.g. a module or a class) to which *obj*
belongs to. belongs to.
""" """
from sphinx.ext.autodoc import AutoDirective, DataDocumenter, \ from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter
ModuleDocumenter
if inspect.ismodule(obj): if inspect.ismodule(obj):
# ModuleDocumenter.can_document_member always returns False # ModuleDocumenter.can_document_member always returns False
@ -176,7 +176,7 @@ def get_documenter(obj, parent):
# Construct a fake documenter for *parent* # Construct a fake documenter for *parent*
if parent is not None: if parent is not None:
parent_doc_cls = get_documenter(parent, None) parent_doc_cls = get_documenter(app, parent, None)
else: else:
parent_doc_cls = ModuleDocumenter parent_doc_cls = ModuleDocumenter
@ -186,7 +186,7 @@ def get_documenter(obj, parent):
parent_doc = parent_doc_cls(FakeDirective(), "") parent_doc = parent_doc_cls(FakeDirective(), "")
# Get the corrent documenter class for *obj* # Get the corrent documenter class for *obj*
classes = [cls for cls in AutoDirective._registry.values() classes = [cls for cls in get_documenters(app).values()
if cls.can_document_member(obj, '', False, parent_doc)] if cls.can_document_member(obj, '', False, parent_doc)]
if classes: if classes:
classes.sort(key=lambda cls: cls.priority) classes.sort(key=lambda cls: cls.priority)
@ -289,7 +289,7 @@ class Autosummary(Directive):
full_name = modname + '::' + full_name[len(modname) + 1:] full_name = modname + '::' + full_name[len(modname) + 1:]
# NB. using full_name here is important, since Documenters # NB. using full_name here is important, since Documenters
# handle module prefixes slightly differently # handle module prefixes slightly differently
documenter = get_documenter(obj, parent)(self, full_name) documenter = get_documenter(self.env.app, obj, parent)(self, full_name)
if not documenter.parse_name(): if not documenter.parse_name():
self.warn('failed to parse name %s' % real_name) self.warn('failed to parse name %s' % real_name)
items.append((display_name, '', '', real_name)) items.append((display_name, '', '', real_name))
@ -325,7 +325,7 @@ class Autosummary(Directive):
# -- Grab the summary # -- Grab the summary
documenter.add_content(None) documenter.add_content(None)
doc = list(documenter.process_doc([self.result.data])) doc = self.result.data
while doc and not doc[0].strip(): while doc and not doc[0].strip():
doc.pop(0) doc.pop(0)
@ -615,7 +615,8 @@ def process_generate_options(app):
generate_autosummary_docs(genfiles, builder=app.builder, generate_autosummary_docs(genfiles, builder=app.builder,
warn=logger.warning, info=logger.info, warn=logger.warning, info=logger.info,
suffix=suffix, base_path=app.srcdir) suffix=suffix, base_path=app.srcdir,
app=app)
def setup(app): def setup(app):

View File

@ -33,24 +33,11 @@ from sphinx import __display_version__
from sphinx import package_dir from sphinx import package_dir
from sphinx.ext.autosummary import import_by_name, get_documenter from sphinx.ext.autosummary import import_by_name, get_documenter
from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.jinja2glue import BuiltinTemplateLoader
from sphinx.registry import SphinxComponentRegistry
from sphinx.util.osutil import ensuredir from sphinx.util.osutil import ensuredir
from sphinx.util.inspect import safe_getattr from sphinx.util.inspect import safe_getattr
from sphinx.util.rst import escape as rst_escape from sphinx.util.rst import escape as rst_escape
# Add documenters to AutoDirective registry
from sphinx.ext.autodoc import add_documenter, \
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter, \
FunctionDocumenter, MethodDocumenter, AttributeDocumenter, \
InstanceAttributeDocumenter
add_documenter(ModuleDocumenter)
add_documenter(ClassDocumenter)
add_documenter(ExceptionDocumenter)
add_documenter(DataDocumenter)
add_documenter(FunctionDocumenter)
add_documenter(MethodDocumenter)
add_documenter(AttributeDocumenter)
add_documenter(InstanceAttributeDocumenter)
if False: if False:
# For type annotation # For type annotation
from typing import Any, Callable, Dict, Tuple, List # NOQA from typing import Any, Callable, Dict, Tuple, List # NOQA
@ -60,6 +47,30 @@ if False:
from sphinx.environment import BuildEnvironment # NOQA from sphinx.environment import BuildEnvironment # NOQA
class DummyApplication(object):
"""Dummy Application class for sphinx-autogen command."""
def __init__(self):
# type: () -> None
self.registry = SphinxComponentRegistry()
def setup_documenters(app):
# type: (Any) -> None
from sphinx.ext.autodoc import (
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
FunctionDocumenter, MethodDocumenter, AttributeDocumenter,
InstanceAttributeDocumenter
)
documenters = [
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
FunctionDocumenter, MethodDocumenter, AttributeDocumenter,
InstanceAttributeDocumenter
]
for documenter in documenters:
app.registry.add_documenter(documenter.objtype, documenter)
def _simple_info(msg): def _simple_info(msg):
# type: (unicode) -> None # type: (unicode) -> None
print(msg) print(msg)
@ -81,8 +92,8 @@ def _underline(title, line='='):
def generate_autosummary_docs(sources, output_dir=None, suffix='.rst', def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
warn=_simple_warn, info=_simple_info, warn=_simple_warn, info=_simple_info,
base_path=None, builder=None, template_dir=None, base_path=None, builder=None, template_dir=None,
imported_members=False): imported_members=False, app=None):
# type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool) -> None # NOQA # type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool, Any) -> None # NOQA
showed_sources = list(sorted(sources)) showed_sources = list(sorted(sources))
if len(showed_sources) > 20: if len(showed_sources) > 20:
@ -148,7 +159,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
new_files.append(fn) new_files.append(fn)
with open(fn, 'w') as f: with open(fn, 'w') as f:
doc = get_documenter(obj, parent) doc = get_documenter(app, obj, parent)
if template_name is not None: if template_name is not None:
template = template_env.get_template(template_name) template = template_env.get_template(template_name)
@ -167,7 +178,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
value = safe_getattr(obj, name) value = safe_getattr(obj, name)
except AttributeError: except AttributeError:
continue continue
documenter = get_documenter(value, obj) documenter = get_documenter(app, value, obj)
if documenter.objtype == typ: if documenter.objtype == typ:
if typ == 'method': if typ == 'method':
items.append(name) items.append(name)
@ -392,11 +403,14 @@ The format of the autosummary directive is documented in the
def main(argv=sys.argv[1:]): def main(argv=sys.argv[1:]):
# type: (List[str]) -> None # type: (List[str]) -> None
app = DummyApplication()
setup_documenters(app)
args = get_parser().parse_args(argv) args = get_parser().parse_args(argv)
generate_autosummary_docs(args.source_file, args.output_dir, generate_autosummary_docs(args.source_file, args.output_dir,
'.' + args.suffix, '.' + args.suffix,
template_dir=args.templates, template_dir=args.templates,
imported_members=args.imported_members) imported_members=args.imported_members,
app=app)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -50,8 +50,12 @@ def compile_regex_list(name, exps):
class CoverageBuilder(Builder): class CoverageBuilder(Builder):
"""
Evaluates coverage of code in the documentation.
"""
name = 'coverage' name = 'coverage'
epilog = ('Testing of coverage in the sources finished, look at the '
'results in %(outdir)s/python.txt.')
def init(self): def init(self):
# type: () -> None # type: () -> None

View File

@ -20,7 +20,8 @@ from os import path
import doctest import doctest
from six import itervalues, StringIO, binary_type, text_type, PY2 from six import itervalues, StringIO, binary_type, text_type, PY2
from distutils.version import LooseVersion from packaging.specifiers import SpecifierSet, InvalidSpecifier
from packaging.version import Version
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import Directive, directives from docutils.parsers.rst import Directive, directives
@ -57,28 +58,23 @@ else:
return text return text
def compare_version(ver1, ver2, operand): def is_allowed_version(spec, version):
# type: (unicode, unicode, unicode) -> bool # type: (unicode, unicode) -> bool
"""Compare `ver1` to `ver2`, relying on `operand`. """Check `spec` satisfies `version` or not.
This obeys PEP-440 specifiers:
https://www.python.org/dev/peps/pep-0440/#version-specifiers
Some examples: Some examples:
>>> compare_version('3.3', '3.5', '<=') >>> is_allowed_version('3.3', '<=3.5')
True True
>>> compare_version('3.3', '3.2', '<=') >>> is_allowed_version('3.3', '<=3.2')
False False
>>> compare_version('3.3a0', '3.3', '<=') >>> is_allowed_version('3.3', '>3.2, <4.0')
True True
""" """
if operand not in ('<=', '<', '==', '>=', '>'): return Version(version) in SpecifierSet(spec)
raise ValueError("'%s' is not a valid operand.")
v1 = LooseVersion(ver1)
v2 = LooseVersion(ver2)
return ((operand == '<=' and (v1 <= v2)) or
(operand == '<' and (v1 < v2)) or
(operand == '==' and (v1 == v2)) or
(operand == '>=' and (v1 >= v2)) or
(operand == '>' and (v1 > v2)))
# set up the necessary directives # set up the necessary directives
@ -120,7 +116,11 @@ class TestDirective(Directive):
if test is not None: if test is not None:
# only save if it differs from code # only save if it differs from code
node['test'] = test node['test'] = test
if self.name == 'testoutput': if self.name == 'doctest':
node['language'] = 'pycon'
elif self.name == 'testcode':
node['language'] = 'python'
elif self.name == 'testoutput':
# don't try to highlight output # don't try to highlight output
node['language'] = 'none' node['language'] = 'none'
node['options'] = {} node['options'] = {}
@ -143,16 +143,13 @@ class TestDirective(Directive):
node['options'][flag] = (option[0] == '+') node['options'][flag] = (option[0] == '+')
if self.name == 'doctest' and 'pyversion' in self.options: if self.name == 'doctest' and 'pyversion' in self.options:
try: try:
option = self.options['pyversion'] spec = self.options['pyversion']
# :pyversion: >= 3.6 --> operand='>=', option_version='3.6' if not is_allowed_version(spec, platform.python_version()):
operand, option_version = [item.strip() for item in option.split()]
running_version = platform.python_version()
if not compare_version(running_version, option_version, operand):
flag = doctest.OPTIONFLAGS_BY_NAME['SKIP'] flag = doctest.OPTIONFLAGS_BY_NAME['SKIP']
node['options'][flag] = True # Skip the test node['options'][flag] = True # Skip the test
except ValueError: except InvalidSpecifier:
self.state.document.reporter.warning( self.state.document.reporter.warning(
_("'%s' is not a valid pyversion option") % option, _("'%s' is not a valid pyversion option") % spec,
line=self.lineno) line=self.lineno)
return [node] return [node]
@ -278,6 +275,8 @@ class DocTestBuilder(Builder):
Runs test snippets in the documentation. Runs test snippets in the documentation.
""" """
name = 'doctest' name = 'doctest'
epilog = ('Testing of doctests in the sources finished, look at the '
'results in %(outdir)s/output.txt.')
def init(self): def init(self):
# type: () -> None # type: () -> None

View File

@ -130,8 +130,8 @@ class InheritanceGraph(object):
graphviz dot graph from them. graphviz dot graph from them.
""" """
def __init__(self, class_names, currmodule, show_builtins=False, def __init__(self, class_names, currmodule, show_builtins=False,
private_bases=False, parts=0, aliases=None): private_bases=False, parts=0, aliases=None, top_classes=[]):
# type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]]) -> None # type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]], List[Any]) -> None # NOQA
"""*class_names* is a list of child classes to show bases from. """*class_names* is a list of child classes to show bases from.
If *show_builtins* is True, then Python builtins will be shown If *show_builtins* is True, then Python builtins will be shown
@ -140,7 +140,7 @@ class InheritanceGraph(object):
self.class_names = class_names self.class_names = class_names
classes = self._import_classes(class_names, currmodule) classes = self._import_classes(class_names, currmodule)
self.class_info = self._class_info(classes, show_builtins, self.class_info = self._class_info(classes, show_builtins,
private_bases, parts, aliases) private_bases, parts, aliases, top_classes)
if not self.class_info: if not self.class_info:
raise InheritanceException('No classes found for ' raise InheritanceException('No classes found for '
'inheritance diagram') 'inheritance diagram')
@ -153,13 +153,16 @@ class InheritanceGraph(object):
classes.extend(import_classes(name, currmodule)) classes.extend(import_classes(name, currmodule))
return classes return classes
def _class_info(self, classes, show_builtins, private_bases, parts, aliases): def _class_info(self, classes, show_builtins, private_bases, parts, aliases, top_classes):
# type: (List[Any], bool, bool, int, Optional[Dict[unicode, unicode]]) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA # type: (List[Any], bool, bool, int, Optional[Dict[unicode, unicode]], List[Any]) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA
"""Return name and bases for all classes that are ancestors of """Return name and bases for all classes that are ancestors of
*classes*. *classes*.
*parts* gives the number of dotted name parts that is removed from the *parts* gives the number of dotted name parts that is removed from the
displayed node names. displayed node names.
*top_classes* gives the name(s) of the top most ancestor class to traverse
to. Multiple names can be specified separated by comma.
""" """
all_classes = {} all_classes = {}
py_builtins = vars(builtins).values() py_builtins = vars(builtins).values()
@ -189,6 +192,10 @@ class InheritanceGraph(object):
baselist = [] # type: List[unicode] baselist = [] # type: List[unicode]
all_classes[cls] = (nodename, fullname, baselist, tooltip) all_classes[cls] = (nodename, fullname, baselist, tooltip)
if fullname in top_classes:
return
for base in cls.__bases__: for base in cls.__bases__:
if not show_builtins and base in py_builtins: if not show_builtins and base in py_builtins:
continue continue
@ -322,6 +329,7 @@ class InheritanceDiagram(Directive):
'parts': directives.nonnegative_int, 'parts': directives.nonnegative_int,
'private-bases': directives.flag, 'private-bases': directives.flag,
'caption': directives.unchanged, 'caption': directives.unchanged,
'top-classes': directives.unchanged_required,
} }
def run(self): def run(self):
@ -334,6 +342,11 @@ class InheritanceDiagram(Directive):
# Store the original content for use as a hash # Store the original content for use as a hash
node['parts'] = self.options.get('parts', 0) node['parts'] = self.options.get('parts', 0)
node['content'] = ', '.join(class_names) node['content'] = ', '.join(class_names)
node['top-classes'] = []
for cls in self.options.get('top-classes', '').split(','):
cls = cls.strip()
if cls:
node['top-classes'].append(cls)
# Create a graph starting with the list of classes # Create a graph starting with the list of classes
try: try:
@ -341,7 +354,8 @@ class InheritanceDiagram(Directive):
class_names, env.ref_context.get('py:module'), class_names, env.ref_context.get('py:module'),
parts=node['parts'], parts=node['parts'],
private_bases='private-bases' in self.options, private_bases='private-bases' in self.options,
aliases=env.config.inheritance_alias) aliases=env.config.inheritance_alias,
top_classes=node['top-classes'])
except InheritanceException as err: except InheritanceException as err:
return [node.document.reporter.warning(err.args[0], return [node.document.reporter.warning(err.args[0],
line=self.lineno)] line=self.lineno)]

View File

@ -304,6 +304,7 @@ def missing_reference(app, env, node, contnode):
in_set = setname in_set = setname
to_try.append((inventories.named_inventory[setname], newtarget)) to_try.append((inventories.named_inventory[setname], newtarget))
if domain: if domain:
node['reftarget'] = newtarget
full_qualified_name = env.get_domain(domain).get_full_qualified_name(node) full_qualified_name = env.get_domain(domain).get_full_qualified_name(node)
if full_qualified_name: if full_qualified_name:
to_try.append((inventories.named_inventory[setname], full_qualified_name)) to_try.append((inventories.named_inventory[setname], full_qualified_name))

View File

@ -20,14 +20,14 @@ from sphinx.ext.mathbase import get_node_equation_number
def html_visit_math(self, node): def html_visit_math(self, node):
self.body.append(self.starttag(node, 'span', '', CLASS='math')) self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate'))
self.body.append(self.encode(node['latex']) + '</span>') self.body.append(self.encode(node['latex']) + '</span>')
raise nodes.SkipNode raise nodes.SkipNode
def html_visit_displaymath(self, node): def html_visit_displaymath(self, node):
if node['nowrap']: if node['nowrap']:
self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
self.body.append(self.encode(node['latex'])) self.body.append(self.encode(node['latex']))
self.body.append('</div>') self.body.append('</div>')
raise nodes.SkipNode raise nodes.SkipNode
@ -40,7 +40,7 @@ def html_visit_displaymath(self, node):
self.body.append('<span class="eqno">(%s)' % number) self.body.append('<span class="eqno">(%s)' % number)
self.add_permalink_ref(node, _('Permalink to this equation')) self.add_permalink_ref(node, _('Permalink to this equation'))
self.body.append('</span>') self.body.append('</span>')
self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
else: else:
# but only once! # but only once!
self.body.append('<div class="math">') self.body.append('<div class="math">')

View File

@ -21,7 +21,7 @@ from sphinx.ext.mathbase import get_node_equation_number
def html_visit_math(self, node): def html_visit_math(self, node):
self.body.append(self.starttag(node, 'span', '', CLASS='math')) self.body.append(self.starttag(node, 'span', '', CLASS='math notranslate'))
self.body.append(self.builder.config.mathjax_inline[0] + self.body.append(self.builder.config.mathjax_inline[0] +
self.encode(node['latex']) + self.encode(node['latex']) +
self.builder.config.mathjax_inline[1] + '</span>') self.builder.config.mathjax_inline[1] + '</span>')
@ -29,7 +29,7 @@ def html_visit_math(self, node):
def html_visit_displaymath(self, node): def html_visit_displaymath(self, node):
self.body.append(self.starttag(node, 'div', CLASS='math')) self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
if node['nowrap']: if node['nowrap']:
self.body.append(self.encode(node['latex'])) self.body.append(self.encode(node['latex']))
self.body.append('</div>') self.body.append('</div>')

View File

@ -71,12 +71,12 @@ def doctree_read(app, doctree):
code = analyzer.code.decode(analyzer.encoding) code = analyzer.code.decode(analyzer.encoding)
else: else:
code = analyzer.code code = analyzer.code
if entry is None or entry[0] != code: if entry is False:
return
elif entry is None or entry[0] != code:
analyzer.find_tags() analyzer.find_tags()
entry = code, analyzer.tags, {}, refname entry = code, analyzer.tags, {}, refname
env._viewcode_modules[modname] = entry # type: ignore env._viewcode_modules[modname] = entry # type: ignore
elif entry is False:
return
_, tags, used, _ = entry _, tags, used, _ = entry
if fullname in tags: if fullname in tags:
used[fullname] = docname used[fullname] = docname

View File

@ -19,11 +19,12 @@ from docutils.writers import UnfilteredWriter
from six import text_type from six import text_type
from typing import Any, Union # NOQA from typing import Any, Union # NOQA
from sphinx.transforms import SphinxTransformer
from sphinx.transforms import ( from sphinx.transforms import (
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences, ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
AutoNumbering, AutoIndexUpgrader, FilterSystemMessages, AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
UnreferencedFootnotesDetector UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink
) )
from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform
from sphinx.transforms.i18n import ( from sphinx.transforms.i18n import (
@ -56,6 +57,11 @@ class SphinxBaseReader(standalone.Reader):
This replaces reporter by Sphinx's on generating document. This replaces reporter by Sphinx's on generating document.
""" """
def __init__(self, app, *args, **kwargs):
# type: (Sphinx, Any, Any) -> None
self.env = app.env
standalone.Reader.__init__(self, *args, **kwargs)
def get_transforms(self): def get_transforms(self):
# type: () -> List[Transform] # type: () -> List[Transform]
return standalone.Reader.get_transforms(self) + self.transforms return standalone.Reader.get_transforms(self) + self.transforms
@ -66,9 +72,16 @@ class SphinxBaseReader(standalone.Reader):
for logging. for logging.
""" """
document = standalone.Reader.new_document(self) document = standalone.Reader.new_document(self)
# substitute transformer
document.transformer = SphinxTransformer(document)
document.transformer.set_environment(self.env)
# substitute reporter
reporter = document.reporter reporter = document.reporter
document.reporter = LoggingReporter.from_reporter(reporter) document.reporter = LoggingReporter.from_reporter(reporter)
document.reporter.set_source(self.source) document.reporter.set_source(self.source)
return document return document
@ -80,13 +93,14 @@ class SphinxStandaloneReader(SphinxBaseReader):
Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets, Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets,
HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds, HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds,
RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages, RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages,
RefOnlyBulletListTransform, UnreferencedFootnotesDetector RefOnlyBulletListTransform, UnreferencedFootnotesDetector, SphinxSmartQuotes,
ManpageLink
] # type: List[Transform] ] # type: List[Transform]
def __init__(self, app, *args, **kwargs): def __init__(self, app, *args, **kwargs):
# type: (Sphinx, Any, Any) -> None # type: (Sphinx, Any, Any) -> None
self.transforms = self.transforms + app.registry.get_transforms() self.transforms = self.transforms + app.registry.get_transforms()
SphinxBaseReader.__init__(self, *args, **kwargs) # type: ignore SphinxBaseReader.__init__(self, app, *args, **kwargs)
class SphinxI18nReader(SphinxBaseReader): class SphinxI18nReader(SphinxBaseReader):
@ -103,7 +117,7 @@ class SphinxI18nReader(SphinxBaseReader):
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
AutoNumbering, SortIds, RemoveTranslatableInline, AutoNumbering, SortIds, RemoveTranslatableInline,
FilterSystemMessages, RefOnlyBulletListTransform, FilterSystemMessages, RefOnlyBulletListTransform,
UnreferencedFootnotesDetector] UnreferencedFootnotesDetector, ManpageLink]
def set_lineno_for_reporter(self, lineno): def set_lineno_for_reporter(self, lineno):
# type: (int) -> None # type: (int) -> None

View File

@ -97,101 +97,6 @@ class Make(object):
if not osname or os.name == osname: if not osname or os.name == osname:
print(' %s %s' % (blue(bname.ljust(10)), description)) print(' %s %s' % (blue(bname.ljust(10)), description))
def build_html(self):
# type: () -> int
if self.run_generic_build('html') > 0:
return 1
print()
print('Build finished. The HTML pages are in %s.' % self.builddir_join('html'))
return 0
def build_dirhtml(self):
# type: () -> int
if self.run_generic_build('dirhtml') > 0:
return 1
print()
print('Build finished. The HTML pages are in %s.' %
self.builddir_join('dirhtml'))
return 0
def build_singlehtml(self):
# type: () -> int
if self.run_generic_build('singlehtml') > 0:
return 1
print()
print('Build finished. The HTML page is in %s.' %
self.builddir_join('singlehtml'))
return 0
def build_pickle(self):
# type: () -> int
if self.run_generic_build('pickle') > 0:
return 1
print()
print('Build finished; now you can process the pickle files.')
return 0
def build_json(self):
# type: () -> int
if self.run_generic_build('json') > 0:
return 1
print()
print('Build finished; now you can process the JSON files.')
return 0
def build_htmlhelp(self):
# type: () -> int
if self.run_generic_build('htmlhelp') > 0:
return 1
print()
print('Build finished; now you can run HTML Help Workshop with the '
'.hhp project file in %s.' % self.builddir_join('htmlhelp'))
return 0
def build_qthelp(self):
# type: () -> int
if self.run_generic_build('qthelp') > 0:
return 1
print()
print('Build finished; now you can run "qcollectiongenerator" with the '
'.qhcp project file in %s, like this:' % self.builddir_join('qthelp'))
print('$ qcollectiongenerator %s.qhcp' % self.builddir_join('qthelp', proj_name))
print('To view the help file:')
print('$ assistant -collectionFile %s.qhc' %
self.builddir_join('qthelp', proj_name))
return 0
def build_devhelp(self):
# type: () -> int
if self.run_generic_build('devhelp') > 0:
return 1
print()
print("Build finished.")
print("To view the help file:")
print("$ mkdir -p $HOME/.local/share/devhelp/" + proj_name)
print("$ ln -s %s $HOME/.local/share/devhelp/%s" %
(self.builddir_join('devhelp'), proj_name))
print("$ devhelp")
return 0
def build_epub(self):
# type: () -> int
if self.run_generic_build('epub') > 0:
return 1
print()
print('Build finished. The ePub file is in %s.' % self.builddir_join('epub'))
return 0
def build_latex(self):
# type: () -> int
if self.run_generic_build('latex') > 0:
return 1
print("Build finished; the LaTeX files are in %s." % self.builddir_join('latex'))
if os.name == 'posix':
print("Run `make' in that directory to run these through (pdf)latex")
print("(use `make latexpdf' here to do that automatically).")
return 0
def build_latexpdf(self): def build_latexpdf(self):
# type: () -> int # type: () -> int
if self.run_generic_build('latex') > 0: if self.run_generic_build('latex') > 0:
@ -206,25 +111,6 @@ class Make(object):
with cd(self.builddir_join('latex')): with cd(self.builddir_join('latex')):
return subprocess.call([self.makecmd, 'all-pdf-ja']) return subprocess.call([self.makecmd, 'all-pdf-ja'])
def build_text(self):
# type: () -> int
if self.run_generic_build('text') > 0:
return 1
print()
print('Build finished. The text files are in %s.' % self.builddir_join('text'))
return 0
def build_texinfo(self):
# type: () -> int
if self.run_generic_build('texinfo') > 0:
return 1
print("Build finished; the Texinfo files are in %s." %
self.builddir_join('texinfo'))
if os.name == 'posix':
print("Run `make' in that directory to run these through makeinfo")
print("(use `make info' here to do that automatically).")
return 0
def build_info(self): def build_info(self):
# type: () -> int # type: () -> int
if self.run_generic_build('texinfo') > 0: if self.run_generic_build('texinfo') > 0:
@ -237,60 +123,6 @@ class Make(object):
dtdir = self.builddir_join('gettext', '.doctrees') dtdir = self.builddir_join('gettext', '.doctrees')
if self.run_generic_build('gettext', doctreedir=dtdir) > 0: if self.run_generic_build('gettext', doctreedir=dtdir) > 0:
return 1 return 1
print()
print('Build finished. The message catalogs are in %s.' %
self.builddir_join('gettext'))
return 0
def build_changes(self):
# type: () -> int
if self.run_generic_build('changes') > 0:
return 1
print()
print('Build finished. The overview file is in %s.' %
self.builddir_join('changes'))
return 0
def build_linkcheck(self):
# type: () -> int
res = self.run_generic_build('linkcheck')
print()
print('Link check complete; look for any errors in the above output '
'or in %s.' % self.builddir_join('linkcheck', 'output.txt'))
return res
def build_doctest(self):
# type: () -> int
res = self.run_generic_build('doctest')
print("Testing of doctests in the sources finished, look at the "
"results in %s." % self.builddir_join('doctest', 'output.txt'))
return res
def build_coverage(self):
# type: () -> int
if self.run_generic_build('coverage') > 0:
print("Has the coverage extension been enabled?")
return 1
print()
print("Testing of coverage in the sources finished, look at the "
"results in %s." % self.builddir_join('coverage'))
return 0
def build_xml(self):
# type: () -> int
if self.run_generic_build('xml') > 0:
return 1
print()
print('Build finished. The XML files are in %s.' % self.builddir_join('xml'))
return 0
def build_pseudoxml(self):
# type: () -> int
if self.run_generic_build('pseudoxml') > 0:
return 1
print()
print('Build finished. The pseudo-XML files are in %s.' %
self.builddir_join('pseudoxml'))
return 0 return 0
def run_generic_build(self, builder, doctreedir=None): def run_generic_build(self, builder, doctreedir=None):

View File

@ -15,8 +15,6 @@ from docutils.parsers.rst import states
from docutils.statemachine import StringList from docutils.statemachine import StringList
from docutils.transforms.universal import SmartQuotes from docutils.transforms.universal import SmartQuotes
from sphinx.transforms import SphinxSmartQuotes
if False: if False:
# For type annotation # For type annotation
from typing import Any, Dict, List, Type # NOQA from typing import Any, Dict, List, Type # NOQA
@ -63,10 +61,11 @@ class RSTParser(docutils.parsers.rst.Parser):
def get_transforms(self): def get_transforms(self):
# type: () -> List[Type[Transform]] # type: () -> List[Type[Transform]]
"""Sphinx's reST parser replaces a transform class for smart-quotes by own's""" """Sphinx's reST parser replaces a transform class for smart-quotes by own's
refs: sphinx.io.SphinxStandaloneReader"""
transforms = docutils.parsers.rst.Parser.get_transforms(self) transforms = docutils.parsers.rst.Parser.get_transforms(self)
transforms.remove(SmartQuotes) transforms.remove(SmartQuotes)
transforms.append(SphinxSmartQuotes)
return transforms return transforms
def parse(self, inputstring, document): def parse(self, inputstring, document):

View File

@ -38,6 +38,7 @@ if False:
from sphinx.builders import Builder # NOQA from sphinx.builders import Builder # NOQA
from sphinx.domains import Domain, Index # NOQA from sphinx.domains import Domain, Index # NOQA
from sphinx.environment import BuildEnvironment # NOQA from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc import Documenter # NOQA
from sphinx.util.typing import RoleFunction # NOQA from sphinx.util.typing import RoleFunction # NOQA
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -51,7 +52,9 @@ EXTENSION_BLACKLIST = {
class SphinxComponentRegistry(object): class SphinxComponentRegistry(object):
def __init__(self): def __init__(self):
self.autodoc_attrgettrs = {} # type: Dict[Type, Callable[[Any, unicode, Any], Any]]
self.builders = {} # type: Dict[unicode, Type[Builder]] self.builders = {} # type: Dict[unicode, Type[Builder]]
self.documenters = {} # type: Dict[unicode, Type[Documenter]]
self.domains = {} # type: Dict[unicode, Type[Domain]] self.domains = {} # type: Dict[unicode, Type[Domain]]
self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]] self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]]
self.domain_indices = {} # type: Dict[unicode, List[Type[Index]]] self.domain_indices = {} # type: Dict[unicode, List[Type[Index]]]
@ -284,6 +287,14 @@ class SphinxComponentRegistry(object):
# type: () -> List[Type[Transform]] # type: () -> List[Type[Transform]]
return self.post_transforms return self.post_transforms
def add_documenter(self, objtype, documenter):
# type: (unicode, Type[Documenter]) -> None
self.documenters[objtype] = documenter
def add_autodoc_attrgetter(self, typ, attrgetter):
# type: (Type, Callable[[Any, unicode, Any], Any]) -> None
self.autodoc_attrgettrs[typ] = attrgetter
def load_extension(self, app, extname): def load_extension(self, app, extname):
# type: (Sphinx, unicode) -> None # type: (Sphinx, unicode) -> None
"""Load a Sphinx extension.""" """Load a Sphinx extension."""

View File

@ -207,4 +207,4 @@ class SearchFrench(SearchLanguage):
self.stemmer = snowballstemmer.stemmer('french') self.stemmer = snowballstemmer.stemmer('french')
def stem(self, word): def stem(self, word):
return self.stemmer.stemWord(word) return self.stemmer.stemWord(word.lower())

View File

@ -5,14 +5,16 @@
SPHINXOPTS ?= SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build SPHINXBUILD ?= sphinx-build
PAPER ?= PAPER ?=
SOURCEDIR = {{ rsrcdir }}
BUILDDIR = {{ rbuilddir }} BUILDDIR = {{ rbuilddir }}
# Internal variables. # Internal variables.
PAPEROPT_a4 = -D latex_elements.papersize=a4 PAPEROPT_a4 = -D latex_elements.papersize=a4
PAPEROPT_letter = -D latex_elements.papersize=letter PAPEROPT_letter = -D latex_elements.papersize=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }} # $(O) is meant as a shortcut for $(SPHINXOPTS)
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) $(SOURCEDIR)
# the i18n builder cannot share the environment and doctrees with the others # the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }} I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) $(SOURCEDIR)
.PHONY: help .PHONY: help
help: help:
@ -49,86 +51,6 @@ help:
clean: clean:
rm -rf $(BUILDDIR)/* rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/{{ project_fn }}.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/{{ project_fn }}.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/{{ project_fn }}"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/{{ project_fn }}"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf .PHONY: latexpdf
latexpdf: latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@ -157,26 +79,6 @@ xelatexpdf:
$(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf $(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf
@echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex." @echo "xelatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info .PHONY: info
info: info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@ -187,49 +89,9 @@ info:
.PHONY: gettext .PHONY: gettext
gettext: gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes # Catch-all target: route all unknown targets to Sphinx
changes: .PHONY: Makefile
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes %: Makefile
@echo $(SPHINXBUILD) -b "$@" $(ALLSPHINXOPTS) "$(BUILDDIR)/$@"
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
.PHONY: dummy
dummy:
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
@echo
@echo "Build finished. Dummy builder generates no files."

View File

@ -1,19 +1,12 @@
{% if PY3 -%}
#!/usr/bin/env python3
{% endif -%}
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# {{ project }} documentation build configuration file, created by # Configuration file for the Sphinx documentation builder.
# sphinx-quickstart on {{ now }}.
# #
# This file is execfile()d with the current directory set to its # This file does only contain a selection of the most common options. For a
# containing dir. # full list see the documentation:
# # http://www.sphinx-doc.org/en/stable/config
# Note that not all possible configuration values are present in this
# autogenerated file. # -- Path setup --------------------------------------------------------------
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
@ -33,7 +26,19 @@ sys.path.insert(0, u'{{ module_path }}')
{% endif -%} {% endif -%}
{% endif %} {% endif %}
# -- General configuration ------------------------------------------------ # -- Project information -----------------------------------------------------
project = u'{{ project_str }}'
copyright = u'{{ copyright_str }}'
author = u'{{ author_str }}'
# The short X.Y version
version = u'{{ version_str }}'
# The full version, including alpha/beta/rc tags
release = u'{{ release_str }}'
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # If your documentation needs a minimal Sphinx version, state it here.
# #
@ -60,20 +65,6 @@ source_suffix = '{{ suffix }}'
# The master toctree document. # The master toctree document.
master_doc = '{{ master_str }}' master_doc = '{{ master_str }}'
# General information about the project.
project = u'{{ project_str }}'
copyright = u'{{ copyright_str }}'
author = u'{{ author_str }}'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'{{ version_str }}'
# The full version, including alpha/beta/rc tags.
release = u'{{ release_str }}'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
# #
@ -90,7 +81,7 @@ exclude_patterns = [{{ exclude_patterns }}]
pygments_style = 'sphinx' pygments_style = 'sphinx'
# -- Options for HTML output ---------------------------------------------- # -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
@ -119,13 +110,13 @@ html_static_path = ['{{ dot }}static']
# html_sidebars = {} # html_sidebars = {}
# -- Options for HTMLHelp output ------------------------------------------ # -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = '{{ project_fn }}doc' htmlhelp_basename = '{{ project_fn }}doc'
# -- Options for LaTeX output --------------------------------------------- # -- Options for LaTeX output ------------------------------------------------
latex_elements = { latex_elements = {
# The paper size ('letterpaper' or 'a4paper'). # The paper size ('letterpaper' or 'a4paper').
@ -154,7 +145,7 @@ latex_documents = [
] ]
# -- Options for manual page output --------------------------------------- # -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
@ -164,7 +155,7 @@ man_pages = [
] ]
# -- Options for Texinfo output ------------------------------------------- # -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples # Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author, # (source start file, target name, title, author,
@ -177,7 +168,7 @@ texinfo_documents = [
{%- if epub %} {%- if epub %}
# -- Options for Epub output ---------------------------------------------- # -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info. # Bibliographic Dublin Core info.
epub_title = project epub_title = project
@ -200,18 +191,18 @@ epub_exclude_files = ['search.html']
{%- if extensions %} {%- if extensions %}
# -- Extension configuration ---------------------------------------------- # -- Extension configuration -------------------------------------------------
{%- endif %} {%- endif %}
{%- if 'sphinx.ext.intersphinx' in extensions %} {%- if 'sphinx.ext.intersphinx' in extensions %}
# -- Options for intersphinx extension ------------------------------------ # -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library. # Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None} intersphinx_mapping = {'https://docs.python.org/': None}
{%- endif %} {%- endif %}
{%- if 'sphinx.ext.todo' in extensions %} {%- if 'sphinx.ext.todo' in extensions %}
# -- Options for todo extension ------------------------------------------- # -- Options for todo extension ----------------------------------------------
# If true, `todo` and `todoList` produce output, else they produce nothing. # If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True todo_include_todos = True

View File

@ -8,8 +8,9 @@ if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build set SPHINXBUILD=sphinx-build
) )
set BUILDDIR={{ rbuilddir }} set BUILDDIR={{ rbuilddir }}
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% {{ rsrcdir }} set SOURCEDIR={{ rsrcdir }}
set I18NSPHINXOPTS=%SPHINXOPTS% {{ rsrcdir }} set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SOURCEDIR%
set I18NSPHINXOPTS=%SPHINXOPTS% %SOURCEDIR%
if NOT "%PAPER%" == "" ( if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_elements.papersize=%PAPER% %ALLSPHINXOPTS% set ALLSPHINXOPTS=-D latex_elements.papersize=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_elements.papersize=%PAPER% %I18NSPHINXOPTS% set I18NSPHINXOPTS=-D latex_elements.papersize=%PAPER% %I18NSPHINXOPTS%
@ -50,7 +51,6 @@ if "%1" == "clean" (
goto end goto end
) )
REM Check if sphinx-build is available and fallback to Python version if any REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL %SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python if errorlevel 9009 goto sphinx_python
@ -74,92 +74,6 @@ if errorlevel 9009 (
:sphinx_ok :sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\{{ project_fn }}.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\{{ project_fn }}.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" ( if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex cd %BUILDDIR%/latex
@ -180,96 +94,14 @@ if "%1" == "latexpdfja" (
goto end goto end
) )
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" ( if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1 if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end goto end
) )
if "%1" == "changes" ( %SPHINXBUILD% -b %1 %ALLSPHINXOPTS% %BUILDDIR%/%1
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
if "%1" == "dummy" (
%SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
if errorlevel 1 exit /b 1
echo.
echo.Build finished. Dummy builder generates no files.
goto end
)
:end :end
popd popd

View File

@ -504,7 +504,7 @@
\fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}}
\fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}}
\fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}}
\fancyhead[LE,RO]{{\py@HeaderFamily \@title, \py@release}} \fancyhead[LE,RO]{{\py@HeaderFamily \@title\sphinxheadercomma\py@release}}
\renewcommand{\headrulewidth}{0.4pt} \renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt} \renewcommand{\footrulewidth}{0.4pt}
% define chaptermark with \@chappos when \@chappos is available for Japanese % define chaptermark with \@chappos when \@chappos is available for Japanese
@ -1401,18 +1401,26 @@
% \date{}. This allows the date to reflect the document's date and % \date{}. This allows the date to reflect the document's date and
% release to specify the release that is documented. % release to specify the release that is documented.
% %
\newcommand{\py@release}{} \newcommand{\py@release}{\releasename\space\version}
\newcommand{\version}{} \newcommand{\version}{}% part of \py@release, used by title page and headers
\newcommand{\shortversion}{} % \releaseinfo is used on titlepage (sphinxmanual.cls, sphinxhowto.cls)
\newcommand{\releaseinfo}{} \newcommand{\releaseinfo}{}
\newcommand{\releasename}{Release} \newcommand{\setreleaseinfo}[1]{\renewcommand{\releaseinfo}{#1}}
\newcommand{\release}[1]{% % this is inserted via template and #1=release config variable
\renewcommand{\py@release}{\releasename\space\version}% \newcommand{\release}[1]{\renewcommand{\version}{#1}}
\renewcommand{\version}{#1}} % this is defined by template to 'releasename' latex_elements key
\newcommand{\setshortversion}[1]{% \newcommand{\releasename}{}
\renewcommand{\shortversion}{#1}} % Fix issue in case release and releasename deliberately left blank
\newcommand{\setreleaseinfo}[1]{% \newcommand{\sphinxheadercomma}{, }% used in fancyhdr header definition
\renewcommand{\releaseinfo}{#1}} \newcommand{\sphinxifemptyorblank}[1]{%
% test after one expansion of macro #1 if contents is empty or spaces
\if&\expandafter\@firstofone\detokenize\expandafter{#1}&%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}%
\AtBeginDocument {%
\sphinxifemptyorblank{\releasename}
{\sphinxifemptyorblank{\version}{\let\sphinxheadercomma\empty}{}}
{}%
}%
% Allow specification of the author's address separately from the % Allow specification of the author's address separately from the
% author's name. This can be used to format them differently, which % author's name. This can be used to format them differently, which

View File

@ -0,0 +1,9 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '{{ url_root }}',
VERSION: '{{ release|e }}',
LANGUAGE: '{{ language }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
HAS_SOURCE: {{ has_source|lower }},
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};

View File

@ -87,16 +87,7 @@
{%- endmacro %} {%- endmacro %}
{%- macro script() %} {%- macro script() %}
<script type="text/javascript"> <script type="text/javascript" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '{{ url_root }}',
VERSION: '{{ release|e }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
HAS_SOURCE: {{ has_source|lower }},
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};
</script>
{%- for scriptfile in script_files %} {%- for scriptfile in script_files %}
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script> <script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
{%- endfor %} {%- endfor %}

View File

@ -10,12 +10,14 @@
{%- if pagename != "search" and builder != "singlehtml" %} {%- if pagename != "search" and builder != "singlehtml" %}
<div id="searchbox" style="display: none" role="search"> <div id="searchbox" style="display: none" role="search">
<h3>{{ _('Quick search') }}</h3> <h3>{{ _('Quick search') }}</h3>
<div class="searchformwrapper">
<form class="search" action="{{ pathto('search') }}" method="get"> <form class="search" action="{{ pathto('search') }}" method="get">
<div><input type="text" name="q" /></div> <input type="text" name="q" />
<div><input type="submit" value="{{ _('Go') }}" /></div> <input type="submit" value="{{ _('Go') }}" />
<input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" /> <input type="hidden" name="area" value="default" />
</form> </form>
</div> </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script> <script type="text/javascript">$('#searchbox').show(0);</script>
{%- endif %} {%- endif %}

View File

@ -82,9 +82,21 @@ div.sphinxsidebar input {
} }
div.sphinxsidebar #searchbox input[type="text"] { div.sphinxsidebar #searchbox input[type="text"] {
width: 170px; float: left;
width: 80%;
padding: 0.25em;
box-sizing: border-box;
} }
div.sphinxsidebar #searchbox input[type="submit"] {
float: left;
width: 20%;
border-left: none;
padding: 0.25em;
box-sizing: border-box;
}
img { img {
border: 0; border: 0;
max-width: 100%; max-width: 100%;

View File

@ -125,12 +125,9 @@ div.sphinxsidebar input {
font-size: 1em; font-size: 1em;
} }
div.sphinxsidebar input[type=text]{ div.sphinxsidebar .searchformwrapper {
margin-left: 20px;
}
div.sphinxsidebar input[type=submit]{
margin-left: 20px; margin-left: 20px;
margin-right: 20px;
} }
/* -- body styles ----------------------------------------------------------- */ /* -- body styles ----------------------------------------------------------- */

View File

@ -148,12 +148,9 @@ div.sphinxsidebar input {
font-size: 1em; font-size: 1em;
} }
div.sphinxsidebar input[type=text]{ div.sphinxsidebar .searchformwrapper {
margin-left: 20px;
}
div.sphinxsidebar input[type=submit]{
margin-left: 20px; margin-left: 20px;
margin-right: 20px;
} }
/* -- sidebars -------------------------------------------------------------- */ /* -- sidebars -------------------------------------------------------------- */

View File

@ -9,11 +9,14 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import re
from docutils import nodes from docutils import nodes
from docutils.transforms import Transform, Transformer from docutils.transforms import Transform, Transformer
from docutils.transforms.parts import ContentsFilter from docutils.transforms.parts import ContentsFilter
from docutils.utils import new_document
from docutils.transforms.universal import SmartQuotes from docutils.transforms.universal import SmartQuotes
from docutils.utils import new_document, normalize_language_tag
from docutils.utils.smartquotes import smartchars
from sphinx import addnodes from sphinx import addnodes
from sphinx.locale import _ from sphinx.locale import _
@ -333,12 +336,54 @@ class SphinxContentsFilter(ContentsFilter):
raise nodes.SkipNode raise nodes.SkipNode
class SphinxSmartQuotes(SmartQuotes): class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
""" """
Customized SmartQuotes to avoid transform for some extra node types. Customized SmartQuotes to avoid transform for some extra node types.
refs: sphinx.parsers.RSTParser refs: sphinx.parsers.RSTParser
""" """
def apply(self):
# type: () -> None
if not self.is_available():
return
SmartQuotes.apply(self)
def is_available(self):
# type: () -> bool
builders = self.config.smartquotes_excludes.get('builders', [])
languages = self.config.smartquotes_excludes.get('languages', [])
if self.document.settings.smart_quotes is False:
# disabled by 3rd party extension (workaround)
return False
elif self.config.smartquotes is False:
# disabled by confval smartquotes
return False
elif self.app.builder.name in builders:
# disabled by confval smartquotes_excludes['builders']
return False
elif self.config.language in languages:
# disabled by confval smartquotes_excludes['languages']
return False
# confirm selected language supports smart_quotes or not
language = self.env.settings['language_code']
for tag in normalize_language_tag(language):
if tag in smartchars.quotes:
return True
else:
return False
@property
def smartquotes_action(self):
# type: () -> unicode
"""A smartquotes_action setting for SmartQuotes.
Users can change this setting through :confval:`smartquotes_action`.
"""
return self.config.smartquotes_action
def get_tokens(self, txtnodes): def get_tokens(self, txtnodes):
# A generator that yields ``(texttype, nodetext)`` tuples for a list # A generator that yields ``(texttype, nodetext)`` tuples for a list
# of "Text" nodes (interface to ``smartquotes.educate_tokens()``). # of "Text" nodes (interface to ``smartquotes.educate_tokens()``).
@ -348,3 +393,21 @@ class SphinxSmartQuotes(SmartQuotes):
for txtnode in txtnodes: for txtnode in txtnodes:
notsmartquotable = not is_smartquotable(txtnode) notsmartquotable = not is_smartquotable(txtnode)
yield (texttype[notsmartquotable], txtnode.astext()) yield (texttype[notsmartquotable], txtnode.astext())
class ManpageLink(SphinxTransform):
"""Find manpage section numbers and names"""
default_priority = 999
def apply(self):
for node in self.document.traverse(addnodes.manpage):
manpage = ' '.join([str(x) for x in node.children
if isinstance(x, nodes.Text)])
pattern = r'^(?P<path>(?P<page>.+)[\(\.](?P<section>[1-9]\w*)?\)?)$' # noqa
info = {'path': manpage,
'page': manpage,
'section': ''}
r = re.match(pattern, manpage)
if r:
info = r.groupdict()
node.attributes.update(info)

View File

@ -50,7 +50,7 @@ def publish_msgstr(app, source, source_path, source_line, config, settings):
:rtype: docutils.nodes.document :rtype: docutils.nodes.document
""" """
from sphinx.io import SphinxI18nReader from sphinx.io import SphinxI18nReader
reader = SphinxI18nReader() reader = SphinxI18nReader(app)
reader.set_lineno_for_reporter(source_line) reader.set_lineno_for_reporter(source_line)
parser = app.registry.create_source_parser(app, '') parser = app.registry.create_source_parser(app, '')
doc = reader.read( doc = reader.read(

View File

@ -18,7 +18,7 @@ from contextlib import contextmanager
import docutils import docutils
from docutils.languages import get_language from docutils.languages import get_language
from docutils.statemachine import ViewList from docutils.statemachine import StateMachine, ViewList
from docutils.parsers.rst import directives, roles, convert_directive_function from docutils.parsers.rst import directives, roles, convert_directive_function
from docutils.utils import Reporter from docutils.utils import Reporter
@ -31,8 +31,9 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(
if False: if False:
# For type annotation # For type annotation
from typing import Any, Callable, Iterator, List, Tuple # NOQA from typing import Any, Callable, Generator, Iterator, List, Tuple # NOQA
from docutils import nodes # NOQA from docutils import nodes # NOQA
from docutils.statemachine import State # NOQA
from sphinx.environment import BuildEnvironment # NOQA from sphinx.environment import BuildEnvironment # NOQA
from sphinx.io import SphinxFileInput # NOQA from sphinx.io import SphinxFileInput # NOQA
@ -216,3 +217,22 @@ def directive_helper(obj, has_content=None, argument_spec=None, **option_spec):
raise ExtensionError(__('when adding directive classes, no ' raise ExtensionError(__('when adding directive classes, no '
'additional arguments may be given')) 'additional arguments may be given'))
return obj return obj
@contextmanager
def switch_source_input(state, content):
# type: (State, ViewList) -> Generator
"""Switch current source input of state temporarily."""
try:
# remember the original ``get_source_and_line()`` method
get_source_and_line = state.memo.reporter.get_source_and_line
# replace it by new one
state_machine = StateMachine([], None)
state_machine.input_lines = content
state.memo.reporter.get_source_and_line = state_machine.get_source_and_line
yield
finally:
# restore the method
state.memo.reporter.get_source_and_line = get_source_and_line

View File

@ -404,10 +404,18 @@ class Signature(object):
if annotation == Ellipsis: if annotation == Ellipsis:
return '...' return '...'
if not isinstance(annotation, type): if not isinstance(annotation, type):
return repr(annotation) qualified_name = repr(annotation)
if qualified_name.startswith('typing.'): # for typing.Union
return qualified_name.split('.', 1)[1]
else:
return qualified_name
qualified_name = (annotation.__module__ + '.' + annotation.__qualname__ # type: ignore if not annotation:
if annotation else repr(annotation)) qualified_name = repr(annotation)
elif annotation.__module__ == 'typing':
qualified_name = annotation.__qualname__ # type: ignore
else:
qualified_name = (annotation.__module__ + '.' + annotation.__qualname__) # type: ignore # NOQA
if annotation.__module__ == 'builtins': if annotation.__module__ == 'builtins':
return annotation.__qualname__ # type: ignore return annotation.__qualname__ # type: ignore

View File

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

View File

@ -79,6 +79,7 @@ class HTMLTranslator(BaseTranslator):
self.highlightopts = builder.config.highlight_options self.highlightopts = builder.config.highlight_options
self.highlightlinenothreshold = sys.maxsize self.highlightlinenothreshold = sys.maxsize
self.docnames = [builder.current_docname] # for singlehtml builder self.docnames = [builder.current_docname] # for singlehtml builder
self.manpages_url = builder.config.manpages_url
self.protect_literal_text = 0 self.protect_literal_text = 0
self.permalink_text = builder.config.html_add_permalinks self.permalink_text = builder.config.html_add_permalinks
# support backwards-compatible setting to a bool # support backwards-compatible setting to a bool
@ -443,7 +444,7 @@ class HTMLTranslator(BaseTranslator):
location=(self.builder.current_docname, node.line), **highlight_args location=(self.builder.current_docname, node.line), **highlight_args
) )
starttag = self.starttag(node, 'div', suffix='', starttag = self.starttag(node, 'div', suffix='',
CLASS='highlight-%s' % lang) CLASS='highlight-%s notranslate' % lang)
self.body.append(starttag + highlighted + '</div>\n') self.body.append(starttag + highlighted + '</div>\n')
raise nodes.SkipNode raise nodes.SkipNode
@ -493,10 +494,10 @@ class HTMLTranslator(BaseTranslator):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
if 'kbd' in node['classes']: if 'kbd' in node['classes']:
self.body.append(self.starttag(node, 'kbd', '', self.body.append(self.starttag(node, 'kbd', '',
CLASS='docutils literal')) CLASS='docutils literal notranslate'))
else: else:
self.body.append(self.starttag(node, 'code', '', self.body.append(self.starttag(node, 'code', '',
CLASS='docutils literal')) CLASS='docutils literal notranslate'))
self.protect_literal_text += 1 self.protect_literal_text += 1
def depart_literal(self, node): def depart_literal(self, node):
@ -816,9 +817,14 @@ class HTMLTranslator(BaseTranslator):
def visit_manpage(self, node): def visit_manpage(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
self.visit_literal_emphasis(node) self.visit_literal_emphasis(node)
if self.manpages_url:
node['refuri'] = self.manpages_url.format(**node.attributes)
self.visit_reference(node)
def depart_manpage(self, node): def depart_manpage(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
if self.manpages_url:
self.depart_reference(node)
self.depart_literal_emphasis(node) self.depart_literal_emphasis(node)
# overwritten to add even/odd classes # overwritten to add even/odd classes

View File

@ -49,6 +49,7 @@ class HTML5Translator(BaseTranslator):
self.highlightopts = builder.config.highlight_options self.highlightopts = builder.config.highlight_options
self.highlightlinenothreshold = sys.maxsize self.highlightlinenothreshold = sys.maxsize
self.docnames = [builder.current_docname] # for singlehtml builder self.docnames = [builder.current_docname] # for singlehtml builder
self.manpages_url = builder.config.manpages_url
self.protect_literal_text = 0 self.protect_literal_text = 0
self.permalink_text = builder.config.html_add_permalinks self.permalink_text = builder.config.html_add_permalinks
# support backwards-compatible setting to a bool # support backwards-compatible setting to a bool
@ -389,7 +390,7 @@ class HTML5Translator(BaseTranslator):
location=(self.builder.current_docname, node.line), **highlight_args location=(self.builder.current_docname, node.line), **highlight_args
) )
starttag = self.starttag(node, 'div', suffix='', starttag = self.starttag(node, 'div', suffix='',
CLASS='highlight-%s' % lang) CLASS='highlight-%s notranslate' % lang)
self.body.append(starttag + highlighted + '</div>\n') self.body.append(starttag + highlighted + '</div>\n')
raise nodes.SkipNode raise nodes.SkipNode
@ -439,10 +440,10 @@ class HTML5Translator(BaseTranslator):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
if 'kbd' in node['classes']: if 'kbd' in node['classes']:
self.body.append(self.starttag(node, 'kbd', '', self.body.append(self.starttag(node, 'kbd', '',
CLASS='docutils literal')) CLASS='docutils literal notranslate'))
else: else:
self.body.append(self.starttag(node, 'code', '', self.body.append(self.starttag(node, 'code', '',
CLASS='docutils literal')) CLASS='docutils literal notranslate'))
self.protect_literal_text += 1 self.protect_literal_text += 1
def depart_literal(self, node): def depart_literal(self, node):
@ -758,9 +759,14 @@ class HTML5Translator(BaseTranslator):
def visit_manpage(self, node): def visit_manpage(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
self.visit_literal_emphasis(node) self.visit_literal_emphasis(node)
if self.manpages_url:
node['refuri'] = self.manpages_url.format(**dict(node))
self.visit_reference(node)
def depart_manpage(self, node): def depart_manpage(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
if self.manpages_url:
self.depart_reference(node)
self.depart_literal_emphasis(node) self.depart_literal_emphasis(node)
# overwritten to add even/odd classes # overwritten to add even/odd classes

View File

@ -549,7 +549,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
'author': document.settings.author, # treat as a raw LaTeX code 'author': document.settings.author, # treat as a raw LaTeX code
'indexname': _('Index'), 'indexname': _('Index'),
}) })
if not self.elements['releasename']: if not self.elements['releasename'] and self.elements['release']:
self.elements.update({ self.elements.update({
'releasename': _('Release'), 'releasename': _('Release'),
}) })
@ -1376,6 +1376,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.table = Table(node) self.table = Table(node)
if self.next_table_colspec: if self.next_table_colspec:
self.table.colspec = '{%s}\n' % self.next_table_colspec self.table.colspec = '{%s}\n' % self.next_table_colspec
if 'colwidths-given' in node.get('classes', []):
logger.info('both tabularcolumns and :widths: option are given. '
':widths: is ignored.', location=node)
self.next_table_colspec = None self.next_table_colspec = None
def depart_table(self, node): def depart_table(self, node):
@ -1853,28 +1856,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
(node['align'] == 'right' and 'r' or 'l', length or '0pt')) (node['align'] == 'right' and 'r' or 'l', length or '0pt'))
self.context.append(ids + '\\end{wrapfigure}\n') self.context.append(ids + '\\end{wrapfigure}\n')
elif self.in_minipage: elif self.in_minipage:
if ('align' not in node.attributes or
node.attributes['align'] == 'center'):
self.body.append('\n\\begin{center}') self.body.append('\n\\begin{center}')
self.context.append('\\end{center}\n') self.context.append('\\end{center}\n')
else: else:
self.body.append('\n\\begin{flush%s}' % node.attributes['align']) self.body.append('\n\\begin{figure}[%s]\n\\centering\n' %
self.context.append('\\end{flush%s}\n' % node.attributes['align']) self.elements['figure_align'])
else:
if ('align' not in node.attributes or
node.attributes['align'] == 'center'):
# centering does not add vertical space like center.
align = '\n\\centering'
align_end = ''
else:
# TODO non vertical space for other alignments.
align = '\\begin{flush%s}' % node.attributes['align']
align_end = '\\end{flush%s}' % node.attributes['align']
self.body.append('\n\\begin{figure}[%s]%s\n' % (
self.elements['figure_align'], align))
if any(isinstance(child, nodes.caption) for child in node): if any(isinstance(child, nodes.caption) for child in node):
self.body.append('\\capstart\n') self.body.append('\\capstart\n')
self.context.append(ids + align_end + '\\end{figure}\n') self.context.append(ids + '\\end{figure}\n')
def depart_figure(self, node): def depart_figure(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None

View File

@ -183,6 +183,8 @@ class TextTranslator(nodes.NodeVisitor):
else: else:
self.nl = '\n' self.nl = '\n'
self.sectionchars = builder.config.text_sectionchars self.sectionchars = builder.config.text_sectionchars
self.add_secnumbers = builder.config.text_add_secnumbers
self.secnumber_suffix = builder.config.text_secnumber_suffix
self.states = [[]] # type: List[List[Tuple[int, Union[unicode, List[unicode]]]]] self.states = [[]] # type: List[List[Tuple[int, Union[unicode, List[unicode]]]]]
self.stateindent = [0] self.stateindent = [0]
self.list_counter = [] # type: List[int] self.list_counter = [] # type: List[int]
@ -307,6 +309,17 @@ class TextTranslator(nodes.NodeVisitor):
raise nodes.SkipNode raise nodes.SkipNode
self.new_state(0) self.new_state(0)
def get_section_number_string(self, node):
# type: (nodes.Node) -> unicode
if isinstance(node.parent, nodes.section):
anchorname = '#' + node.parent['ids'][0]
numbers = self.builder.secnumbers.get(anchorname)
if numbers is None:
numbers = self.builder.secnumbers.get('')
if numbers is not None:
return '.'.join(map(str, numbers)) + self.secnumber_suffix
return ''
def depart_title(self, node): def depart_title(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
if isinstance(node.parent, nodes.section): if isinstance(node.parent, nodes.section):
@ -315,6 +328,8 @@ class TextTranslator(nodes.NodeVisitor):
char = '^' char = '^'
text = None # type: unicode text = None # type: unicode
text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) # type: ignore text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) # type: ignore
if self.add_secnumbers:
text = self.get_section_number_string(node) + text
self.stateindent.pop() self.stateindent.pop()
title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode] title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode]
if len(self.states) == 2 and len(self.states[-1]) == 0: if len(self.states) == 2 and len(self.states[-1]) == 0:
@ -987,7 +1002,10 @@ class TextTranslator(nodes.NodeVisitor):
def visit_reference(self, node): def visit_reference(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
pass if self.add_secnumbers:
numbers = node.get("secnumber")
if numbers is not None:
self.add_text('.'.join(map(str, numbers)) + self.secnumber_suffix)
def depart_reference(self, node): def depart_reference(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None

View File

@ -35,14 +35,6 @@ def pytest_report_header(config):
sys.version.split()[0]) sys.version.split()[0])
def _filter_warnings():
def ignore(**kwargs): warnings.filterwarnings('ignore', **kwargs)
ignore(category=DeprecationWarning, module='site') # virtualenv
ignore(category=PendingDeprecationWarning, module=r'_pytest\..*')
ignore(category=ImportWarning, module='pkgutil')
def _initialize_test_directory(session): def _initialize_test_directory(session):
testroot = os.path.join(str(session.config.rootdir), 'tests') testroot = os.path.join(str(session.config.rootdir), 'tests')
tempdir = os.path.abspath(os.getenv('SPHINX_TEST_TEMPDIR', tempdir = os.path.abspath(os.getenv('SPHINX_TEST_TEMPDIR',
@ -58,5 +50,4 @@ def _initialize_test_directory(session):
def pytest_sessionstart(session): def pytest_sessionstart(session):
_filter_warnings()
_initialize_test_directory(session) _initialize_test_directory(session)

View File

@ -21,6 +21,7 @@ from docutils.statemachine import ViewList
from sphinx.ext.autodoc import AutoDirective, add_documenter, \ from sphinx.ext.autodoc import AutoDirective, add_documenter, \
ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL
from sphinx.util import logging
app = None app = None
@ -47,7 +48,7 @@ directive = options = None
@pytest.fixture @pytest.fixture
def setup_test(): def setup_test():
global options, directive global options, directive
global processed_docstrings, processed_signatures, _warnings global processed_docstrings, processed_signatures
options = Struct( options = Struct(
inherited_members = False, inherited_members = False,
@ -70,24 +71,17 @@ def setup_test():
env = app.builder.env, env = app.builder.env,
genopt = options, genopt = options,
result = ViewList(), result = ViewList(),
warn = warnfunc,
filename_set = set(), filename_set = set(),
) )
processed_docstrings = [] processed_docstrings = []
processed_signatures = [] processed_signatures = []
_warnings = []
_warnings = []
processed_docstrings = [] processed_docstrings = []
processed_signatures = [] processed_signatures = []
def warnfunc(msg):
_warnings.append(msg)
def process_docstring(app, what, name, obj, options, lines): def process_docstring(app, what, name, obj, options, lines):
processed_docstrings.append((what, name)) processed_docstrings.append((what, name))
if name == 'bar': if name == 'bar':
@ -111,20 +105,21 @@ def skip_member(app, what, name, obj, skip, options):
@pytest.mark.usefixtures('setup_test') @pytest.mark.usefixtures('setup_test')
def test_generate(): def test_generate():
logging.setup(app, app._status, app._warning)
def assert_warns(warn_str, objtype, name, **kw): def assert_warns(warn_str, objtype, name, **kw):
inst = AutoDirective._registry[objtype](directive, name) inst = app.registry.documenters[objtype](directive, name)
inst.generate(**kw) inst.generate(**kw)
assert len(directive.result) == 0, directive.result assert len(directive.result) == 0, directive.result
assert len(_warnings) == 1, _warnings assert warn_str in app._warning.getvalue()
assert warn_str in _warnings[0], _warnings app._warning.truncate(0)
del _warnings[:]
def assert_works(objtype, name, **kw): def assert_works(objtype, name, **kw):
inst = AutoDirective._registry[objtype](directive, name) inst = app.registry.documenters[objtype](directive, name)
inst.generate(**kw) inst.generate(**kw)
assert directive.result assert directive.result
# print '\n'.join(directive.result) # print '\n'.join(directive.result)
assert len(_warnings) == 0, _warnings assert app._warning.getvalue() == ''
del directive.result[:] del directive.result[:]
def assert_processes(items, objtype, name, **kw): def assert_processes(items, objtype, name, **kw):
@ -134,18 +129,18 @@ def test_generate():
assert set(processed_docstrings) | set(processed_signatures) == set(items) assert set(processed_docstrings) | set(processed_signatures) == set(items)
def assert_result_contains(item, objtype, name, **kw): def assert_result_contains(item, objtype, name, **kw):
inst = AutoDirective._registry[objtype](directive, name) inst = app.registry.documenters[objtype](directive, name)
inst.generate(**kw) inst.generate(**kw)
# print '\n'.join(directive.result) # print '\n'.join(directive.result)
assert len(_warnings) == 0, _warnings assert app._warning.getvalue() == ''
assert item in directive.result assert item in directive.result
del directive.result[:] del directive.result[:]
def assert_order(items, objtype, name, member_order, **kw): def assert_order(items, objtype, name, member_order, **kw):
inst = AutoDirective._registry[objtype](directive, name) inst = app.registry.documenters[objtype](directive, name)
inst.options.member_order = member_order inst.options.member_order = member_order
inst.generate(**kw) inst.generate(**kw)
assert len(_warnings) == 0, _warnings assert app._warning.getvalue() == ''
items = list(reversed(items)) items = list(reversed(items))
lineiter = iter(directive.result) lineiter = iter(directive.result)
# for line in directive.result: # for line in directive.result:

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python
import os
import mod_resource
import mod_something
if __name__ == "__main__":
print("Hello, world! -> something returns: {}".format(mod_something.something()))
res_path = \
os.path.join(os.path.dirname(mod_resource.__file__), 'resource.txt')
with open(res_path) as f:
text = f.read()
print("From mod_resource:resource.txt -> {}".format(text))

View File

@ -0,0 +1 @@
MESSAGE="There's no __init__.py in this folder, hence we should be left out"

View File

@ -0,0 +1 @@
This is a text resource to be included in this otherwise empty module. No python contents here.

View File

@ -0,0 +1 @@
"Subpackage Something"

View File

@ -1,5 +1,8 @@
.. toctree:: .. toctree::
:numbered:
doc1
doc2
maxwidth maxwidth
lineblock lineblock
nonascii_title nonascii_title

View File

@ -0,0 +1,2 @@
Section A
=========

View File

@ -0,0 +1,9 @@
Section B
=========
Sub Ba
------
Sub Bb
------

View File

@ -0,0 +1,5 @@
Basic Diagram
==============
.. inheritance-diagram::
dummy.test

View File

@ -0,0 +1,6 @@
import sys, os
sys.path.insert(0, os.path.abspath('.'))
extensions = ['sphinx.ext.inheritance_diagram']
source_suffix = '.rst'

View File

@ -0,0 +1,4 @@
.. toctree::
:glob:
*

View File

@ -0,0 +1,6 @@
Diagram using module with 2 top classes
=======================================
.. inheritance-diagram::
dummy.test
:top-classes: dummy.test.B, dummy.test.C

View File

@ -0,0 +1,7 @@
Diagram using 1 top class
=========================
.. inheritance-diagram::
dummy.test
:top-classes: dummy.test.B

View File

@ -0,0 +1,9 @@
Diagram using 2 top classes
===========================
.. inheritance-diagram::
dummy.test.F
dummy.test.D
dummy.test.E
:top-classes: dummy.test.B, dummy.test.C

View File

@ -0,0 +1,7 @@
Diagram using the parts option
==============================
.. inheritance-diagram::
dummy.test
:parts: 1

View File

@ -0,0 +1,30 @@
"""
Test with a class diagram like this::
A
/ \
B C
/ \ / \
E D F
"""
class A(object):
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E(B):
pass
class F(C):
pass

View File

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

View File

@ -0,0 +1,3 @@
* :manpage:`man(1)`
* :manpage:`ls.1`
* :manpage:`sphinx`

Some files were not shown because too many files have changed in this diff Show More