mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'master' into body-width
This commit is contained in:
commit
1d0a087f75
@ -6,19 +6,12 @@ environment:
|
||||
|
||||
matrix:
|
||||
- PYTHON: 27
|
||||
DOCUTILS: 0.13.1
|
||||
TEST_IGNORE: --ignore py35
|
||||
- PYTHON: 27
|
||||
DOCUTILS: 0.14
|
||||
TEST_IGNORE: --ignore py35
|
||||
- PYTHON: 36
|
||||
DOCUTILS: 0.14
|
||||
- PYTHON: 36-x64
|
||||
DOCUTILS: 0.14
|
||||
|
||||
install:
|
||||
- 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]
|
||||
|
||||
# No automatic build, just run python tests
|
||||
|
@ -6,7 +6,6 @@ cache: pip
|
||||
env:
|
||||
global:
|
||||
- PYTHONFAULTHANDLER=x
|
||||
- PYTHONWARNINGS=all
|
||||
- SKIP_LATEX_BUILD=1
|
||||
|
||||
matrix:
|
||||
|
2
AUTHORS
2
AUTHORS
@ -18,6 +18,7 @@ Other co-maintainers:
|
||||
Other contributors, listed alphabetically, are:
|
||||
|
||||
* Alastair Houghton -- Apple Help builder
|
||||
* Alexander Todorov -- inheritance_diagram tests and improvements
|
||||
* Andi Albrecht -- agogo theme
|
||||
* Jakob Lykke Andersen -- Rewritten C++ domain
|
||||
* Henrique Bastos -- SVG support for graphviz extension
|
||||
@ -68,6 +69,7 @@ Other contributors, listed alphabetically, are:
|
||||
* Barry Warsaw -- setup command improvements
|
||||
* Sebastian Wiesner -- image handling, distutils support
|
||||
* Michael Wilson -- Intersphinx HTTP basic auth support
|
||||
* Matthew Woodcraft -- text output improvements
|
||||
* Joel Wurtz -- cellspanning support in LaTeX
|
||||
* Hong Xu -- svg support in imgmath extension and various bug fixes
|
||||
* Stephen Finucane -- setup command improvements and documentation
|
||||
|
71
CHANGES
71
CHANGES
@ -1,6 +1,11 @@
|
||||
Release 1.7 (in development)
|
||||
============================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* Add ``packaging`` package
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
@ -13,6 +18,15 @@ Incompatible changes
|
||||
* #3929: apidoc: Move sphinx.apidoc to sphinx.ext.apidoc
|
||||
* #4226: apidoc: Generate new style makefile (make-mode)
|
||||
* #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
|
||||
options ``body_min_width`` and ``body_max_width``.
|
||||
|
||||
@ -23,6 +37,12 @@ Deprecated
|
||||
values will be accepted at 2.0.
|
||||
* ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use
|
||||
``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
|
||||
--------------
|
||||
@ -57,7 +77,21 @@ Features added
|
||||
code-blocks
|
||||
* #947: autodoc now supports ignore-module-all to ignore a module's ``__all__``
|
||||
* #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
|
||||
----------------
|
||||
@ -88,6 +122,8 @@ Features removed
|
||||
* LaTeX environment ``notice``, use ``sphinxadmonition`` instead
|
||||
* LaTeX ``\sphinxstylethead``, use ``\sphinxstyletheadfamily``
|
||||
* C++, support of function concepts. Thanks to mickk-on-cpp.
|
||||
* Not used and previously not documented LaTeX macros ``\shortversion``
|
||||
and ``\setshortversion``
|
||||
|
||||
|
||||
Bugs fixed
|
||||
@ -103,13 +139,18 @@ Bugs fixed
|
||||
one of figures and tables
|
||||
* #4330: PDF 'howto' documents have an incoherent default LaTeX tocdepth counter
|
||||
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
|
||||
--------
|
||||
|
||||
* 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
|
||||
@ -124,14 +165,35 @@ Deprecated
|
||||
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
|
||||
* ``VerbatimHighlightColor`` is a new
|
||||
:ref:`LaTeX 'sphinxsetup' <latexsphinxsetup>` key (refs: #4285)
|
||||
* 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
|
||||
----------
|
||||
|
||||
* #4334: sphinx-apidoc: Don't generate references to non-existing files in TOC
|
||||
* #4206: latex: reST label between paragraphs loses paragraph break
|
||||
* #4231: html: Apply fixFirefoxAnchorBug only under Firefox
|
||||
* #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
|
||||
``\chapter`` commands
|
||||
* #4214: Two todolist directives break sphinx-1.6.5
|
||||
|
||||
Testing
|
||||
--------
|
||||
* Fix links to external option docs with intersphinx (refs: #3769)
|
||||
* #4091: Private members not documented without :undoc-members:
|
||||
|
||||
Release 1.6.5 (released Oct 23, 2017)
|
||||
=====================================
|
||||
|
4
EXAMPLES
4
EXAMPLES
@ -93,7 +93,7 @@ Documentation using the classic theme
|
||||
* simuPOP: http://simupop.sourceforge.net/manual_release/build/userGuide.html (customized)
|
||||
* Sprox: http://sprox.org/ (customized)
|
||||
* SymPy: http://docs.sympy.org/
|
||||
* TurboGears: https://turbogears.readthedocs.org/ (customized)
|
||||
* TurboGears: https://turbogears.readthedocs.io/ (customized)
|
||||
* tvtk: http://docs.enthought.com/mayavi/tvtk/
|
||||
* Varnish: https://www.varnish-cache.org/docs/ (customized, alabaster for index)
|
||||
* Waf: https://waf.io/apidocs/
|
||||
@ -259,7 +259,7 @@ Documentation using sphinx_bootstrap_theme
|
||||
* Bootstrap Theme: https://ryan-roemer.github.io/sphinx-bootstrap-theme/
|
||||
* C/C++ Software Development with Eclipse: http://eclipsebook.in/
|
||||
* Dataverse: http://guides.dataverse.org/
|
||||
* e-cidadania: http://e-cidadania.readthedocs.org/
|
||||
* e-cidadania: https://e-cidadania.readthedocs.io/
|
||||
* Hangfire: http://docs.hangfire.io/
|
||||
* Hedge: https://documen.tician.de/hedge/
|
||||
* ObsPy: https://docs.obspy.org/
|
||||
|
6
doc/_templates/index.html
vendored
6
doc/_templates/index.html
vendored
@ -74,9 +74,9 @@
|
||||
|
||||
<p>{%trans%}
|
||||
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
|
||||
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%}
|
||||
</p>
|
||||
|
||||
@ -106,7 +106,7 @@
|
||||
<h2>{%trans%}Hosting{%endtrans%}</h2>
|
||||
|
||||
<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
|
||||
powerful built-in search that exceeds the possibilities of Sphinx' JavaScript-based
|
||||
offline search.{%endtrans%}</p>
|
||||
|
10
doc/_templates/indexsidebar.html
vendored
10
doc/_templates/indexsidebar.html
vendored
@ -20,12 +20,14 @@ Index</a>, or install it with:{%endtrans%}</p>
|
||||
<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>
|
||||
<div class="subscribeformwrapper">
|
||||
<form action="http://groups.google.com/group/sphinx-users/boxsubscribe"
|
||||
style="padding-left: 0.5em">
|
||||
<input type="text" name="email" value="your@email" style="font-size: 90%; width: 120px"
|
||||
onfocus="$(this).val('');"/>
|
||||
<input type="submit" name="sub" value="Subscribe" style="font-size: 90%; width: 70px"/>
|
||||
class="subscribeform">
|
||||
<input type="text" name="email" value="your@email"
|
||||
onfocus="$(this).val('');" />
|
||||
<input type="submit" name="sub" value="Subscribe" />
|
||||
</form>
|
||||
</div>
|
||||
<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
|
||||
<a href="https://github.com/sphinx-doc/sphinx/issues">tracker</a>.{%endtrans%}</p>
|
||||
|
30
doc/_themes/sphinx13/static/sphinx13.css
vendored
30
doc/_themes/sphinx13/static/sphinx13.css
vendored
@ -140,11 +140,37 @@ div.sphinxsidebar .logo img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.subscribeformwrapper {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
margin-bottom: 1.2em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #aaa;
|
||||
font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'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 {
|
||||
@ -281,7 +307,7 @@ tt {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2px;
|
||||
color: #333;
|
||||
padding: 1px;
|
||||
padding: 1px 0.2em;
|
||||
}
|
||||
|
||||
tt.descname, tt.descclassname, tt.xref {
|
||||
|
@ -293,6 +293,24 @@ General configuration
|
||||
|
||||
.. 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
|
||||
|
||||
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
|
||||
``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
|
||||
|
||||
If true, Sphinx verifies server certifications. Default is ``True``.
|
||||
@ -785,15 +860,11 @@ that use Sphinx's HTMLWriter class.
|
||||
|
||||
.. confval:: html_use_smartypants
|
||||
|
||||
If true, `SmartyPants <https://daringfireball.net/projects/smartypants/>`_
|
||||
will be used to convert quotes and dashes to typographically correct
|
||||
If true, quotes and dashes are converted to typographically correct
|
||||
entities. Default: ``True``.
|
||||
|
||||
.. deprecated:: 1.6
|
||||
To disable or customize smart quotes, use the Docutils configuration file
|
||||
(``docutils.conf``) instead to set there its `smart_quotes option`_.
|
||||
|
||||
.. _`smart_quotes option`: http://docutils.sourceforge.net/docs/user/config.html#smart-quotes
|
||||
To disable smart quotes, use rather :confval:`smartquotes`.
|
||||
|
||||
.. confval:: html_add_permalinks
|
||||
|
||||
@ -1968,6 +2039,20 @@ These options influence text output.
|
||||
|
||||
.. 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:
|
||||
|
||||
|
@ -138,7 +138,7 @@ own extensions.
|
||||
.. _cmakedomain: https://bitbucket.org/klorenz/sphinxcontrib-cmakedomain
|
||||
.. _GNU Make: http://www.gnu.org/software/make/
|
||||
.. _makedomain: https://bitbucket.org/klorenz/sphinxcontrib-makedomain
|
||||
.. _inlinesyntaxhighlight: http://sphinxcontrib-inlinesyntaxhighlight.readthedocs.org
|
||||
.. _inlinesyntaxhighlight: https://sphinxcontrib-inlinesyntaxhighlight.readthedocs.io/
|
||||
.. _CMake: https://cmake.org
|
||||
.. _domaintools: https://bitbucket.org/klorenz/sphinxcontrib-domaintools
|
||||
.. _restbuilder: https://pypi.python.org/pypi/sphinxcontrib-restbuilder
|
||||
|
@ -80,12 +80,24 @@ a comma-separated list of group names.
|
||||
.. doctest::
|
||||
:pyversion: > 3.3
|
||||
|
||||
The supported operands are ``<``, ``<=``, ``==``, ``>=``, ``>``, and
|
||||
comparison is performed by `distutils.version.LooseVersion
|
||||
<https://www.python.org/dev/peps/pep-0386/#distutils>`__.
|
||||
The following operands are supported:
|
||||
|
||||
* ``~=``: 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
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
Supported PEP-440 operands and notations
|
||||
|
||||
Note that like with standard doctests, you have to use ``<BLANKLINE>`` to
|
||||
signal a blank line in the expected output. The ``<BLANKLINE>`` is removed
|
||||
when building presentation output (HTML, LaTeX etc.).
|
||||
|
@ -42,6 +42,54 @@ It adds this directive:
|
||||
.. versionchanged:: 1.5
|
||||
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:
|
||||
|
||||
|
@ -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.
|
||||
|
||||
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.
|
||||
|
||||
If you write an extension that you think others will find useful or you think
|
||||
|
@ -15,6 +15,7 @@ Builder API
|
||||
|
||||
.. autoattribute:: name
|
||||
.. autoattribute:: format
|
||||
.. autoattribute:: epilog
|
||||
.. autoattribute:: supported_image_types
|
||||
|
||||
These methods are predefined and will be called from the application:
|
||||
|
@ -117,12 +117,30 @@ Both APIs parse the content into a given node. They are used like this::
|
||||
|
||||
node = docutils.nodes.paragraph()
|
||||
# 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)
|
||||
# or
|
||||
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
|
||||
return ``node.children`` from the Directive.
|
||||
|
||||
|
@ -58,7 +58,7 @@ Read the Docs
|
||||
Sphinx. They will host sphinx documentation, along with supporting a number
|
||||
of other features including version support, PDF generation, and more. The
|
||||
`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.
|
||||
|
||||
Epydoc
|
||||
|
@ -3,7 +3,7 @@ Introduction
|
||||
|
||||
This is the documentation for the Sphinx documentation builder. Sphinx is a
|
||||
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
|
||||
possibly subdirectories of docs in there as well), Sphinx can generate a
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
.. _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.
|
||||
|
||||
* 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
|
||||
to Sphinx: `odt2sphinx <https://pypi.python.org/pypi/odt2sphinx/>`_.
|
||||
|
@ -355,7 +355,8 @@ in a different style:
|
||||
.. rst:role:: manpage
|
||||
|
||||
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
|
||||
|
||||
|
@ -323,6 +323,11 @@ following directive exists:
|
||||
Sphinx's merged cells interact well with ``p{width}``, ``\X{a}{b}``, ``Y{f}``
|
||||
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
|
||||
----
|
||||
|
||||
|
@ -44,6 +44,10 @@ incremental = True
|
||||
check_untyped_defs = True
|
||||
warn_unused_ignores = True
|
||||
|
||||
[tool:pytest]
|
||||
filterwarnings =
|
||||
ignore::DeprecationWarning:docutils.io
|
||||
|
||||
[coverage:run]
|
||||
branch = True
|
||||
source = sphinx
|
||||
|
1
setup.py
1
setup.py
@ -26,6 +26,7 @@ requires = [
|
||||
'imagesize',
|
||||
'requests>=2.0.0',
|
||||
'setuptools',
|
||||
'packaging',
|
||||
'sphinxcontrib-websupport',
|
||||
]
|
||||
|
||||
|
@ -157,10 +157,6 @@ class Sphinx(object):
|
||||
# status code for command-line application
|
||||
self.statuscode = 0
|
||||
|
||||
if not path.isdir(outdir):
|
||||
logger.info('making output directory...')
|
||||
ensuredir(outdir)
|
||||
|
||||
# read config
|
||||
self.tags = Tags(tags)
|
||||
self.config = Config(confdir, CONFIG_FILENAME,
|
||||
@ -197,6 +193,10 @@ class Sphinx(object):
|
||||
# preload builder module (before init config values)
|
||||
self.preload_builder(buildername)
|
||||
|
||||
if not path.isdir(outdir):
|
||||
logger.info('making output directory...')
|
||||
ensuredir(outdir)
|
||||
|
||||
# the config file itself can be an extension
|
||||
if self.config.setup:
|
||||
self._setting_up_extension = ['conf.py']
|
||||
@ -338,6 +338,13 @@ class Sphinx(object):
|
||||
(status, self._warncount)))
|
||||
else:
|
||||
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:
|
||||
# delete the saved env to force a fresh build next time
|
||||
envfile = path.join(self.doctreedir, ENV_PICKLE_FILENAME)
|
||||
@ -642,15 +649,14 @@ class Sphinx(object):
|
||||
def add_autodocumenter(self, cls):
|
||||
# type: (Any) -> None
|
||||
logger.debug('[app] adding autodocumenter: %r', cls)
|
||||
from sphinx.ext import autodoc
|
||||
autodoc.add_documenter(cls)
|
||||
self.add_directive('auto' + cls.objtype, autodoc.AutoDirective)
|
||||
from sphinx.ext.autodoc.directive import AutodocDirective
|
||||
self.registry.add_documenter(cls.objtype, cls)
|
||||
self.add_directive('auto' + cls.objtype, AutodocDirective)
|
||||
|
||||
def add_autodoc_attrgetter(self, type, getter):
|
||||
# type: (Any, Callable) -> None
|
||||
logger.debug('[app] adding autodoc attrgetter: %r', (type, getter))
|
||||
from sphinx.ext import autodoc
|
||||
autodoc.AutoDirective._special_attrgetters[type] = getter
|
||||
def add_autodoc_attrgetter(self, typ, getter):
|
||||
# type: (Type, Callable[[Any, unicode, Any], Any]) -> None
|
||||
logger.debug('[app] adding autodoc attrgetter: %r', (typ, getter))
|
||||
self.registry.add_autodoc_attrgetter(typ, getter)
|
||||
|
||||
def add_search_language(self, cls):
|
||||
# type: (Any) -> None
|
||||
|
@ -54,6 +54,11 @@ class Builder(object):
|
||||
name = '' # type: unicode
|
||||
#: The builder's output format, or '' if no document output is produced.
|
||||
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
|
||||
# ``app.set_translator()``.
|
||||
default_translator_class = None # type: nodes.NodeVisitor
|
||||
|
@ -75,6 +75,10 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
|
||||
on the ``hiutil`` command line tool.
|
||||
"""
|
||||
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
|
||||
copysource = False
|
||||
|
@ -38,6 +38,7 @@ class ChangesBuilder(Builder):
|
||||
Write a summary with all versionadded/changed directives.
|
||||
"""
|
||||
name = 'changes'
|
||||
epilog = 'The overview file is in %(outdir)s.'
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
|
@ -43,6 +43,10 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
|
||||
Builder that also outputs GNOME Devhelp file.
|
||||
"""
|
||||
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
|
||||
copysource = False
|
||||
|
@ -21,6 +21,8 @@ if False:
|
||||
|
||||
class DummyBuilder(Builder):
|
||||
name = 'dummy'
|
||||
epilog = 'The dummy builder generates no files.'
|
||||
|
||||
allow_parallel = True
|
||||
|
||||
def init(self):
|
||||
|
@ -63,6 +63,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
|
||||
an epub file.
|
||||
"""
|
||||
name = 'epub'
|
||||
epilog = 'The ePub file is in %(outdir)s.'
|
||||
|
||||
supported_remote_images = False
|
||||
template_dir = path.join(package_dir, 'templates', 'epub3')
|
||||
|
@ -214,6 +214,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
Builds gettext-style message catalogs (.pot files).
|
||||
"""
|
||||
name = 'gettext'
|
||||
epilog = 'The message catalogs are in %(outdir)s.'
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
|
@ -153,6 +153,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
"""
|
||||
name = 'html'
|
||||
format = 'html'
|
||||
epilog = 'The HTML pages are in %(outdir)s.'
|
||||
|
||||
copysource = True
|
||||
allow_parallel = True
|
||||
out_suffix = '.html'
|
||||
@ -1066,6 +1068,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
HTML page.
|
||||
"""
|
||||
name = 'singlehtml'
|
||||
epilog = 'The HTML page is in %(outdir)s.'
|
||||
|
||||
copysource = False
|
||||
|
||||
def get_outdated_docs(self): # type: ignore
|
||||
@ -1328,12 +1332,14 @@ class PickleHTMLBuilder(SerializingHTMLBuilder):
|
||||
"""
|
||||
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_dumps_unicode = False
|
||||
additional_dump_args = (pickle.HIGHEST_PROTOCOL,)
|
||||
indexer_format = pickle
|
||||
indexer_dumps_unicode = False
|
||||
name = 'pickle'
|
||||
out_suffix = '.fpickle'
|
||||
globalcontext_filename = 'globalcontext.pickle'
|
||||
searchindex_filename = 'searchindex.pickle'
|
||||
@ -1347,11 +1353,13 @@ class JSONHTMLBuilder(SerializingHTMLBuilder):
|
||||
"""
|
||||
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_dumps_unicode = True
|
||||
indexer_format = jsonimpl
|
||||
indexer_dumps_unicode = True
|
||||
name = 'json'
|
||||
out_suffix = '.fjson'
|
||||
globalcontext_filename = 'globalcontext.json'
|
||||
searchindex_filename = 'searchindex.json'
|
||||
|
@ -174,6 +174,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
|
||||
index files. Adapted from the original Doc/tools/prechm.py.
|
||||
"""
|
||||
name = 'htmlhelp'
|
||||
epilog = ('You can now run HTML Help Workshop with the .htp file in '
|
||||
'%(outdir)s.')
|
||||
|
||||
# don't copy the reST source
|
||||
copysource = False
|
||||
|
@ -49,6 +49,12 @@ class LaTeXBuilder(Builder):
|
||||
"""
|
||||
name = '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_remote_images = False
|
||||
default_translator_class = LaTeXTranslator
|
||||
|
@ -90,6 +90,8 @@ class CheckExternalLinksBuilder(Builder):
|
||||
Checks for broken external links.
|
||||
"""
|
||||
name = 'linkcheck'
|
||||
epilog = ('Look for any errors in the above output or in '
|
||||
'%(outdir)s/output.txt')
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
|
@ -40,6 +40,8 @@ class ManualPageBuilder(Builder):
|
||||
"""
|
||||
name = 'man'
|
||||
format = 'man'
|
||||
epilog = 'The manual pages are in %(outdir)s.'
|
||||
|
||||
default_translator_class = ManualPageTranslator
|
||||
supported_image_types = [] # type: List[unicode]
|
||||
|
||||
|
@ -108,6 +108,11 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
|
||||
Builder that also outputs Qt help project, contents and index files.
|
||||
"""
|
||||
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
|
||||
copysource = False
|
||||
|
@ -9,6 +9,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
from os import path
|
||||
|
||||
from docutils import nodes
|
||||
@ -97,6 +98,12 @@ class TexinfoBuilder(Builder):
|
||||
"""
|
||||
name = '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',
|
||||
'image/gif']
|
||||
default_translator_class = TexinfoTranslator
|
||||
|
@ -21,7 +21,7 @@ from sphinx.writers.text import TextWriter, TextTranslator
|
||||
|
||||
if False:
|
||||
# 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 sphinx.application import Sphinx # NOQA
|
||||
|
||||
@ -31,6 +31,8 @@ logger = logging.getLogger(__name__)
|
||||
class TextBuilder(Builder):
|
||||
name = 'text'
|
||||
format = 'text'
|
||||
epilog = 'The text files are in %(outdir)s.'
|
||||
|
||||
out_suffix = '.txt'
|
||||
allow_parallel = True
|
||||
default_translator_class = TextTranslator
|
||||
@ -39,7 +41,8 @@ class TextBuilder(Builder):
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
pass
|
||||
# section numbers for headings in the currently visited document
|
||||
self.secnumbers = {} # type: Dict[unicode, Tuple[int, ...]]
|
||||
|
||||
def get_outdated_docs(self):
|
||||
# type: () -> Iterator[unicode]
|
||||
@ -72,6 +75,7 @@ class TextBuilder(Builder):
|
||||
def write_doc(self, docname, doctree):
|
||||
# type: (unicode, nodes.Node) -> None
|
||||
self.current_docname = docname
|
||||
self.secnumbers = self.env.toc_secnumbers.get(docname, {})
|
||||
destination = StringOutput(encoding='utf-8')
|
||||
self.writer.write(doctree, destination)
|
||||
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_newlines', 'unix', 'env')
|
||||
app.add_config_value('text_add_secnumbers', True, 'env')
|
||||
app.add_config_value('text_secnumber_suffix', '. ', 'env')
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
@ -35,6 +35,8 @@ class XMLBuilder(Builder):
|
||||
"""
|
||||
name = 'xml'
|
||||
format = 'xml'
|
||||
epilog = 'The XML files are in %(outdir)s.'
|
||||
|
||||
out_suffix = '.xml'
|
||||
allow_parallel = True
|
||||
|
||||
@ -108,6 +110,8 @@ class PseudoXMLBuilder(XMLBuilder):
|
||||
"""
|
||||
name = 'pseudoxml'
|
||||
format = 'pseudoxml'
|
||||
epilog = 'The pseudo-XML files are in %(outdir)s.'
|
||||
|
||||
out_suffix = '.pseudoxml'
|
||||
|
||||
_writer_class = PseudoXMLWriter
|
||||
|
@ -10,6 +10,7 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
import traceback
|
||||
from os import path, getenv
|
||||
|
||||
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"
|
||||
if PY3:
|
||||
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) " \
|
||||
"called sys.exit()"
|
||||
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]),
|
||||
needs_sphinx = (None, None, string_classes),
|
||||
needs_extensions = ({}, None),
|
||||
manpages_url = (None, 'env'),
|
||||
nitpicky = (False, None),
|
||||
nitpick_ignore = ([], None),
|
||||
numfig = (False, 'env'),
|
||||
@ -135,6 +138,11 @@ class Config(object):
|
||||
|
||||
tls_verify = (True, 'env'),
|
||||
tls_cacerts = (None, 'env'),
|
||||
smartquotes = (True, 'env'),
|
||||
smartquotes_action = ('qDe', 'env'),
|
||||
smartquotes_excludes = ({'languages': ['ja'],
|
||||
'builders': ['man', 'text']},
|
||||
'env'),
|
||||
) # type: Dict[unicode, Tuple]
|
||||
|
||||
def __init__(self, dirname, filename, overrides, tags):
|
||||
@ -155,6 +163,8 @@ class Config(object):
|
||||
raise ConfigError(CONFIG_SYNTAX_ERROR % err)
|
||||
except SystemExit:
|
||||
raise ConfigError(CONFIG_EXIT_ERROR)
|
||||
except Exception:
|
||||
raise ConfigError(CONFIG_ERROR % traceback.format_exc())
|
||||
|
||||
self._raw_config = config
|
||||
# these two must be preinitialized because extensions can add their
|
||||
|
@ -959,12 +959,18 @@ class StandardDomain(Domain):
|
||||
|
||||
def get_full_qualified_name(self, node):
|
||||
# type: (nodes.Node) -> unicode
|
||||
progname = node.get('std:program')
|
||||
target = node.get('reftarget')
|
||||
if progname is None or target is None:
|
||||
return None
|
||||
if node.get('reftype') == 'option':
|
||||
progname = node.get('std:program')
|
||||
command = ws_re.split(node.get('reftarget'))
|
||||
if progname:
|
||||
command.insert(0, progname)
|
||||
option = command.pop()
|
||||
if command:
|
||||
return '.'.join(['-'.join(command), option])
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return '.'.join([progname, target])
|
||||
return None
|
||||
|
||||
|
||||
def setup(app):
|
||||
|
@ -23,8 +23,7 @@ from collections import defaultdict
|
||||
from six import BytesIO, itervalues, class_types, next
|
||||
from six.moves import cPickle as pickle
|
||||
|
||||
from docutils.utils import Reporter, get_source_line, normalize_language_tag
|
||||
from docutils.utils.smartquotes import smartchars
|
||||
from docutils.utils import Reporter, get_source_line
|
||||
from docutils.frontend import OptionParser
|
||||
|
||||
from sphinx import addnodes, versioning
|
||||
@ -47,7 +46,7 @@ from sphinx.environment.adapters.toctree import TocTree
|
||||
|
||||
if False:
|
||||
# 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 sphinx.application import Sphinx # NOQA
|
||||
from sphinx.builders import Builder # NOQA
|
||||
@ -66,6 +65,7 @@ default_settings = {
|
||||
'sectsubtitle_xform': False,
|
||||
'halt_level': 5,
|
||||
'file_insertion_enabled': True,
|
||||
'smartquotes_locales': [],
|
||||
}
|
||||
|
||||
# This is increased every time an environment attribute is added
|
||||
@ -642,17 +642,10 @@ class BuildEnvironment(object):
|
||||
self.config.trim_footnote_reference_space
|
||||
self.settings['gettext_compact'] = self.config.gettext_compact
|
||||
|
||||
language = self.config.language or 'en'
|
||||
self.settings['language_code'] = language
|
||||
if 'smart_quotes' not in self.settings:
|
||||
self.settings['smart_quotes'] = True
|
||||
self.settings['language_code'] = self.config.language or 'en'
|
||||
|
||||
# confirm selected language supports smart_quotes or not
|
||||
for tag in normalize_language_tag(language):
|
||||
if tag in smartchars.quotes:
|
||||
break
|
||||
else:
|
||||
self.settings['smart_quotes'] = False
|
||||
# Allow to disable by 3rd party extension (workaround)
|
||||
self.settings.setdefault('smart_quotes', True)
|
||||
|
||||
def read_doc(self, docname, app=None):
|
||||
# type: (unicode, Sphinx) -> None
|
||||
|
@ -117,7 +117,11 @@ def create_package_file(root, master_package, subroot, py_files, opts, subs, is_
|
||||
text += '\n'
|
||||
|
||||
# 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 subs:
|
||||
text += format_heading(2, 'Subpackages')
|
||||
|
@ -14,17 +14,15 @@
|
||||
import re
|
||||
import sys
|
||||
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
|
||||
|
||||
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.inspector import format_annotation, formatargspec # to keep compatibility # NOQA
|
||||
from sphinx.util import rpartition, force_decode
|
||||
@ -32,21 +30,23 @@ from sphinx.locale import _
|
||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||
from sphinx.application import ExtensionError
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.nodes import nested_parse_with_titles
|
||||
from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \
|
||||
safe_getattr, object_description, is_builtin_class_method, \
|
||||
isenumclass, isenumattribute, getdoc
|
||||
isenumattribute, getdoc
|
||||
from sphinx.util.docstrings import prepare_docstring
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from types import ModuleType # 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 sphinx.application import Sphinx # NOQA
|
||||
from sphinx.ext.autodoc.directive import DocumenterBridge # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# This type isn't exposed directly in any modules, but can be found
|
||||
# here in most Python versions
|
||||
MethodDescriptorType = type(type.__subclasses__)
|
||||
@ -63,42 +63,11 @@ py_ext_sig_re = re.compile(
|
||||
''', 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):
|
||||
# type: (Any) -> Any
|
||||
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()
|
||||
INSTANCEATTR = object()
|
||||
|
||||
@ -146,6 +115,9 @@ class AutodocReporter(object):
|
||||
"""
|
||||
def __init__(self, viewlist, reporter):
|
||||
# type: (ViewList, Reporter) -> None
|
||||
warnings.warn('AutodocReporter is now deprecated. '
|
||||
'Use sphinx.util.docutils.switch_source_input() instead.',
|
||||
RemovedInSphinx20Warning)
|
||||
self.viewlist = viewlist
|
||||
self.reporter = reporter
|
||||
|
||||
@ -284,14 +256,10 @@ class Documenter(object):
|
||||
|
||||
option_spec = {'noindex': bool_option} # type: Dict[unicode, Callable]
|
||||
|
||||
@staticmethod
|
||||
def get_attr(obj, name, *defargs):
|
||||
def get_attr(self, obj, name, *defargs):
|
||||
# type: (Any, unicode, Any) -> Any
|
||||
"""getattr() override for types such as Zope interfaces."""
|
||||
for typ, func in iteritems(AutoDirective._special_attrgetters):
|
||||
if isinstance(obj, typ):
|
||||
return func(obj, name, *defargs)
|
||||
return safe_getattr(obj, name, *defargs)
|
||||
return autodoc_attrgetter(self.env.app, obj, name, *defargs)
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls, member, membername, isattr, parent):
|
||||
@ -300,7 +268,7 @@ class Documenter(object):
|
||||
raise NotImplementedError('must be implemented in subclasses')
|
||||
|
||||
def __init__(self, directive, name, indent=u''):
|
||||
# type: (Directive, unicode, unicode) -> None
|
||||
# type: (DocumenterBridge, unicode, unicode) -> None
|
||||
self.directive = directive
|
||||
self.env = directive.env
|
||||
self.options = directive.genopt
|
||||
@ -324,6 +292,12 @@ class Documenter(object):
|
||||
# the module analyzer to get at attribute docs, or None
|
||||
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):
|
||||
# type: (unicode, unicode, int) -> None
|
||||
"""Append one line of generated reST to the output."""
|
||||
@ -354,8 +328,7 @@ class Documenter(object):
|
||||
explicit_modname, path, base, args, retann = \
|
||||
py_ext_sig_re.match(self.name).groups() # type: ignore
|
||||
except AttributeError:
|
||||
self.directive.warn('invalid signature for auto%s (%r)' %
|
||||
(self.objtype, self.name))
|
||||
logger.warning('invalid signature for auto%s (%r)' % (self.objtype, self.name))
|
||||
return False
|
||||
|
||||
# support explicit module and class name separation via ::
|
||||
@ -384,56 +357,15 @@ class Documenter(object):
|
||||
|
||||
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):
|
||||
try:
|
||||
logger.debug('[autodoc] import %s', self.modname)
|
||||
obj = import_module(self.modname, self.env.config.autodoc_warningiserror)
|
||||
parent = None
|
||||
self.module = obj
|
||||
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
|
||||
ret = import_object(self.modname, self.objpath, self.objtype,
|
||||
attrgetter=self.get_attr,
|
||||
warningiserror=self.env.config.autodoc_warningiserror)
|
||||
self.module, self.parent, self.object_name, self.object = ret
|
||||
return True
|
||||
except (AttributeError, ImportError) as exc:
|
||||
if self.objpath:
|
||||
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)
|
||||
except ImportError as exc:
|
||||
logger.warning(exc.args[0])
|
||||
self.env.note_reread()
|
||||
return False
|
||||
|
||||
@ -493,8 +425,8 @@ class Documenter(object):
|
||||
try:
|
||||
args = self.format_args()
|
||||
except Exception as err:
|
||||
self.directive.warn('error while formatting arguments for '
|
||||
'%s: %s' % (self.fullname, err))
|
||||
logger.warning('error while formatting arguments for %s: %s' %
|
||||
(self.fullname, err))
|
||||
args = None
|
||||
|
||||
retann = self.retann
|
||||
@ -606,57 +538,24 @@ class Documenter(object):
|
||||
If *want_all* is True, return all members. Else, only return those
|
||||
members given by *self.options.members* (which may also be none).
|
||||
"""
|
||||
analyzed_member_names = set()
|
||||
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])
|
||||
members = get_object_members(self.object, self.objpath, self.get_attr, self.analyzer)
|
||||
if not want_all:
|
||||
if not self.options.members:
|
||||
return False, []
|
||||
# specific members given
|
||||
members = []
|
||||
for mname in self.options.members:
|
||||
try:
|
||||
members.append((mname, self.get_attr(self.object, mname)))
|
||||
except AttributeError:
|
||||
if mname not in analyzed_member_names:
|
||||
self.directive.warn('missing attribute %s in object %s'
|
||||
% (mname, self.fullname))
|
||||
selected = []
|
||||
for name in self.options.members:
|
||||
if name in members:
|
||||
selected.append((name, members[name].value))
|
||||
else:
|
||||
logger.warning('missing attribute %s in object %s' %
|
||||
(name, self.fullname))
|
||||
return False, sorted(selected)
|
||||
elif self.options.inherited_members:
|
||||
# safe_getmembers() uses dir() which pulls in members from all
|
||||
# base classes
|
||||
members = safe_getmembers(self.object, attr_getter=self.get_attr)
|
||||
return False, sorted((m.name, m.value) for m in itervalues(members))
|
||||
else:
|
||||
# __dict__ contains only the members directly defined in
|
||||
# the class (but get them via getattr anyway, to e.g. get
|
||||
# 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)
|
||||
return False, sorted((m.name, m.value) for m in itervalues(members)
|
||||
if m.directly_defined)
|
||||
|
||||
def filter_members(self, members, want_all):
|
||||
# type: (List[Tuple[unicode, Any]], bool) -> List[Tuple[unicode, Any, bool]]
|
||||
@ -715,8 +614,7 @@ class Documenter(object):
|
||||
elif (namespace, membername) in attr_docs:
|
||||
if want_all and membername.startswith('_'):
|
||||
# ignore members whose name starts with _ by default
|
||||
keep = self.options.private_members and \
|
||||
(has_doc or self.options.undoc_members)
|
||||
keep = self.options.private_members
|
||||
else:
|
||||
# keep documented attributes
|
||||
keep = True
|
||||
@ -769,7 +667,7 @@ class Documenter(object):
|
||||
# document non-skipped members
|
||||
memberdocumenters = [] # type: List[Tuple[Documenter, bool]]
|
||||
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 not classes:
|
||||
# don't know how to document this member
|
||||
@ -820,11 +718,11 @@ class Documenter(object):
|
||||
"""
|
||||
if not self.parse_name():
|
||||
# need a module to import
|
||||
self.directive.warn(
|
||||
logger.warning(
|
||||
'don\'t know which module to import for autodocumenting '
|
||||
'%r (try placing a "module" or "currentmodule" directive '
|
||||
'in the document, or giving an explicit module name)'
|
||||
% self.name)
|
||||
'in the document, or giving an explicit module name)' %
|
||||
self.name)
|
||||
return
|
||||
|
||||
# now, import the module and get object to document
|
||||
@ -910,15 +808,15 @@ class ModuleDocumenter(Documenter):
|
||||
def resolve_name(self, modname, parents, path, base):
|
||||
# type: (str, Any, str, Any) -> Tuple[str, List[unicode]]
|
||||
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, []
|
||||
|
||||
def parse_name(self):
|
||||
# type: () -> bool
|
||||
ret = Documenter.parse_name(self)
|
||||
if self.args or self.retann:
|
||||
self.directive.warn('signature arguments or return annotation '
|
||||
'given for automodule %s' % self.fullname)
|
||||
logger.warning('signature arguments or return annotation '
|
||||
'given for automodule %s' % self.fullname)
|
||||
return ret
|
||||
|
||||
def add_directive_header(self, sig):
|
||||
@ -950,7 +848,7 @@ class ModuleDocumenter(Documenter):
|
||||
# Sometimes __all__ is broken...
|
||||
if not isinstance(memberlist, (list, tuple)) or not \
|
||||
all(isinstance(entry, string_types) for entry in memberlist):
|
||||
self.directive.warn(
|
||||
logger.warning(
|
||||
'__all__ should be a list of strings, not %r '
|
||||
'(in module %s) -- ignoring __all__' %
|
||||
(memberlist, self.fullname))
|
||||
@ -963,10 +861,10 @@ class ModuleDocumenter(Documenter):
|
||||
try:
|
||||
ret.append((mname, safe_getattr(self.object, mname)))
|
||||
except AttributeError:
|
||||
self.directive.warn(
|
||||
logger.warning(
|
||||
'missing attribute mentioned in :members: or __all__: '
|
||||
'module %s, attribute %s' % (
|
||||
safe_getattr(self.object, '__name__', '???'), mname))
|
||||
'module %s, attribute %s' %
|
||||
(safe_getattr(self.object, '__name__', '???'), mname))
|
||||
return False, ret
|
||||
|
||||
|
||||
@ -1505,118 +1403,56 @@ class InstanceAttributeDocumenter(AttributeDocumenter):
|
||||
AttributeDocumenter.add_content(self, more_content, no_docstring=True)
|
||||
|
||||
|
||||
class AutoDirective(Directive):
|
||||
"""
|
||||
The AutoDirective class is used for all autodoc directives. It dispatches
|
||||
most of the work to one of the Documenters, which it selects through its
|
||||
*_registry* dictionary.
|
||||
class DeprecatedDict(dict):
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
super(DeprecatedDict, self).__init__()
|
||||
|
||||
The *_special_attrgetters* attribute is used to customize ``getattr()``
|
||||
calls that the Documenters make; its entries are of the form ``type:
|
||||
getattr_function``.
|
||||
def __setitem__(self, key, value):
|
||||
warnings.warn(self.message, RemovedInSphinx20Warning)
|
||||
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
|
||||
accessed using the descendant's *_special_attrgetters*, thus this
|
||||
dictionary should include all necessary functions for accessing
|
||||
attributes of the parents.
|
||||
"""
|
||||
# a registry of objtype -> documenter class
|
||||
_registry = {} # type: Dict[unicode, Type[Documenter]]
|
||||
# a registry of objtype -> documenter class (Deprecated)
|
||||
_registry = DeprecatedDict(
|
||||
'AutoDirective._registry has been deprecated. '
|
||||
'Please use app.add_autodocumenter() instead.'
|
||||
) # type: Dict[unicode, Type[Documenter]]
|
||||
|
||||
# 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
|
||||
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
|
||||
AutoDirective = AutodocRegistry # for backward compatibility
|
||||
|
||||
|
||||
def add_documenter(cls):
|
||||
# type: (Type[Documenter]) -> None
|
||||
"""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):
|
||||
raise ExtensionError('autodoc documenter %r must be a subclass '
|
||||
'of Documenter' % cls)
|
||||
@ -1627,6 +1463,29 @@ def add_documenter(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):
|
||||
# type: (Sphinx) -> Dict[unicode, Any]
|
||||
app.add_autodocumenter(ModuleDocumenter)
|
||||
|
155
sphinx/ext/autodoc/directive.py
Normal file
155
sphinx/ext/autodoc/directive.py
Normal 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
|
@ -13,13 +13,17 @@ import sys
|
||||
import warnings
|
||||
import traceback
|
||||
import contextlib
|
||||
from collections import namedtuple
|
||||
from types import FunctionType, MethodType, ModuleType
|
||||
|
||||
from six import PY2
|
||||
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import isenumclass, safe_getattr
|
||||
|
||||
if False:
|
||||
# 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__)
|
||||
|
||||
@ -80,13 +84,7 @@ class _MockModule(ModuleType):
|
||||
class _MockImporter(object):
|
||||
def __init__(self, names):
|
||||
# type: (List[str]) -> None
|
||||
self.base_packages = set() # type: Set[str]
|
||||
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.names = names
|
||||
self.mocked_modules = [] # type: List[str]
|
||||
# enable hook by adding itself to meta_path
|
||||
sys.meta_path = sys.meta_path + [self]
|
||||
@ -102,9 +100,10 @@ class _MockImporter(object):
|
||||
|
||||
def find_module(self, name, path=None):
|
||||
# type: (str, str) -> Any
|
||||
base_package = name.split('.')[0]
|
||||
if base_package in self.base_packages:
|
||||
return self
|
||||
# check if name is (or is a descendant of) one of our base_packages
|
||||
for n in self.names:
|
||||
if n == name or name.startswith(n + '.'):
|
||||
return self
|
||||
return None
|
||||
|
||||
def load_module(self, name):
|
||||
@ -144,3 +143,86 @@ def import_module(modname, warningiserror=False):
|
||||
# Importing modules may cause any side effects, including
|
||||
# SystemExit, so we need to catch all errors.
|
||||
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
|
||||
|
@ -72,7 +72,8 @@ from sphinx import addnodes
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.util import import_object, rst, logging
|
||||
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
|
||||
|
||||
if False:
|
||||
@ -153,13 +154,13 @@ def autosummary_table_visit_html(self, node):
|
||||
|
||||
# -- autodoc integration -------------------------------------------------------
|
||||
|
||||
class FakeDirective(object):
|
||||
env = {} # type: Dict
|
||||
genopt = Options()
|
||||
class FakeDirective(DocumenterBridge):
|
||||
def __init__(self):
|
||||
super(FakeDirective, self).__init__({}, None, Options(), 0) # type: ignore
|
||||
|
||||
|
||||
def get_documenter(obj, parent):
|
||||
# type: (Any, Any) -> Type[Documenter]
|
||||
def get_documenter(app, obj, parent):
|
||||
# type: (Sphinx, Any, Any) -> Type[Documenter]
|
||||
"""Get an autodoc.Documenter class suitable for documenting the given
|
||||
object.
|
||||
|
||||
@ -167,8 +168,7 @@ def get_documenter(obj, parent):
|
||||
another Python object (e.g. a module or a class) to which *obj*
|
||||
belongs to.
|
||||
"""
|
||||
from sphinx.ext.autodoc import AutoDirective, DataDocumenter, \
|
||||
ModuleDocumenter
|
||||
from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter
|
||||
|
||||
if inspect.ismodule(obj):
|
||||
# ModuleDocumenter.can_document_member always returns False
|
||||
@ -176,7 +176,7 @@ def get_documenter(obj, parent):
|
||||
|
||||
# Construct a fake documenter for *parent*
|
||||
if parent is not None:
|
||||
parent_doc_cls = get_documenter(parent, None)
|
||||
parent_doc_cls = get_documenter(app, parent, None)
|
||||
else:
|
||||
parent_doc_cls = ModuleDocumenter
|
||||
|
||||
@ -186,7 +186,7 @@ def get_documenter(obj, parent):
|
||||
parent_doc = parent_doc_cls(FakeDirective(), "")
|
||||
|
||||
# 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 classes:
|
||||
classes.sort(key=lambda cls: cls.priority)
|
||||
@ -289,7 +289,7 @@ class Autosummary(Directive):
|
||||
full_name = modname + '::' + full_name[len(modname) + 1:]
|
||||
# NB. using full_name here is important, since Documenters
|
||||
# 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():
|
||||
self.warn('failed to parse name %s' % real_name)
|
||||
items.append((display_name, '', '', real_name))
|
||||
@ -325,7 +325,7 @@ class Autosummary(Directive):
|
||||
# -- Grab the summary
|
||||
|
||||
documenter.add_content(None)
|
||||
doc = list(documenter.process_doc([self.result.data]))
|
||||
doc = self.result.data
|
||||
|
||||
while doc and not doc[0].strip():
|
||||
doc.pop(0)
|
||||
@ -615,7 +615,8 @@ def process_generate_options(app):
|
||||
|
||||
generate_autosummary_docs(genfiles, builder=app.builder,
|
||||
warn=logger.warning, info=logger.info,
|
||||
suffix=suffix, base_path=app.srcdir)
|
||||
suffix=suffix, base_path=app.srcdir,
|
||||
app=app)
|
||||
|
||||
|
||||
def setup(app):
|
||||
|
@ -33,24 +33,11 @@ from sphinx import __display_version__
|
||||
from sphinx import package_dir
|
||||
from sphinx.ext.autosummary import import_by_name, get_documenter
|
||||
from sphinx.jinja2glue import BuiltinTemplateLoader
|
||||
from sphinx.registry import SphinxComponentRegistry
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.inspect import safe_getattr
|
||||
from sphinx.util.rst import escape as rst_escape
|
||||
|
||||
# Add documenters to AutoDirective registry
|
||||
from sphinx.ext.autodoc import add_documenter, \
|
||||
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:
|
||||
# For type annotation
|
||||
from typing import Any, Callable, Dict, Tuple, List # NOQA
|
||||
@ -60,6 +47,30 @@ if False:
|
||||
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):
|
||||
# type: (unicode) -> None
|
||||
print(msg)
|
||||
@ -81,8 +92,8 @@ def _underline(title, line='='):
|
||||
def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
warn=_simple_warn, info=_simple_info,
|
||||
base_path=None, builder=None, template_dir=None,
|
||||
imported_members=False):
|
||||
# type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool) -> None # NOQA
|
||||
imported_members=False, app=None):
|
||||
# type: (List[unicode], unicode, unicode, Callable, Callable, unicode, Builder, unicode, bool, Any) -> None # NOQA
|
||||
|
||||
showed_sources = list(sorted(sources))
|
||||
if len(showed_sources) > 20:
|
||||
@ -148,7 +159,7 @@ def generate_autosummary_docs(sources, output_dir=None, suffix='.rst',
|
||||
new_files.append(fn)
|
||||
|
||||
with open(fn, 'w') as f:
|
||||
doc = get_documenter(obj, parent)
|
||||
doc = get_documenter(app, obj, parent)
|
||||
|
||||
if template_name is not None:
|
||||
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)
|
||||
except AttributeError:
|
||||
continue
|
||||
documenter = get_documenter(value, obj)
|
||||
documenter = get_documenter(app, value, obj)
|
||||
if documenter.objtype == typ:
|
||||
if typ == 'method':
|
||||
items.append(name)
|
||||
@ -392,11 +403,14 @@ The format of the autosummary directive is documented in the
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
# type: (List[str]) -> None
|
||||
app = DummyApplication()
|
||||
setup_documenters(app)
|
||||
args = get_parser().parse_args(argv)
|
||||
generate_autosummary_docs(args.source_file, args.output_dir,
|
||||
'.' + args.suffix,
|
||||
template_dir=args.templates,
|
||||
imported_members=args.imported_members)
|
||||
imported_members=args.imported_members,
|
||||
app=app)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -50,8 +50,12 @@ def compile_regex_list(name, exps):
|
||||
|
||||
|
||||
class CoverageBuilder(Builder):
|
||||
|
||||
"""
|
||||
Evaluates coverage of code in the documentation.
|
||||
"""
|
||||
name = 'coverage'
|
||||
epilog = ('Testing of coverage in the sources finished, look at the '
|
||||
'results in %(outdir)s/python.txt.')
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
|
@ -20,7 +20,8 @@ from os import path
|
||||
import doctest
|
||||
|
||||
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.parsers.rst import Directive, directives
|
||||
@ -57,28 +58,23 @@ else:
|
||||
return text
|
||||
|
||||
|
||||
def compare_version(ver1, ver2, operand):
|
||||
# type: (unicode, unicode, unicode) -> bool
|
||||
"""Compare `ver1` to `ver2`, relying on `operand`.
|
||||
def is_allowed_version(spec, version):
|
||||
# type: (unicode, unicode) -> bool
|
||||
"""Check `spec` satisfies `version` or not.
|
||||
|
||||
This obeys PEP-440 specifiers:
|
||||
https://www.python.org/dev/peps/pep-0440/#version-specifiers
|
||||
|
||||
Some examples:
|
||||
|
||||
>>> compare_version('3.3', '3.5', '<=')
|
||||
>>> is_allowed_version('3.3', '<=3.5')
|
||||
True
|
||||
>>> compare_version('3.3', '3.2', '<=')
|
||||
>>> is_allowed_version('3.3', '<=3.2')
|
||||
False
|
||||
>>> compare_version('3.3a0', '3.3', '<=')
|
||||
>>> is_allowed_version('3.3', '>3.2, <4.0')
|
||||
True
|
||||
"""
|
||||
if operand not in ('<=', '<', '==', '>=', '>'):
|
||||
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)))
|
||||
return Version(version) in SpecifierSet(spec)
|
||||
|
||||
|
||||
# set up the necessary directives
|
||||
@ -120,7 +116,11 @@ class TestDirective(Directive):
|
||||
if test is not None:
|
||||
# only save if it differs from code
|
||||
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
|
||||
node['language'] = 'none'
|
||||
node['options'] = {}
|
||||
@ -143,16 +143,13 @@ class TestDirective(Directive):
|
||||
node['options'][flag] = (option[0] == '+')
|
||||
if self.name == 'doctest' and 'pyversion' in self.options:
|
||||
try:
|
||||
option = self.options['pyversion']
|
||||
# :pyversion: >= 3.6 --> operand='>=', option_version='3.6'
|
||||
operand, option_version = [item.strip() for item in option.split()]
|
||||
running_version = platform.python_version()
|
||||
if not compare_version(running_version, option_version, operand):
|
||||
spec = self.options['pyversion']
|
||||
if not is_allowed_version(spec, platform.python_version()):
|
||||
flag = doctest.OPTIONFLAGS_BY_NAME['SKIP']
|
||||
node['options'][flag] = True # Skip the test
|
||||
except ValueError:
|
||||
except InvalidSpecifier:
|
||||
self.state.document.reporter.warning(
|
||||
_("'%s' is not a valid pyversion option") % option,
|
||||
_("'%s' is not a valid pyversion option") % spec,
|
||||
line=self.lineno)
|
||||
return [node]
|
||||
|
||||
@ -278,6 +275,8 @@ class DocTestBuilder(Builder):
|
||||
Runs test snippets in the documentation.
|
||||
"""
|
||||
name = 'doctest'
|
||||
epilog = ('Testing of doctests in the sources finished, look at the '
|
||||
'results in %(outdir)s/output.txt.')
|
||||
|
||||
def init(self):
|
||||
# type: () -> None
|
||||
|
@ -130,8 +130,8 @@ class InheritanceGraph(object):
|
||||
graphviz dot graph from them.
|
||||
"""
|
||||
def __init__(self, class_names, currmodule, show_builtins=False,
|
||||
private_bases=False, parts=0, aliases=None):
|
||||
# type: (unicode, str, bool, bool, int, Optional[Dict[unicode, unicode]]) -> None
|
||||
private_bases=False, parts=0, aliases=None, top_classes=[]):
|
||||
# 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.
|
||||
|
||||
If *show_builtins* is True, then Python builtins will be shown
|
||||
@ -140,7 +140,7 @@ class InheritanceGraph(object):
|
||||
self.class_names = class_names
|
||||
classes = self._import_classes(class_names, currmodule)
|
||||
self.class_info = self._class_info(classes, show_builtins,
|
||||
private_bases, parts, aliases)
|
||||
private_bases, parts, aliases, top_classes)
|
||||
if not self.class_info:
|
||||
raise InheritanceException('No classes found for '
|
||||
'inheritance diagram')
|
||||
@ -153,13 +153,16 @@ class InheritanceGraph(object):
|
||||
classes.extend(import_classes(name, currmodule))
|
||||
return classes
|
||||
|
||||
def _class_info(self, classes, show_builtins, private_bases, parts, aliases):
|
||||
# type: (List[Any], bool, bool, int, Optional[Dict[unicode, unicode]]) -> List[Tuple[unicode, unicode, List[unicode], unicode]] # NOQA
|
||||
def _class_info(self, classes, show_builtins, private_bases, parts, aliases, top_classes):
|
||||
# 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
|
||||
*classes*.
|
||||
|
||||
*parts* gives the number of dotted name parts that is removed from the
|
||||
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 = {}
|
||||
py_builtins = vars(builtins).values()
|
||||
@ -189,6 +192,10 @@ class InheritanceGraph(object):
|
||||
|
||||
baselist = [] # type: List[unicode]
|
||||
all_classes[cls] = (nodename, fullname, baselist, tooltip)
|
||||
|
||||
if fullname in top_classes:
|
||||
return
|
||||
|
||||
for base in cls.__bases__:
|
||||
if not show_builtins and base in py_builtins:
|
||||
continue
|
||||
@ -322,6 +329,7 @@ class InheritanceDiagram(Directive):
|
||||
'parts': directives.nonnegative_int,
|
||||
'private-bases': directives.flag,
|
||||
'caption': directives.unchanged,
|
||||
'top-classes': directives.unchanged_required,
|
||||
}
|
||||
|
||||
def run(self):
|
||||
@ -334,6 +342,11 @@ class InheritanceDiagram(Directive):
|
||||
# Store the original content for use as a hash
|
||||
node['parts'] = self.options.get('parts', 0)
|
||||
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
|
||||
try:
|
||||
@ -341,7 +354,8 @@ class InheritanceDiagram(Directive):
|
||||
class_names, env.ref_context.get('py:module'),
|
||||
parts=node['parts'],
|
||||
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:
|
||||
return [node.document.reporter.warning(err.args[0],
|
||||
line=self.lineno)]
|
||||
|
@ -304,6 +304,7 @@ def missing_reference(app, env, node, contnode):
|
||||
in_set = setname
|
||||
to_try.append((inventories.named_inventory[setname], newtarget))
|
||||
if domain:
|
||||
node['reftarget'] = newtarget
|
||||
full_qualified_name = env.get_domain(domain).get_full_qualified_name(node)
|
||||
if full_qualified_name:
|
||||
to_try.append((inventories.named_inventory[setname], full_qualified_name))
|
||||
|
@ -20,14 +20,14 @@ from sphinx.ext.mathbase import get_node_equation_number
|
||||
|
||||
|
||||
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>')
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
def html_visit_displaymath(self, node):
|
||||
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('</div>')
|
||||
raise nodes.SkipNode
|
||||
@ -40,7 +40,7 @@ def html_visit_displaymath(self, node):
|
||||
self.body.append('<span class="eqno">(%s)' % number)
|
||||
self.add_permalink_ref(node, _('Permalink to this equation'))
|
||||
self.body.append('</span>')
|
||||
self.body.append(self.starttag(node, 'div', CLASS='math'))
|
||||
self.body.append(self.starttag(node, 'div', CLASS='math notranslate'))
|
||||
else:
|
||||
# but only once!
|
||||
self.body.append('<div class="math">')
|
||||
|
@ -21,7 +21,7 @@ from sphinx.ext.mathbase import get_node_equation_number
|
||||
|
||||
|
||||
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.encode(node['latex']) +
|
||||
self.builder.config.mathjax_inline[1] + '</span>')
|
||||
@ -29,7 +29,7 @@ def html_visit_math(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']:
|
||||
self.body.append(self.encode(node['latex']))
|
||||
self.body.append('</div>')
|
||||
|
@ -71,12 +71,12 @@ def doctree_read(app, doctree):
|
||||
code = analyzer.code.decode(analyzer.encoding)
|
||||
else:
|
||||
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()
|
||||
entry = code, analyzer.tags, {}, refname
|
||||
env._viewcode_modules[modname] = entry # type: ignore
|
||||
elif entry is False:
|
||||
return
|
||||
_, tags, used, _ = entry
|
||||
if fullname in tags:
|
||||
used[fullname] = docname
|
||||
|
22
sphinx/io.py
22
sphinx/io.py
@ -19,11 +19,12 @@ from docutils.writers import UnfilteredWriter
|
||||
from six import text_type
|
||||
from typing import Any, Union # NOQA
|
||||
|
||||
from sphinx.transforms import SphinxTransformer
|
||||
from sphinx.transforms import (
|
||||
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
|
||||
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks, SortIds,
|
||||
AutoNumbering, AutoIndexUpgrader, FilterSystemMessages,
|
||||
UnreferencedFootnotesDetector
|
||||
UnreferencedFootnotesDetector, SphinxSmartQuotes, ManpageLink
|
||||
)
|
||||
from sphinx.transforms.compact_bullet_list import RefOnlyBulletListTransform
|
||||
from sphinx.transforms.i18n import (
|
||||
@ -56,6 +57,11 @@ class SphinxBaseReader(standalone.Reader):
|
||||
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):
|
||||
# type: () -> List[Transform]
|
||||
return standalone.Reader.get_transforms(self) + self.transforms
|
||||
@ -66,9 +72,16 @@ class SphinxBaseReader(standalone.Reader):
|
||||
for logging.
|
||||
"""
|
||||
document = standalone.Reader.new_document(self)
|
||||
|
||||
# substitute transformer
|
||||
document.transformer = SphinxTransformer(document)
|
||||
document.transformer.set_environment(self.env)
|
||||
|
||||
# substitute reporter
|
||||
reporter = document.reporter
|
||||
document.reporter = LoggingReporter.from_reporter(reporter)
|
||||
document.reporter.set_source(self.source)
|
||||
|
||||
return document
|
||||
|
||||
|
||||
@ -80,13 +93,14 @@ class SphinxStandaloneReader(SphinxBaseReader):
|
||||
Locale, CitationReferences, DefaultSubstitutions, MoveModuleTargets,
|
||||
HandleCodeBlocks, AutoNumbering, AutoIndexUpgrader, SortIds,
|
||||
RemoveTranslatableInline, PreserveTranslatableMessages, FilterSystemMessages,
|
||||
RefOnlyBulletListTransform, UnreferencedFootnotesDetector
|
||||
RefOnlyBulletListTransform, UnreferencedFootnotesDetector, SphinxSmartQuotes,
|
||||
ManpageLink
|
||||
] # type: List[Transform]
|
||||
|
||||
def __init__(self, app, *args, **kwargs):
|
||||
# type: (Sphinx, Any, Any) -> None
|
||||
self.transforms = self.transforms + app.registry.get_transforms()
|
||||
SphinxBaseReader.__init__(self, *args, **kwargs) # type: ignore
|
||||
SphinxBaseReader.__init__(self, app, *args, **kwargs)
|
||||
|
||||
|
||||
class SphinxI18nReader(SphinxBaseReader):
|
||||
@ -103,7 +117,7 @@ class SphinxI18nReader(SphinxBaseReader):
|
||||
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
|
||||
AutoNumbering, SortIds, RemoveTranslatableInline,
|
||||
FilterSystemMessages, RefOnlyBulletListTransform,
|
||||
UnreferencedFootnotesDetector]
|
||||
UnreferencedFootnotesDetector, ManpageLink]
|
||||
|
||||
def set_lineno_for_reporter(self, lineno):
|
||||
# type: (int) -> None
|
||||
|
@ -97,101 +97,6 @@ class Make(object):
|
||||
if not osname or os.name == osname:
|
||||
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):
|
||||
# type: () -> int
|
||||
if self.run_generic_build('latex') > 0:
|
||||
@ -206,25 +111,6 @@ class Make(object):
|
||||
with cd(self.builddir_join('latex')):
|
||||
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):
|
||||
# type: () -> int
|
||||
if self.run_generic_build('texinfo') > 0:
|
||||
@ -237,60 +123,6 @@ class Make(object):
|
||||
dtdir = self.builddir_join('gettext', '.doctrees')
|
||||
if self.run_generic_build('gettext', doctreedir=dtdir) > 0:
|
||||
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
|
||||
|
||||
def run_generic_build(self, builder, doctreedir=None):
|
||||
|
@ -15,8 +15,6 @@ from docutils.parsers.rst import states
|
||||
from docutils.statemachine import StringList
|
||||
from docutils.transforms.universal import SmartQuotes
|
||||
|
||||
from sphinx.transforms import SphinxSmartQuotes
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any, Dict, List, Type # NOQA
|
||||
@ -63,10 +61,11 @@ class RSTParser(docutils.parsers.rst.Parser):
|
||||
|
||||
def get_transforms(self):
|
||||
# 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.remove(SmartQuotes)
|
||||
transforms.append(SphinxSmartQuotes)
|
||||
return transforms
|
||||
|
||||
def parse(self, inputstring, document):
|
||||
|
@ -38,6 +38,7 @@ if False:
|
||||
from sphinx.builders import Builder # NOQA
|
||||
from sphinx.domains import Domain, Index # NOQA
|
||||
from sphinx.environment import BuildEnvironment # NOQA
|
||||
from sphinx.ext.autodoc import Documenter # NOQA
|
||||
from sphinx.util.typing import RoleFunction # NOQA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -51,7 +52,9 @@ EXTENSION_BLACKLIST = {
|
||||
|
||||
class SphinxComponentRegistry(object):
|
||||
def __init__(self):
|
||||
self.autodoc_attrgettrs = {} # type: Dict[Type, Callable[[Any, unicode, Any], Any]]
|
||||
self.builders = {} # type: Dict[unicode, Type[Builder]]
|
||||
self.documenters = {} # type: Dict[unicode, Type[Documenter]]
|
||||
self.domains = {} # type: Dict[unicode, Type[Domain]]
|
||||
self.domain_directives = {} # type: Dict[unicode, Dict[unicode, Any]]
|
||||
self.domain_indices = {} # type: Dict[unicode, List[Type[Index]]]
|
||||
@ -284,6 +287,14 @@ class SphinxComponentRegistry(object):
|
||||
# type: () -> List[Type[Transform]]
|
||||
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):
|
||||
# type: (Sphinx, unicode) -> None
|
||||
"""Load a Sphinx extension."""
|
||||
|
@ -207,4 +207,4 @@ class SearchFrench(SearchLanguage):
|
||||
self.stemmer = snowballstemmer.stemmer('french')
|
||||
|
||||
def stem(self, word):
|
||||
return self.stemmer.stemWord(word)
|
||||
return self.stemmer.stemWord(word.lower())
|
||||
|
@ -5,14 +5,16 @@
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
PAPER ?=
|
||||
SOURCEDIR = {{ rsrcdir }}
|
||||
BUILDDIR = {{ rbuilddir }}
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_elements.papersize=a4
|
||||
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
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) {{ rsrcdir }}
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(O) $(SOURCEDIR)
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@ -49,86 +51,6 @@ help:
|
||||
clean:
|
||||
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
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@ -157,26 +79,6 @@ xelatexpdf:
|
||||
$(MAKE) PDFLATEX=xelatex -C $(BUILDDIR)/latex all-pdf
|
||||
@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
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@ -187,49 +89,9 @@ info:
|
||||
.PHONY: gettext
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
.PHONY: changes
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@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."
|
||||
# Catch-all target: route all unknown targets to Sphinx
|
||||
.PHONY: Makefile
|
||||
%: Makefile
|
||||
$(SPHINXBUILD) -b "$@" $(ALLSPHINXOPTS) "$(BUILDDIR)/$@"
|
||||
|
||||
|
@ -1,19 +1,12 @@
|
||||
{% if PY3 -%}
|
||||
#!/usr/bin/env python3
|
||||
{% endif -%}
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# {{ project }} documentation build configuration file, created by
|
||||
# sphinx-quickstart on {{ now }}.
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/stable/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# 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
|
||||
@ -33,7 +26,19 @@ sys.path.insert(0, u'{{ module_path }}')
|
||||
{% 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.
|
||||
#
|
||||
@ -60,20 +65,6 @@ source_suffix = '{{ suffix }}'
|
||||
# The master toctree document.
|
||||
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
|
||||
# for a list of supported languages.
|
||||
#
|
||||
@ -90,7 +81,7 @@ exclude_patterns = [{{ exclude_patterns }}]
|
||||
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
|
||||
# a list of builtin themes.
|
||||
@ -119,13 +110,13 @@ html_static_path = ['{{ dot }}static']
|
||||
# html_sidebars = {}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '{{ project_fn }}doc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# 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
|
||||
# (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
|
||||
# (source start file, target name, title, author,
|
||||
@ -177,7 +168,7 @@ texinfo_documents = [
|
||||
{%- if epub %}
|
||||
|
||||
|
||||
# -- Options for Epub output ----------------------------------------------
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
@ -200,18 +191,18 @@ epub_exclude_files = ['search.html']
|
||||
{%- if extensions %}
|
||||
|
||||
|
||||
# -- Extension configuration ----------------------------------------------
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
{%- endif %}
|
||||
{%- if 'sphinx.ext.intersphinx' in extensions %}
|
||||
|
||||
# -- Options for intersphinx extension ------------------------------------
|
||||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
{%- endif %}
|
||||
{%- 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.
|
||||
todo_include_todos = True
|
||||
|
@ -8,8 +8,9 @@ if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR={{ rbuilddir }}
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% {{ rsrcdir }}
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% {{ rsrcdir }}
|
||||
set SOURCEDIR={{ rsrcdir }}
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% %SOURCEDIR%
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% %SOURCEDIR%
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_elements.papersize=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_elements.papersize=%PAPER% %I18NSPHINXOPTS%
|
||||
@ -50,7 +51,6 @@ if "%1" == "clean" (
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
REM Check if sphinx-build is available and fallback to Python version if any
|
||||
%SPHINXBUILD% 1>NUL 2>NUL
|
||||
if errorlevel 9009 goto sphinx_python
|
||||
@ -74,92 +74,6 @@ if errorlevel 9009 (
|
||||
|
||||
: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" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
@ -180,96 +94,14 @@ if "%1" == "latexpdfja" (
|
||||
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" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
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
|
||||
)
|
||||
%SPHINXBUILD% -b %1 %ALLSPHINXOPTS% %BUILDDIR%/%1
|
||||
goto end
|
||||
|
||||
:end
|
||||
popd
|
||||
|
@ -504,7 +504,7 @@
|
||||
\fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}}
|
||||
\fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}}
|
||||
\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{\footrulewidth}{0.4pt}
|
||||
% 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
|
||||
% release to specify the release that is documented.
|
||||
%
|
||||
\newcommand{\py@release}{}
|
||||
\newcommand{\version}{}
|
||||
\newcommand{\shortversion}{}
|
||||
\newcommand{\py@release}{\releasename\space\version}
|
||||
\newcommand{\version}{}% part of \py@release, used by title page and headers
|
||||
% \releaseinfo is used on titlepage (sphinxmanual.cls, sphinxhowto.cls)
|
||||
\newcommand{\releaseinfo}{}
|
||||
\newcommand{\releasename}{Release}
|
||||
\newcommand{\release}[1]{%
|
||||
\renewcommand{\py@release}{\releasename\space\version}%
|
||||
\renewcommand{\version}{#1}}
|
||||
\newcommand{\setshortversion}[1]{%
|
||||
\renewcommand{\shortversion}{#1}}
|
||||
\newcommand{\setreleaseinfo}[1]{%
|
||||
\renewcommand{\releaseinfo}{#1}}
|
||||
\newcommand{\setreleaseinfo}[1]{\renewcommand{\releaseinfo}{#1}}
|
||||
% this is inserted via template and #1=release config variable
|
||||
\newcommand{\release}[1]{\renewcommand{\version}{#1}}
|
||||
% this is defined by template to 'releasename' latex_elements key
|
||||
\newcommand{\releasename}{}
|
||||
% Fix issue in case release and releasename deliberately left blank
|
||||
\newcommand{\sphinxheadercomma}{, }% used in fancyhdr header definition
|
||||
\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
|
||||
% author's name. This can be used to format them differently, which
|
||||
|
9
sphinx/themes/basic/documentation_options.js_t
Normal file
9
sphinx/themes/basic/documentation_options.js_t
Normal 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 }}'
|
||||
};
|
@ -87,16 +87,7 @@
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro script() %}
|
||||
<script type="text/javascript">
|
||||
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>
|
||||
<script type="text/javascript" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
|
@ -10,12 +10,14 @@
|
||||
{%- if pagename != "search" and builder != "singlehtml" %}
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3>{{ _('Quick search') }}</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="{{ pathto('search') }}" method="get">
|
||||
<div><input type="text" name="q" /></div>
|
||||
<div><input type="submit" value="{{ _('Go') }}" /></div>
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="{{ _('Go') }}" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
{%- endif %}
|
||||
|
@ -82,9 +82,21 @@ div.sphinxsidebar input {
|
||||
}
|
||||
|
||||
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 {
|
||||
border: 0;
|
||||
max-width: 100%;
|
||||
|
@ -125,14 +125,11 @@ div.sphinxsidebar input {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input[type=text]{
|
||||
div.sphinxsidebar .searchformwrapper {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input[type=submit]{
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
a {
|
||||
|
@ -148,12 +148,9 @@ div.sphinxsidebar input {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input[type=text]{
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input[type=submit]{
|
||||
div.sphinxsidebar .searchformwrapper {
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
@ -9,11 +9,14 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.transforms import Transform, Transformer
|
||||
from docutils.transforms.parts import ContentsFilter
|
||||
from docutils.utils import new_document
|
||||
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.locale import _
|
||||
@ -333,12 +336,54 @@ class SphinxContentsFilter(ContentsFilter):
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
class SphinxSmartQuotes(SmartQuotes):
|
||||
class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
|
||||
"""
|
||||
Customized SmartQuotes to avoid transform for some extra node types.
|
||||
|
||||
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):
|
||||
# A generator that yields ``(texttype, nodetext)`` tuples for a list
|
||||
# of "Text" nodes (interface to ``smartquotes.educate_tokens()``).
|
||||
@ -348,3 +393,21 @@ class SphinxSmartQuotes(SmartQuotes):
|
||||
for txtnode in txtnodes:
|
||||
notsmartquotable = not is_smartquotable(txtnode)
|
||||
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)
|
||||
|
@ -50,7 +50,7 @@ def publish_msgstr(app, source, source_path, source_line, config, settings):
|
||||
:rtype: docutils.nodes.document
|
||||
"""
|
||||
from sphinx.io import SphinxI18nReader
|
||||
reader = SphinxI18nReader()
|
||||
reader = SphinxI18nReader(app)
|
||||
reader.set_lineno_for_reporter(source_line)
|
||||
parser = app.registry.create_source_parser(app, '')
|
||||
doc = reader.read(
|
||||
|
@ -18,7 +18,7 @@ from contextlib import contextmanager
|
||||
|
||||
import docutils
|
||||
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.utils import Reporter
|
||||
|
||||
@ -31,8 +31,9 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(
|
||||
|
||||
if False:
|
||||
# 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.statemachine import State # NOQA
|
||||
from sphinx.environment import BuildEnvironment # 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 '
|
||||
'additional arguments may be given'))
|
||||
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
|
||||
|
@ -404,10 +404,18 @@ class Signature(object):
|
||||
if annotation == Ellipsis:
|
||||
return '...'
|
||||
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 annotation else repr(annotation))
|
||||
if not 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':
|
||||
return annotation.__qualname__ # type: ignore
|
||||
|
@ -53,7 +53,7 @@ VERBOSITY_MAP.update({
|
||||
COLOR_MAP = defaultdict(lambda: 'blue') # type: Dict[int, unicode]
|
||||
COLOR_MAP.update({
|
||||
logging.ERROR: 'darkred',
|
||||
logging.WARNING: 'darkred',
|
||||
logging.WARNING: 'red',
|
||||
logging.DEBUG: 'darkgray',
|
||||
})
|
||||
|
||||
|
@ -79,6 +79,7 @@ class HTMLTranslator(BaseTranslator):
|
||||
self.highlightopts = builder.config.highlight_options
|
||||
self.highlightlinenothreshold = sys.maxsize
|
||||
self.docnames = [builder.current_docname] # for singlehtml builder
|
||||
self.manpages_url = builder.config.manpages_url
|
||||
self.protect_literal_text = 0
|
||||
self.permalink_text = builder.config.html_add_permalinks
|
||||
# support backwards-compatible setting to a bool
|
||||
@ -443,7 +444,7 @@ class HTMLTranslator(BaseTranslator):
|
||||
location=(self.builder.current_docname, node.line), **highlight_args
|
||||
)
|
||||
starttag = self.starttag(node, 'div', suffix='',
|
||||
CLASS='highlight-%s' % lang)
|
||||
CLASS='highlight-%s notranslate' % lang)
|
||||
self.body.append(starttag + highlighted + '</div>\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
@ -493,10 +494,10 @@ class HTMLTranslator(BaseTranslator):
|
||||
# type: (nodes.Node) -> None
|
||||
if 'kbd' in node['classes']:
|
||||
self.body.append(self.starttag(node, 'kbd', '',
|
||||
CLASS='docutils literal'))
|
||||
CLASS='docutils literal notranslate'))
|
||||
else:
|
||||
self.body.append(self.starttag(node, 'code', '',
|
||||
CLASS='docutils literal'))
|
||||
CLASS='docutils literal notranslate'))
|
||||
self.protect_literal_text += 1
|
||||
|
||||
def depart_literal(self, node):
|
||||
@ -816,9 +817,14 @@ class HTMLTranslator(BaseTranslator):
|
||||
def visit_manpage(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
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):
|
||||
# type: (nodes.Node) -> None
|
||||
if self.manpages_url:
|
||||
self.depart_reference(node)
|
||||
self.depart_literal_emphasis(node)
|
||||
|
||||
# overwritten to add even/odd classes
|
||||
|
@ -49,6 +49,7 @@ class HTML5Translator(BaseTranslator):
|
||||
self.highlightopts = builder.config.highlight_options
|
||||
self.highlightlinenothreshold = sys.maxsize
|
||||
self.docnames = [builder.current_docname] # for singlehtml builder
|
||||
self.manpages_url = builder.config.manpages_url
|
||||
self.protect_literal_text = 0
|
||||
self.permalink_text = builder.config.html_add_permalinks
|
||||
# support backwards-compatible setting to a bool
|
||||
@ -389,7 +390,7 @@ class HTML5Translator(BaseTranslator):
|
||||
location=(self.builder.current_docname, node.line), **highlight_args
|
||||
)
|
||||
starttag = self.starttag(node, 'div', suffix='',
|
||||
CLASS='highlight-%s' % lang)
|
||||
CLASS='highlight-%s notranslate' % lang)
|
||||
self.body.append(starttag + highlighted + '</div>\n')
|
||||
raise nodes.SkipNode
|
||||
|
||||
@ -439,10 +440,10 @@ class HTML5Translator(BaseTranslator):
|
||||
# type: (nodes.Node) -> None
|
||||
if 'kbd' in node['classes']:
|
||||
self.body.append(self.starttag(node, 'kbd', '',
|
||||
CLASS='docutils literal'))
|
||||
CLASS='docutils literal notranslate'))
|
||||
else:
|
||||
self.body.append(self.starttag(node, 'code', '',
|
||||
CLASS='docutils literal'))
|
||||
CLASS='docutils literal notranslate'))
|
||||
self.protect_literal_text += 1
|
||||
|
||||
def depart_literal(self, node):
|
||||
@ -758,9 +759,14 @@ class HTML5Translator(BaseTranslator):
|
||||
def visit_manpage(self, node):
|
||||
# type: (nodes.Node) -> None
|
||||
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):
|
||||
# type: (nodes.Node) -> None
|
||||
if self.manpages_url:
|
||||
self.depart_reference(node)
|
||||
self.depart_literal_emphasis(node)
|
||||
|
||||
# overwritten to add even/odd classes
|
||||
|
@ -549,7 +549,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
'author': document.settings.author, # treat as a raw LaTeX code
|
||||
'indexname': _('Index'),
|
||||
})
|
||||
if not self.elements['releasename']:
|
||||
if not self.elements['releasename'] and self.elements['release']:
|
||||
self.elements.update({
|
||||
'releasename': _('Release'),
|
||||
})
|
||||
@ -1376,6 +1376,9 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
self.table = Table(node)
|
||||
if 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
|
||||
|
||||
def depart_table(self, node):
|
||||
@ -1853,28 +1856,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
||||
(node['align'] == 'right' and 'r' or 'l', length or '0pt'))
|
||||
self.context.append(ids + '\\end{wrapfigure}\n')
|
||||
elif self.in_minipage:
|
||||
if ('align' not in node.attributes or
|
||||
node.attributes['align'] == 'center'):
|
||||
self.body.append('\n\\begin{center}')
|
||||
self.context.append('\\end{center}\n')
|
||||
else:
|
||||
self.body.append('\n\\begin{flush%s}' % node.attributes['align'])
|
||||
self.context.append('\\end{flush%s}\n' % node.attributes['align'])
|
||||
self.body.append('\n\\begin{center}')
|
||||
self.context.append('\\end{center}\n')
|
||||
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))
|
||||
self.body.append('\n\\begin{figure}[%s]\n\\centering\n' %
|
||||
self.elements['figure_align'])
|
||||
if any(isinstance(child, nodes.caption) for child in node):
|
||||
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):
|
||||
# type: (nodes.Node) -> None
|
||||
|
@ -183,6 +183,8 @@ class TextTranslator(nodes.NodeVisitor):
|
||||
else:
|
||||
self.nl = '\n'
|
||||
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.stateindent = [0]
|
||||
self.list_counter = [] # type: List[int]
|
||||
@ -307,6 +309,17 @@ class TextTranslator(nodes.NodeVisitor):
|
||||
raise nodes.SkipNode
|
||||
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):
|
||||
# type: (nodes.Node) -> None
|
||||
if isinstance(node.parent, nodes.section):
|
||||
@ -315,6 +328,8 @@ class TextTranslator(nodes.NodeVisitor):
|
||||
char = '^'
|
||||
text = None # type: unicode
|
||||
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()
|
||||
title = ['', text, '%s' % (char * column_width(text)), ''] # type: List[unicode]
|
||||
if len(self.states) == 2 and len(self.states[-1]) == 0:
|
||||
@ -987,7 +1002,10 @@ class TextTranslator(nodes.NodeVisitor):
|
||||
|
||||
def visit_reference(self, node):
|
||||
# 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):
|
||||
# type: (nodes.Node) -> None
|
||||
|
@ -35,14 +35,6 @@ def pytest_report_header(config):
|
||||
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):
|
||||
testroot = os.path.join(str(session.config.rootdir), 'tests')
|
||||
tempdir = os.path.abspath(os.getenv('SPHINX_TEST_TEMPDIR',
|
||||
@ -58,5 +50,4 @@ def _initialize_test_directory(session):
|
||||
|
||||
|
||||
def pytest_sessionstart(session):
|
||||
_filter_warnings()
|
||||
_initialize_test_directory(session)
|
||||
|
@ -21,6 +21,7 @@ from docutils.statemachine import ViewList
|
||||
|
||||
from sphinx.ext.autodoc import AutoDirective, add_documenter, \
|
||||
ModuleLevelDocumenter, FunctionDocumenter, cut_lines, between, ALL
|
||||
from sphinx.util import logging
|
||||
|
||||
app = None
|
||||
|
||||
@ -30,7 +31,7 @@ def setup_module(rootdir, sphinx_test_tempdir):
|
||||
global app
|
||||
srcdir = sphinx_test_tempdir / 'autodoc-root'
|
||||
if not srcdir.exists():
|
||||
(rootdir/'test-root').copytree(srcdir)
|
||||
(rootdir / 'test-root').copytree(srcdir)
|
||||
app = SphinxTestApp(srcdir=srcdir)
|
||||
app.builder.env.app = app
|
||||
app.builder.env.temp_data['docname'] = 'dummy'
|
||||
@ -47,7 +48,7 @@ directive = options = None
|
||||
@pytest.fixture
|
||||
def setup_test():
|
||||
global options, directive
|
||||
global processed_docstrings, processed_signatures, _warnings
|
||||
global processed_docstrings, processed_signatures
|
||||
|
||||
options = Struct(
|
||||
inherited_members = False,
|
||||
@ -70,24 +71,17 @@ def setup_test():
|
||||
env = app.builder.env,
|
||||
genopt = options,
|
||||
result = ViewList(),
|
||||
warn = warnfunc,
|
||||
filename_set = set(),
|
||||
)
|
||||
|
||||
processed_docstrings = []
|
||||
processed_signatures = []
|
||||
_warnings = []
|
||||
|
||||
|
||||
_warnings = []
|
||||
processed_docstrings = []
|
||||
processed_signatures = []
|
||||
|
||||
|
||||
def warnfunc(msg):
|
||||
_warnings.append(msg)
|
||||
|
||||
|
||||
def process_docstring(app, what, name, obj, options, lines):
|
||||
processed_docstrings.append((what, name))
|
||||
if name == 'bar':
|
||||
@ -111,20 +105,21 @@ def skip_member(app, what, name, obj, skip, options):
|
||||
|
||||
@pytest.mark.usefixtures('setup_test')
|
||||
def test_generate():
|
||||
logging.setup(app, app._status, app._warning)
|
||||
|
||||
def assert_warns(warn_str, objtype, name, **kw):
|
||||
inst = AutoDirective._registry[objtype](directive, name)
|
||||
inst = app.registry.documenters[objtype](directive, name)
|
||||
inst.generate(**kw)
|
||||
assert len(directive.result) == 0, directive.result
|
||||
assert len(_warnings) == 1, _warnings
|
||||
assert warn_str in _warnings[0], _warnings
|
||||
del _warnings[:]
|
||||
assert warn_str in app._warning.getvalue()
|
||||
app._warning.truncate(0)
|
||||
|
||||
def assert_works(objtype, name, **kw):
|
||||
inst = AutoDirective._registry[objtype](directive, name)
|
||||
inst = app.registry.documenters[objtype](directive, name)
|
||||
inst.generate(**kw)
|
||||
assert directive.result
|
||||
# print '\n'.join(directive.result)
|
||||
assert len(_warnings) == 0, _warnings
|
||||
assert app._warning.getvalue() == ''
|
||||
del directive.result[:]
|
||||
|
||||
def assert_processes(items, objtype, name, **kw):
|
||||
@ -134,18 +129,18 @@ def test_generate():
|
||||
assert set(processed_docstrings) | set(processed_signatures) == set(items)
|
||||
|
||||
def assert_result_contains(item, objtype, name, **kw):
|
||||
inst = AutoDirective._registry[objtype](directive, name)
|
||||
inst = app.registry.documenters[objtype](directive, name)
|
||||
inst.generate(**kw)
|
||||
# print '\n'.join(directive.result)
|
||||
assert len(_warnings) == 0, _warnings
|
||||
assert app._warning.getvalue() == ''
|
||||
assert item in directive.result
|
||||
del directive.result[:]
|
||||
|
||||
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.generate(**kw)
|
||||
assert len(_warnings) == 0, _warnings
|
||||
assert app._warning.getvalue() == ''
|
||||
items = list(reversed(items))
|
||||
lineiter = iter(directive.result)
|
||||
# for line in directive.result:
|
||||
|
0
tests/roots/test-apidoc-toc/mypackage/__init__.py
Normal file
0
tests/roots/test-apidoc-toc/mypackage/__init__.py
Normal file
16
tests/roots/test-apidoc-toc/mypackage/main.py
Executable file
16
tests/roots/test-apidoc-toc/mypackage/main.py
Executable 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))
|
1
tests/roots/test-apidoc-toc/mypackage/no_init/foo.py
Normal file
1
tests/roots/test-apidoc-toc/mypackage/no_init/foo.py
Normal file
@ -0,0 +1 @@
|
||||
MESSAGE="There's no __init__.py in this folder, hence we should be left out"
|
@ -0,0 +1 @@
|
||||
This is a text resource to be included in this otherwise empty module. No python contents here.
|
@ -0,0 +1 @@
|
||||
"Subpackage Something"
|
@ -1,5 +1,8 @@
|
||||
.. toctree::
|
||||
:numbered:
|
||||
|
||||
doc1
|
||||
doc2
|
||||
maxwidth
|
||||
lineblock
|
||||
nonascii_title
|
||||
|
2
tests/roots/test-build-text/doc1.txt
Normal file
2
tests/roots/test-build-text/doc1.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Section A
|
||||
=========
|
9
tests/roots/test-build-text/doc2.txt
Normal file
9
tests/roots/test-build-text/doc2.txt
Normal file
@ -0,0 +1,9 @@
|
||||
Section B
|
||||
=========
|
||||
|
||||
Sub Ba
|
||||
------
|
||||
|
||||
Sub Bb
|
||||
------
|
||||
|
5
tests/roots/test-inheritance/basic_diagram.rst
Normal file
5
tests/roots/test-inheritance/basic_diagram.rst
Normal file
@ -0,0 +1,5 @@
|
||||
Basic Diagram
|
||||
==============
|
||||
|
||||
.. inheritance-diagram::
|
||||
dummy.test
|
6
tests/roots/test-inheritance/conf.py
Normal file
6
tests/roots/test-inheritance/conf.py
Normal file
@ -0,0 +1,6 @@
|
||||
import sys, os
|
||||
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
extensions = ['sphinx.ext.inheritance_diagram']
|
||||
source_suffix = '.rst'
|
4
tests/roots/test-inheritance/contents.rst
Normal file
4
tests/roots/test-inheritance/contents.rst
Normal file
@ -0,0 +1,4 @@
|
||||
.. toctree::
|
||||
:glob:
|
||||
|
||||
*
|
@ -0,0 +1,6 @@
|
||||
Diagram using module with 2 top classes
|
||||
=======================================
|
||||
|
||||
.. inheritance-diagram::
|
||||
dummy.test
|
||||
:top-classes: dummy.test.B, dummy.test.C
|
7
tests/roots/test-inheritance/diagram_w_1_top_class.rst
Normal file
7
tests/roots/test-inheritance/diagram_w_1_top_class.rst
Normal file
@ -0,0 +1,7 @@
|
||||
Diagram using 1 top class
|
||||
=========================
|
||||
|
||||
.. inheritance-diagram::
|
||||
dummy.test
|
||||
:top-classes: dummy.test.B
|
||||
|
9
tests/roots/test-inheritance/diagram_w_2_top_classes.rst
Normal file
9
tests/roots/test-inheritance/diagram_w_2_top_classes.rst
Normal 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
|
||||
|
7
tests/roots/test-inheritance/diagram_w_parts.rst
Normal file
7
tests/roots/test-inheritance/diagram_w_parts.rst
Normal file
@ -0,0 +1,7 @@
|
||||
Diagram using the parts option
|
||||
==============================
|
||||
|
||||
.. inheritance-diagram::
|
||||
dummy.test
|
||||
:parts: 1
|
||||
|
0
tests/roots/test-inheritance/dummy/__init__.py
Normal file
0
tests/roots/test-inheritance/dummy/__init__.py
Normal file
30
tests/roots/test-inheritance/dummy/test.py
Normal file
30
tests/roots/test-inheritance/dummy/test.py
Normal 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
|
||||
|
5
tests/roots/test-manpage_url/conf.py
Normal file
5
tests/roots/test-manpage_url/conf.py
Normal file
@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
master_doc = 'index'
|
||||
html_theme = 'classic'
|
||||
exclude_patterns = ['_build']
|
3
tests/roots/test-manpage_url/index.rst
Normal file
3
tests/roots/test-manpage_url/index.rst
Normal 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
Loading…
Reference in New Issue
Block a user