Merge branch 'master' into dont_emit_system_message_on_autodoc_warning

This commit is contained in:
Takeshi KOMIYA 2018-01-08 20:19:36 +09:00
commit 326d7e64ce
328 changed files with 3045 additions and 1905 deletions

View File

@ -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
@ -39,7 +32,7 @@ test_script:
if (-not $test_ignore) { $test_ignore = '' }
$tests = $env:TEST
if (-not $tests) { $tests = '' }
& "C:\Python$($env:PYTHON)\python.exe" run.py $test_ignore.Split(' ') --junitxml .junit.xml $tests.Split(' ')
& "C:\Python$($env:PYTHON)\python.exe" -m pytest $test_ignore.Split(' ') --junitxml .junit.xml $tests.Split(' ')
Pop-Location
if ($LastExitCode -eq 1) { Write-Host "Test Failures Occurred, leaving for test result parsing" }
elseif ($LastExitCode -ne 0) { Write-Host "Other Error Occurred, aborting"; exit $LastExitCode }

View File

@ -6,4 +6,6 @@ jobs:
working_directory: /sphinx
steps:
- checkout
- run: /python3.4/bin/pip install -U pip setuptools
- run: /python3.4/bin/pip install -U .[test,websupport]
- run: make test PYTHON=/python3.4/bin/python

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ TAGS
.tox
.venv
.coverage
htmlcov
.DS_Store
sphinx/pycode/Grammar*pickle
distribute-*

View File

@ -2,46 +2,48 @@ language: python
sudo: false
dist: trusty
cache: pip
python:
- "pypy-5.4.1"
- "3.6"
- "3.5"
- "3.4"
- "2.7"
- "nightly"
env:
global:
- TEST='-v --durations 25'
- PYTHONFAULTHANDLER=x
- PYTHONWARNINGS=all
- SKIP_LATEX_BUILD=1
matrix:
- DOCUTILS=0.13.1
- DOCUTILS=0.14
matrix:
exclude:
- python: "3.4"
env: DOCUTILS=0.13.1
- python: "3.5"
env: DOCUTILS=0.13.1
- python: "3.6"
env: DOCUTILS=0.13.1
- python: nightly
env: DOCUTILS=0.13.1
- python: "pypy-5.4.1"
env: DOCUTILS=0.13.1
include:
- python: 'pypy'
env: TOXENV=pypy
- python: '2.7'
env:
- TOXENV=du13
- PYTEST_ADDOPTS = --cov sphinx --cov-append --cov-config setup.cfg
- python: '3.4'
env: TOXENV=py34
- python: '3.5'
env: TOXENV=py35
- python: '3.6'
env:
- TOXENV=py36
- PYTEST_ADDOPTS = --cov sphinx --cov-append --cov-config setup.cfg
- python: 'nightly'
env: TOXENV=py37
- python: '3.6'
env: TOXENV=docs
- python: '3.6'
env: TOXENV=mypy
- python: '2.7'
env: TOXENV=flake8
addons:
apt:
packages:
- graphviz
- imagemagick
install:
- pip install -U pip setuptools
- pip install docutils==$DOCUTILS
- pip install .[test,websupport]
- pip install flake8
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then python3.6 -m pip install mypy typed-ast; fi
- pip install -U tox codecov
script:
- flake8
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make type-check test-async; fi
- if [[ $TRAVIS_PYTHON_VERSION != '3.6' ]]; then make test; fi
- tox -- -v
after_success:
- codecov

31
CHANGES
View File

@ -13,6 +13,7 @@ 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.
@ -23,6 +24,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
--------------
@ -51,7 +58,13 @@ Features added
* HTML themes can set up default sidebars through ``theme.conf``
* #3160: html: Use ``<kdb>`` to represent ``:kbd:`` role
* #4212: autosummary: catch all exceptions when importing modules
* #4166: Add :confval:`math_numfig` for equation numbering by section (refs:
#3991, #4080). Thanks to Oliver Jahn.
* #4311: Let LaTeX obey :confval:`numfig_secnum_depth` for figures, tables, and
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
Features removed
----------------
@ -92,6 +105,14 @@ Bugs fixed
* #4094: C++, allow empty template argument lists.
* C++, also hyperlink types in the name of declarations with qualified names.
* C++, do not add index entries for declarations inside concepts.
* C++, support the template disambiguator for dependent names.
* #4314: For PDF 'howto' documents, numbering of code-blocks differs from the
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
Testing
--------
@ -117,10 +138,12 @@ Features added
* ``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)
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
@ -133,6 +156,12 @@ Bugs fixed
* #4279: Sphinx crashes with pickling error when run with multiple processes and
remote image
* #1421: Respect the quiet flag in sphinx-quickstart
* #4281: Race conditions when creating output directory
* #4315: For PDF 'howto' documents, ``latex_toplevel_sectioning='part'`` generates
``\chapter`` commands
* #4214: Two todolist directives break sphinx-1.6.5
* Fix links to external option docs with intersphinx (refs: #3769)
* #4091: Private members not documented without :undoc-members:
Testing
--------

View File

@ -33,10 +33,10 @@ Bug Reports and Feature Requests
If you have encountered a problem with Sphinx or have an idea for a new
feature, please submit it to the `issue tracker`_ on GitHub or discuss it
on the sphinx-dev mailing list.
on the `sphinx-dev`_ mailing list.
For bug reports, please include the output produced during the build process
and also the log file Sphinx creates after it encounters an un-handled
and also the log file Sphinx creates after it encounters an unhandled
exception. The location of this file should be shown towards the end of the
error message.
@ -45,6 +45,7 @@ issue. If possible, try to create a minimal project that produces the error
and post that instead.
.. _`issue tracker`: https://github.com/sphinx-doc/sphinx/issues
.. _`sphinx-dev`: mailto:sphinx-dev@googlegroups.com
Contributing to Sphinx
@ -58,7 +59,7 @@ of the core developers before it is merged into the main repository.
#. Check for open issues or open a fresh issue to start a discussion around a
feature idea or a bug.
#. If you feel uncomfortable or uncertain about an issue or your changes, feel
free to email sphinx-dev@googlegroups.com.
free to email the *sphinx-dev* mailing list.
#. Fork `the repository`_ on GitHub to start making your changes to the
**master** branch for next major version, or **stable** branch for next
minor version.
@ -98,10 +99,14 @@ These are the basic steps needed to start developing on Sphinx.
For new features or other substantial changes that should wait until the
next major release, use the ``master`` branch.
#. Optional: setup a virtual environment. ::
#. Setup a virtual environment.
virtualenv ~/sphinxenv
. ~/sphinxenv/bin/activate
This is not necessary for unit testing, thanks to ``tox``, but it is
necessary if you wish to run ``sphinx-build`` locally or run unit tests
without the help of ``tox``. ::
virtualenv ~/.venv
. ~/.venv/bin/activate
pip install -e .
#. Create a new working branch. Choose any name you like. ::
@ -112,44 +117,53 @@ These are the basic steps needed to start developing on Sphinx.
For tips on working with the code, see the `Coding Guide`_.
#. Test, test, test. Possible steps:
#. Test, test, test.
* Run the unit tests::
Testing is best done through ``tox``, which provides a number of targets and
allows testing against multiple different Python environments:
pip install .[test,websupport]
make test
* To list all possible targets::
* Again, it's useful to turn on deprecation warnings on so they're shown in
the test output::
tox -av
PYTHONWARNINGS=all make test
* To run unit tests for a specific Python version, such as 3.6::
* Arguments to pytest can be passed via tox, e.g. in order to run a
tox -e py36
* To run unit tests for a specific Python version and turn on deprecation
warnings on so they're shown in the test output::
PYTHONWARNINGS=all tox -e py36
* To run code style and type checks::
tox -e mypy
tox -e flake8
* Arguments to ``pytest`` can be passed via ``tox``, e.g. in order to run a
particular test::
tox -e py27 tests/test_module.py::test_new_feature
tox -e py36 tests/test_module.py::test_new_feature
* Build the documentation and check the output for different builders::
* To build the documentation::
make docs target="clean html latexpdf"
tox -e docs
* Run code style checks and type checks (type checks require mypy)::
* To build the documentation in multiple formats::
make style-check
make type-check
tox -e docs -- -b html,latexpdf
* Run the unit tests under different Python environments using
:program:`tox`::
You can also test by installing dependencies in your local environment. ::
pip install tox
tox -v
pip install .[test]
* Add a new unit test in the ``tests`` directory if you can.
New unit tests should be included in the ``tests`` directory where
necessary:
* For bug fixes, first add a test that fails without your changes and passes
after they are applied.
* Tests that need a sphinx-build run should be integrated in one of the
* Tests that need a ``sphinx-build`` run should be integrated in one of the
existing test modules if possible. New tests that to ``@with_app`` and
then ``build_all`` for a few assertions are not good since *the test suite
should not take more than a minute to run*.
@ -266,7 +280,7 @@ Debugging Tips
code by running the command ``make clean`` or using the
:option:`sphinx-build -E` option.
* Use the :option:`sphinx-build -P` option to run Pdb on exceptions.
* Use the :option:`sphinx-build -P` option to run ``pdb`` on exceptions.
* Use ``node.pformat()`` and ``node.asdom().toxml()`` to generate a printable
representation of the document structure.
@ -303,14 +317,17 @@ There are a couple reasons that code in Sphinx might be deprecated:
no longer needs to support the older version of Python that doesn't include
the library, the library will be deprecated in Sphinx.
As the :ref:`deprecation-policy` describes,
the first release of Sphinx that deprecates a feature (``A.B``) should raise a
``RemovedInSphinxXXWarning`` (where XX is the Sphinx version where the feature
will be removed) when the deprecated feature is invoked. Assuming we have good
test coverage, these warnings are converted to errors when running the test
suite with warnings enabled: ``python -Wall tests/run.py``. Thus, when adding
a ``RemovedInSphinxXXWarning`` you need to eliminate or silence any warnings
generated when running the tests.
As the :ref:`deprecation-policy` describes, the first release of Sphinx that
deprecates a feature (``A.B``) should raise a ``RemovedInSphinxXXWarning``
(where ``XX`` is the Sphinx version where the feature will be removed) when the
deprecated feature is invoked. Assuming we have good test coverage, these
warnings are converted to errors when running the test suite with warnings
enabled::
pytest -Wall
Thus, when adding a ``RemovedInSphinxXXWarning`` you need to eliminate or
silence any warnings generated when running the tests.
.. _deprecation-policy:

View File

@ -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/
@ -141,6 +141,7 @@ Documentation using the nature theme
Documentation using another builtin theme
-----------------------------------------
* Arcade: http://arcade.academy/ (sphinx_rtd_theme)
* Breathe: https://breathe.readthedocs.io/ (haiku)
* MPipe: https://vmlaker.github.io/mpipe/ (sphinx13)
* NLTK: http://www.nltk.org/ (agogo)
@ -258,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/

View File

@ -1,7 +1,7 @@
License for Sphinx
==================
Copyright (c) 2007-2017 by the Sphinx team (see AUTHORS file).
Copyright (c) 2007-2018 by the Sphinx team (see AUTHORS file).
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -69,15 +69,15 @@ reindent:
.PHONY: test
test:
@cd tests; $(PYTHON) run.py --ignore py35 -v $(TEST)
@$(PYTHON) -m pytest -v $(TEST)
.PHONY: test-async
test-async:
@cd tests; $(PYTHON) run.py -v $(TEST)
@echo "This target no longer does anything and will be removed imminently"
.PHONY: covertest
covertest:
@cd tests; $(PYTHON) run.py -v --cov=sphinx --junitxml=.junit.xml $(TEST)
@$(PYTHON) -m pytest -v --cov=sphinx --junitxml=.junit.xml $(TEST)
.PHONY: build
build:

View File

@ -1,45 +1,106 @@
========
Sphinx
========
.. image:: https://img.shields.io/pypi/v/sphinx.svg
:target: https://pypi.python.org/pypi/Sphinx
:alt: Package on PyPi
.. image:: https://readthedocs.org/projects/sphinx/badge/
:target: http://www.sphinx-doc.org/
:alt: Documentation Status
.. image:: https://travis-ci.org/sphinx-doc/sphinx.svg?branch=master
:target: https://travis-ci.org/sphinx-doc/sphinx
:alt: Build Status (Travis CI)
=================
README for Sphinx
=================
.. image:: https://ci.appveyor.com/api/projects/status/github/sphinx-doc/sphinx?branch=master&svg=true
:target: https://ci.appveyor.com/project/sphinxdoc/sphinx
:alt: Build Status (AppVeyor)
This is the Sphinx documentation generator, see http://www.sphinx-doc.org/.
.. image:: https://circleci.com/gh/sphinx-doc/sphinx.svg?style=shield
:target: https://circleci.com/gh/sphinx-doc/sphinx
:alt: Build Status (CircleCI)
.. image:: https://codecov.io/gh/sphinx-doc/sphinx/branch/master/graph/badge.svg
:target: https://codecov.io/gh/sphinx-doc/sphinx
:alt: Code Coverage Status (Codecov)
Installing
==========
Sphinx is a tool that makes it easy to create intelligent and beautiful
documentation for Python projects (or other documents consisting of multiple
reStructuredText sources), written by Georg Brandl. It was originally created
for the new Python documentation, and has excellent facilities for Python
project documentation, but C/C++ is supported as well, and more languages are
planned.
Install from PyPI to use stable version::
Sphinx uses reStructuredText as its markup language, and many of its strengths
come from the power and straightforwardness of reStructuredText and its parsing
and translating suite, the Docutils.
Among its features are the following:
* Output formats: HTML (including derivative formats such as HTML Help, Epub
and Qt Help), plain text, manual pages and LaTeX or direct PDF output
using rst2pdf
* Extensive cross-references: semantic markup and automatic links
for functions, classes, glossary terms and similar pieces of information
* Hierarchical structure: easy definition of a document tree, with automatic
links to siblings, parents and children
* Automatic indices: general index as well as a module index
* Code handling: automatic highlighting using the Pygments highlighter
* Flexible HTML output using the Jinja 2 templating engine
* Various extensions are available, e.g. for automatic testing of snippets
and inclusion of appropriately formatted docstrings
* Setuptools integration
For more information, refer to the `the documentation`__.
.. __: http://www.sphinx-doc.org/
Installation
============
Sphinx is published on `PyPI`__ and can be installed from there::
pip install -U sphinx
Install from PyPI to use beta version::
We also publish beta releases::
pip install -U --pre sphinx
Install from newest dev version in stable branch::
If you wish to install `Sphinx` for development purposes, refer to `the
contributors guide`__.
pip install git+https://github.com/sphinx-doc/sphinx@stable
__ https://pypi.python.org/pypi/Sphinx
__ CONTRIBUTING.rst
Install from newest dev version in master branch::
Documentation
=============
pip install git+https://github.com/sphinx-doc/sphinx
Documentation is available from `sphinx-doc.org`__.
Install from cloned source::
__ http://www.sphinx-doc.org/
pip install .
Testing
=======
Install from cloned source as editable::
Continuous testing is provided by `Travis`__ (for unit tests and style checks
on Linux), `AppVeyor`__ (for unit tests on Windows), and `CircleCI`__ (for
large processes like TeX compilation).
pip install -e .
For information on running tests locally, refer to `the contributors guide`__.
__ https://travis-ci.org/sphinx-doc/sphinx
__ https://ci.appveyor.com/project/sphinxdoc/sphinx
__ https://circleci.com/gh/sphinx-doc/sphinx
__ CONTRIBUTING.rst
Contributing
============
Refer to `the contributors guide`__.
__ CONTRIBUTING.rst
Release signatures
==================
@ -48,37 +109,3 @@ Releases are signed with following keys:
* `498D6B9E <https://pgp.mit.edu/pks/lookup?op=vindex&search=0x102C2C17498D6B9E>`_
* `5EBA0E07 <https://pgp.mit.edu/pks/lookup?op=vindex&search=0x1425F8CE5EBA0E07>`_
Reading the docs
================
You can read them online at <http://www.sphinx-doc.org/>.
Or, after installing::
cd doc
make html
Then, direct your browser to ``_build/html/index.html``.
Testing
=======
To run the tests with the interpreter available as ``python``, use::
make test
If you want to use a different interpreter, e.g. ``python3``, use::
PYTHON=python3 make test
Continuous testing runs on travis: https://travis-ci.org/sphinx-doc/sphinx
Contributing
============
See `CONTRIBUTING.rst`__
.. __: CONTRIBUTING.rst

View File

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

View File

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

View File

@ -4,7 +4,7 @@
Sphinx layout template for the sphinxdoc theme.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{%- extends "basic/layout.html" %}

View File

@ -4,7 +4,7 @@
*
* Sphinx stylesheet -- sphinx13 theme.
*
* :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@ -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 {

View File

@ -15,7 +15,7 @@ templates_path = ['_templates']
exclude_patterns = ['_build']
project = 'Sphinx'
copyright = '2007-2017, Georg Brandl and the Sphinx team'
copyright = '2007-2018, Georg Brandl and the Sphinx team'
version = sphinx.__display_version__
release = version
show_authors = True

View File

@ -138,12 +138,10 @@ General configuration
- ``'library/xml.rst'`` -- ignores the ``library/xml.rst`` file (replaces
entry in :confval:`unused_docs`)
- ``'library/xml'`` -- ignores the ``library/xml`` directory (replaces entry
in :confval:`exclude_trees`)
- ``'library/xml'`` -- ignores the ``library/xml`` directory
- ``'library/xml*'`` -- ignores all files and directories starting with
``library/xml``
- ``'**/.svn'`` -- ignores all ``.svn`` directories (replaces entry in
:confval:`exclude_dirnames`)
- ``'**/.svn'`` -- ignores all ``.svn`` directories
:confval:`exclude_patterns` is also consulted when looking for static files
in :confval:`html_static_path` and :confval:`html_extra_path`.
@ -315,8 +313,8 @@ General configuration
.. confval:: numfig
If true, figures, tables and code-blocks are automatically numbered if they
have a caption. At same time, the `numref` role is enabled. For now, it
works only with the HTML builder and LaTeX builder. Default is ``False``.
have a caption. The :rst:role:`numref` role is enabled.
Obeyed so far only by HTML and LaTeX builders. Default is ``False``.
.. note::
@ -339,13 +337,23 @@ General configuration
.. confval:: numfig_secnum_depth
The scope of figure numbers, that is, the numfig feature numbers figures
in which scope. ``0`` means "whole document". ``1`` means "in a section".
Sphinx numbers like x.1, x.2, x.3... ``2`` means "in a subsection". Sphinx
numbers like x.x.1, x.x.2, x.x.3..., and so on. Default is ``1``.
- if set to ``0``, figures, tables and code-blocks are continuously numbered
starting at ``1``.
- if ``1`` (default) numbers will be ``x.1``, ``x.2``, ... with ``x``
the section number (top level sectioning; no ``x.`` if no section).
This naturally applies only if section numbering has been activated via
the ``:numbered:`` option of the :rst:dir:`toctree` directive.
- ``2`` means that numbers will be ``x.y.1``, ``x.y.2``, ... if located in
a sub-section (but still ``x.1``, ``x.2``, ... if located directly under a
section and ``1``, ``2``, ... if not in any top level section.)
- etc...
.. versionadded:: 1.3
.. versionchanged:: 1.7
The LaTeX builder obeys this setting (if :confval:`numfig` is set to
``True``).
.. confval:: tls_verify
If true, Sphinx verifies server certifications. Default is ``True``.
@ -1450,10 +1458,6 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
a chapter, but can be confusing because it mixes entries of different
depth in one list. The default value is ``True``.
.. note::
``epub3`` builder ignores ``epub_tocdup`` option(always ``False``)
.. confval:: epub_tocscope
This setting control the scope of the epub table of contents. The setting
@ -1615,10 +1619,15 @@ These options influence LaTeX output. See further :doc:`latex`.
.. confval:: latex_toplevel_sectioning
This value determines the topmost sectioning unit. It should be chosen from
``part``, ``chapter`` or ``section``. The default is ``None``; the topmost
sectioning unit is switched by documentclass. ``section`` is used if
``'part'``, ``'chapter'`` or ``'section'``. The default is ``None``;
the topmost
sectioning unit is switched by documentclass: ``section`` is used if
documentclass will be ``howto``, otherwise ``chapter`` will be used.
Note that if LaTeX uses ``\part`` command, then the numbering of sectioning
units one level deep gets off-sync with HTML numbering, because LaTeX
numbers continuously ``\chapter`` (or ``\section`` for ``howto``.)
.. versionadded:: 1.4
.. confval:: latex_appendices

View File

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

View File

@ -103,8 +103,10 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
will document all non-private member functions and properties (that is,
those whose name doesn't start with ``_``).
For modules, ``__all__`` will be respected when looking for members; the
order of the members will also be the order in ``__all__``.
For modules, ``__all__`` will be respected when looking for members unless
you give the ``ignore-module-all`` flag option. Without
``ignore-module-all``, the order of the members will also be the order in
``__all__``.
You can also give an explicit list of members; only these will then be
documented::
@ -339,7 +341,7 @@ There are also new config values that you can set:
This value is a list of autodoc directive flags that should be automatically
applied to all autodoc directives. The supported flags are ``'members'``,
``'undoc-members'``, ``'private-members'``, ``'special-members'``,
``'inherited-members'`` and ``'show-inheritance'``.
``'inherited-members'``, ``'show-inheritance'`` and ``'ignore-module-all'``.
If you set one of these flags in this config value, you can use a negated
form, :samp:`'no-{flag}'`, in an autodoc directive, to disable it once.

View File

@ -44,6 +44,15 @@ or use Python raw strings (``r"raw"``).
Example: ``'Eq.{number}'`` is rendered as ``Eq.10``
.. confval:: math_numfig
If ``True``, displayed math equations are numbered across pages when
:confval:`numfig` is enabled. The :confval:`numfig_secnum_depth` setting
is respected. The :rst:role:`eq`, not :rst:role:`numref`, role
must be used to reference equation numbers. Default is ``True``.
.. versionadded:: 1.7
:mod:`.mathbase` defines these new markup elements:
.. rst:role:: math
@ -102,8 +111,7 @@ or use Python raw strings (``r"raw"``).
.. rst:role:: eq
Role for cross-referencing equations via their label. This currently works
only within the same document. Example::
Role for cross-referencing equations via their label. Example::
.. math:: e^{i\pi} + 1 = 0
:label: euler

View File

@ -6,7 +6,7 @@ repository. It is open for anyone who wants to maintain an extension
publicly; just send a short message asking for write permissions.
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

View File

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

View File

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

View File

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

View File

@ -91,7 +91,7 @@ Options
Interpret paths recursively according to PEP-0420.
.. option:: -M
.. option:: -M, --module-first
Put module documentation before submodule documentation.
@ -118,6 +118,14 @@ These options are used when :option:`--full` is specified:
Sets the project release to put in generated files (see :confval:`release`).
Environment
-----------
.. envvar:: SPHINX_APIDOC_OPTIONS
A comma-separated list of option to append to generated ``automodule``
directives. Defaults to ``members,undoc-members,show-inheritance``.
See also
--------

View File

@ -63,7 +63,7 @@ Cross-referencing anything
by :rst:role:`doc`, :rst:role:`ref` or :rst:role:`option`.
Custom objects added to the standard domain by extensions (see
:meth:`.add_object_type`) are also searched.
:meth:`Sphinx.add_object_type`) are also searched.
* Then, it looks for objects (targets) in all loaded domains. It is up to
the domains how specific a match must be. For example, in the Python
@ -227,15 +227,15 @@ Cross-referencing figures by figure number
reST labels are used. When you use this role, it will insert a reference to
the figure with link text by its figure number like "Fig. 1.1".
If an explicit link text is given (like usual: ``:numref:`Image of Sphinx (Fig.
%s) <my-figure>```), the link caption will be the title of the reference.
As a special character, `%s` and `{number}` will be replaced to figure
number. `{name}` will be replaced to figure caption.
If no explicit link text is given, the value of :confval:`numfig_format` is
used to default value of link text.
If an explicit link text is given (as usual: ``:numref:`Image of Sphinx (Fig.
%s) <my-figure>```), the link caption will serve as title of the reference.
As placeholders, `%s` and `{number}` get replaced by the figure
number and `{name}` by the figure caption.
If no explicit link text is given, the :confval:`numfig_format` setting is
used as fall-back default.
If :confval:`numfig` is ``False``, figures are not numbered.
so this role inserts not a reference but labels or link text.
If :confval:`numfig` is ``False``, figures are not numbered,
so this role inserts not a reference but the label or the link text.
Cross-referencing other items of interest
-----------------------------------------

View File

@ -1,11 +1,20 @@
[metadata]
license_file = LICENSE
[egg_info]
tag_build = .dev
tag_date = true
[bdist_wheel]
universal = 1
[aliases]
release = egg_info -Db ''
upload = upload --sign --identity=36580288
[build_sphinx]
warning-is-error = 1
[extract_messages]
mapping_file = babel.cfg
output_file = sphinx/locale/sphinx.pot
@ -20,12 +29,6 @@ output_dir = sphinx/locale/
domain = sphinx
directory = sphinx/locale/
[bdist_wheel]
universal = 1
[metadata]
license_file = LICENSE
[flake8]
max-line-length = 95
ignore = E116,E241,E251,E741
@ -41,5 +44,20 @@ incremental = True
check_untyped_defs = True
warn_unused_ignores = True
[build_sphinx]
warning-is-error = 1
[tool:pytest]
filterwarnings =
ignore::DeprecationWarning:docutils.io
[coverage:run]
branch = True
source = sphinx
[coverage:report]
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover
# Don't complain if tests don't hit defensive assertion code:
raise NotImplementedError
# Don't complain if non-runnable code isn't run:
if __name__ == .__main__.:
ignore_errors = True

View File

@ -8,34 +8,8 @@ from distutils.cmd import Command
import sphinx
long_desc = '''
Sphinx is a tool that makes it easy to create intelligent and beautiful
documentation for Python projects (or other documents consisting of multiple
reStructuredText sources), written by Georg Brandl. It was originally created
for the new Python documentation, and has excellent facilities for Python
project documentation, but C/C++ is supported as well, and more languages are
planned.
Sphinx uses reStructuredText as its markup language, and many of its strengths
come from the power and straightforwardness of reStructuredText and its parsing
and translating suite, the Docutils.
Among its features are the following:
* Output formats: HTML (including derivative formats such as HTML Help, Epub
and Qt Help), plain text, manual pages and LaTeX or direct PDF output
using rst2pdf
* Extensive cross-references: semantic markup and automatic links
for functions, classes, glossary terms and similar pieces of information
* Hierarchical structure: easy definition of a document tree, with automatic
links to siblings, parents and children
* Automatic indices: general index as well as a module index
* Code handling: automatic highlighting using the Pygments highlighter
* Flexible HTML output using the Jinja 2 templating engine
* Various extensions are available, e.g. for automatic testing of snippets
and inclusion of appropriately formatted docstrings
* Setuptools integration
'''
with open('README.rst') as f:
long_desc = f.read()
if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 4):
print('ERROR: Sphinx requires at least Python 2.7 or 3.4 to run.')
@ -72,6 +46,7 @@ extras_require = {
'pytest',
'pytest-cov',
'html5lib',
'flake8',
],
'test:python_version<"3"': [
'enum34',

View File

@ -5,7 +5,7 @@
The Sphinx documentation toolchain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The Sphinx documentation toolchain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys

View File

@ -5,7 +5,7 @@
Additional docutils nodes.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
This file has moved to :py:mod:`sphinx.ext.apidoc`.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -7,7 +7,7 @@
Gracefully adapted from the TextPress system by Armin.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function
@ -19,7 +19,7 @@ import posixpath
from os import path
from collections import deque
from six import iteritems
from six import iteritems, itervalues
from six.moves import cStringIO
from docutils import nodes
@ -33,14 +33,13 @@ from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment import BuildEnvironment
from sphinx.events import EventManager
from sphinx.extension import verify_required_extensions
from sphinx.io import SphinxStandaloneReader
from sphinx.locale import __
from sphinx.registry import SphinxComponentRegistry
from sphinx.util import pycompat # noqa: F401
from sphinx.util import import_object
from sphinx.util import logging
from sphinx.util.tags import Tags
from sphinx.util.osutil import ENOENT
from sphinx.util.osutil import ENOENT, ensuredir
from sphinx.util.console import bold # type: ignore
from sphinx.util.docutils import is_html5_writer_available, directive_helper
from sphinx.util.i18n import find_catalog_source_files
@ -54,7 +53,9 @@ if False:
from sphinx.domains import Domain, Index # NOQA
from sphinx.environment.collectors import EnvironmentCollector # NOQA
from sphinx.extension import Extension # NOQA
from sphinx.roles import XRefRole # NOQA
from sphinx.theming import Theme # NOQA
from sphinx.util.typing import RoleFunction # NOQA
builtin_extensions = (
'sphinx.builders.applehelp',
@ -120,7 +121,6 @@ class Sphinx(object):
self.env = None # type: BuildEnvironment
self.registry = SphinxComponentRegistry()
self.enumerable_nodes = {} # type: Dict[nodes.Node, Tuple[unicode, Callable]] # NOQA
self.post_transforms = [] # type: List[Transform]
self.html_themes = {} # type: Dict[unicode, unicode]
self.srcdir = srcdir
@ -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...')
os.makedirs(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']
@ -444,7 +444,6 @@ class Sphinx(object):
def add_builder(self, builder):
# type: (Type[Builder]) -> None
logger.debug('[app] adding builder: %r', builder)
self.registry.add_builder(builder)
def add_config_value(self, name, default, rebuild, types=()):
@ -464,7 +463,6 @@ class Sphinx(object):
def set_translator(self, name, translator_class):
# type: (unicode, Type[nodes.NodeVisitor]) -> None
logger.info(bold(__('Change of translator for the %s builder.') % name))
self.registry.add_translator(name, translator_class)
def add_node(self, node, **kwds):
@ -553,39 +551,30 @@ class Sphinx(object):
def add_domain(self, domain):
# type: (Type[Domain]) -> None
logger.debug('[app] adding domain: %r', domain)
self.registry.add_domain(domain)
def override_domain(self, domain):
# type: (Type[Domain]) -> None
logger.debug('[app] overriding domain: %r', domain)
self.registry.override_domain(domain)
def add_directive_to_domain(self, domain, name, obj,
has_content=None, argument_spec=None, **option_spec):
# type: (unicode, unicode, Any, bool, Any, Any) -> None
logger.debug('[app] adding directive to domain: %r',
(domain, name, obj, has_content, argument_spec, option_spec))
self.registry.add_directive_to_domain(domain, name, obj,
has_content, argument_spec, **option_spec)
def add_role_to_domain(self, domain, name, role):
# type: (unicode, unicode, Any) -> None
logger.debug('[app] adding role to domain: %r', (domain, name, role))
# type: (unicode, unicode, Union[RoleFunction, XRefRole]) -> None
self.registry.add_role_to_domain(domain, name, role)
def add_index_to_domain(self, domain, index):
# type: (unicode, Type[Index]) -> None
logger.debug('[app] adding index to domain: %r', (domain, index))
self.registry.add_index_to_domain(domain, index)
def add_object_type(self, directivename, rolename, indextemplate='',
parse_node=None, ref_nodeclass=None, objname='',
doc_field_types=[]):
# type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None
logger.debug('[app] adding object type: %r',
(directivename, rolename, indextemplate, parse_node,
ref_nodeclass, objname, doc_field_types))
self.registry.add_object_type(directivename, rolename, indextemplate, parse_node,
ref_nodeclass, objname, doc_field_types)
@ -602,21 +591,16 @@ class Sphinx(object):
def add_crossref_type(self, directivename, rolename, indextemplate='',
ref_nodeclass=None, objname=''):
# type: (unicode, unicode, unicode, nodes.Node, unicode) -> None
logger.debug('[app] adding crossref type: %r',
(directivename, rolename, indextemplate, ref_nodeclass,
objname))
self.registry.add_crossref_type(directivename, rolename,
indextemplate, ref_nodeclass, objname)
def add_transform(self, transform):
# type: (Type[Transform]) -> None
logger.debug('[app] adding transform: %r', transform)
SphinxStandaloneReader.transforms.append(transform)
self.registry.add_transform(transform)
def add_post_transform(self, transform):
# type: (Type[Transform]) -> None
logger.debug('[app] adding post transform: %r', transform)
self.post_transforms.append(transform)
self.registry.add_post_transform(transform)
def add_javascript(self, filename):
# type: (unicode) -> None
@ -658,15 +642,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
@ -677,7 +660,6 @@ class Sphinx(object):
def add_source_parser(self, suffix, parser):
# type: (unicode, Parser) -> None
logger.debug('[app] adding search source_parser: %r, %r', suffix, parser)
self.registry.add_source_parser(suffix, parser)
def add_env_collector(self, collector):
@ -690,6 +672,34 @@ class Sphinx(object):
logger.debug('[app] adding HTML theme: %r, %r', name, theme_path)
self.html_themes[name] = theme_path
# ---- other methods -------------------------------------------------
def is_parallel_allowed(self, typ):
# type: (unicode) -> bool
"""Check parallel processing is allowed or not.
``typ`` is a type of processing; ``'read'`` or ``'write'``.
"""
if typ == 'read':
attrname = 'parallel_read_safe'
elif typ == 'write':
attrname = 'parallel_write_safe'
else:
raise ValueError('parallel type %s is not supported' % typ)
for ext in itervalues(self.extensions):
allowed = getattr(ext, attrname, None)
if allowed is None:
logger.warning(__("the %s extension does not declare if it is safe "
"for parallel %sing, assuming it isn't - please "
"ask the extension author to check and make it "
"explicit"), ext.name, typ)
logger.warning('doing serial %s', typ)
return False
elif not allowed:
return False
return True
class TemplateBridge(object):
"""

View File

@ -5,11 +5,10 @@
Builder superclass for all builders.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import os
from os import path
import warnings
@ -18,13 +17,12 @@ try:
except ImportError:
multiprocessing = None
from six import itervalues
from docutils import nodes
from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.util import i18n, path_stabilize, logging, status_iterator
from sphinx.util.osutil import SEP, relative_uri
from sphinx.util.osutil import SEP, ensuredir, relative_uri
from sphinx.util.i18n import find_catalog
from sphinx.util.console import bold # type: ignore
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
@ -79,8 +77,7 @@ class Builder(object):
self.confdir = app.confdir
self.outdir = app.outdir
self.doctreedir = app.doctreedir
if not path.isdir(self.doctreedir):
os.makedirs(self.doctreedir)
ensuredir(self.doctreedir)
self.app = app # type: Sphinx
self.env = None # type: BuildEnvironment
@ -373,15 +370,10 @@ class Builder(object):
docnames = set(docnames) & self.env.found_docs
# determine if we can write in parallel
self.parallel_ok = False
if parallel_available and self.app.parallel > 1 and self.allow_parallel:
self.parallel_ok = True
for extension in itervalues(self.app.extensions):
if not extension.parallel_write_safe:
logger.warning('the %s extension is not safe for parallel '
'writing, doing serial write', extension.name)
self.parallel_ok = False
break
self.parallel_ok = self.app.is_parallel_allowed('write')
else:
self.parallel_ok = False
# create a task executor to use for misc. "finish-up" tasks
# if self.parallel_ok:

View File

@ -5,7 +5,7 @@
Base class of epub2/epub3 builders.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Build Apple help books.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function

View File

@ -5,7 +5,7 @@
Changelog builder.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -7,7 +7,7 @@
.. _Devhelp: http://live.gnome.org/devhelp
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import absolute_import

View File

@ -5,7 +5,7 @@
The MessageCatalogBuilder class.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Several HTML builders.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -6,7 +6,7 @@
Build HTML help support files.
Parts adapted from Python's Doc/tools/prechm.py.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function

View File

@ -5,7 +5,7 @@
LaTeX builder.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The CheckExternalLinksBuilder class.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Manual pages builder.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Build input files for the Qt collection generator.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Texinfo builder.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Plain-text Sphinx builder.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Builder for the web support package.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Docutils-native XML and pseudo-XML builders.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,6 +5,6 @@
Modules for command line executables.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Build documentation from a provided source.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Quickly setup documentation source to work with Sphinx.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function
@ -36,7 +36,7 @@ from six.moves.urllib.parse import quote as urlquote
from docutils.utils import column_width
from sphinx import __display_version__, package_dir
from sphinx.util.osutil import make_filename
from sphinx.util.osutil import ensuredir, make_filename
from sphinx.util.console import ( # type: ignore
purple, bold, red, turquoise, nocolor, color_terminal
)
@ -79,13 +79,6 @@ DEFAULTS = {
PROMPT_PREFIX = '> '
def mkdir_p(dir):
# type: (unicode) -> None
if path.isdir(dir):
return
os.makedirs(dir)
# function to get input from terminal -- overridden by the test suite
def term_input(prompt):
# type: (unicode) -> unicode
@ -413,11 +406,11 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'")
if not path.isdir(d['path']):
mkdir_p(d['path'])
ensuredir(d['path'])
srcdir = d['sep'] and path.join(d['path'], 'source') or d['path']
mkdir_p(srcdir)
ensuredir(srcdir)
if d['sep']:
builddir = path.join(d['path'], 'build')
d['exclude_patterns'] = ''
@ -428,9 +421,9 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
'Thumbs.db', '.DS_Store',
])
d['exclude_patterns'] = ', '.join(exclude_patterns)
mkdir_p(builddir)
mkdir_p(path.join(srcdir, d['dot'] + 'templates'))
mkdir_p(path.join(srcdir, d['dot'] + 'static'))
ensuredir(builddir)
ensuredir(path.join(srcdir, d['dot'] + 'templates'))
ensuredir(path.join(srcdir, d['dot'] + 'static'))
def write_file(fpath, content, newline=None):
# type: (unicode, unicode, unicode) -> None

View File

@ -5,7 +5,7 @@
sphinx-build command-line handling.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function

View File

@ -5,11 +5,12 @@
Build configuration file handling.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
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}, " \
@ -155,6 +157,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

View File

@ -5,7 +5,7 @@
Sphinx deprecation classes and utilities.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Handlers for additional ReST directives.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -3,7 +3,7 @@
sphinx.directives.code
~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -3,7 +3,7 @@
sphinx.directives.other
~~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -3,7 +3,7 @@
sphinx.directives.patches
~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -6,7 +6,7 @@
Support for domains, which are groupings of description directives
and roles describing e.g. constructs of one programming language.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -141,7 +141,7 @@ class Domain(object):
#: domain label: longer, more descriptive (used in messages)
label = ''
#: type (usually directive) name -> ObjType instance
object_types = {} # type: Dict[unicode, Any]
object_types = {} # type: Dict[unicode, ObjType]
#: directive name -> directive class
directives = {} # type: Dict[unicode, Any]
#: role name -> role callable
@ -161,6 +161,17 @@ class Domain(object):
def __init__(self, env):
# type: (BuildEnvironment) -> None
self.env = env # type: BuildEnvironment
self._role_cache = {} # type: Dict[unicode, Callable]
self._directive_cache = {} # type: Dict[unicode, Callable]
self._role2type = {} # type: Dict[unicode, List[unicode]]
self._type2role = {} # type: Dict[unicode, unicode]
# convert class variables to instance one (to enhance through API)
self.object_types = dict(self.object_types)
self.directives = dict(self.directives)
self.roles = dict(self.roles)
self.indices = list(self.indices)
if self.name not in env.domaindata:
assert isinstance(self.initial_data, dict)
new_data = copy.deepcopy(self.initial_data)
@ -170,10 +181,6 @@ class Domain(object):
self.data = env.domaindata[self.name]
if self.data['version'] != self.data_version:
raise IOError('data of %r domain out of date' % self.label)
self._role_cache = {} # type: Dict[unicode, Callable]
self._directive_cache = {} # type: Dict[unicode, Callable]
self._role2type = {} # type: Dict[unicode, List[unicode]]
self._type2role = {} # type: Dict[unicode, unicode]
for name, obj in iteritems(self.object_types):
for rolename in obj.roles:
self._role2type.setdefault(rolename, []).append(name)
@ -181,6 +188,18 @@ class Domain(object):
self.objtypes_for_role = self._role2type.get # type: Callable[[unicode], List[unicode]] # NOQA
self.role_for_objtype = self._type2role.get # type: Callable[[unicode], unicode]
def add_object_type(self, name, objtype):
# type: (unicode, ObjType) -> None
"""Add an object type."""
self.object_types[name] = objtype
if objtype.roles:
self._type2role[name] = objtype.roles[0]
else:
self._type2role[name] = ''
for role in objtype.roles:
self._role2type.setdefault(role, []).append(name)
def role(self, name):
# type: (unicode) -> Callable
"""Return a role adapter function that always gives the registered

View File

@ -5,7 +5,7 @@
The C language domain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The C++ language domain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -1285,7 +1285,7 @@ class ASTTemplateParamType(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
@property
def isPack(self):
@ -1314,6 +1314,44 @@ class ASTTemplateParamType(ASTBase):
self.data.describe_signature(signode, mode, env, symbol)
class ASTTemplateParamConstrainedTypeWithInit(ASTBase):
def __init__(self, type, init):
# type: (Any, Any) -> None
assert type
self.type = type
self.init = init
@property
def name(self):
# type: () -> ASTNestedName
return self.type.name
def get_id(self, version, objectType=None, symbol=None):
# type: (int, unicode, Symbol) -> unicode
# this is not part of the normal name mangling in C++
assert version >= 2
if symbol:
# the anchor will be our parent
return symbol.parent.declaration.get_id(version, prefixed=False)
else:
return self.type.get_id(version)
def __unicode__(self):
# type: () -> unicode
res = text_type(self.type)
if self.init:
res += " = "
res += text_type(self.init)
return res
def describe_signature(self, signode, mode, env, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None
self.type.describe_signature(signode, mode, env, symbol)
if self.init:
signode += nodes.Text(" = ")
self.init.describe_signature(signode, mode, env, symbol)
class ASTTemplateParamTemplateType(ASTBase):
def __init__(self, nestedParams, data):
# type: (Any, Any) -> None
@ -1326,7 +1364,7 @@ class ASTTemplateParamTemplateType(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
def get_identifier(self):
# type: () -> unicode
@ -1363,16 +1401,16 @@ class ASTTemplateParamNonType(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
def get_identifier(self):
# type: () -> unicode
name = self.param.name
if name:
assert len(name.names) == 1
assert name.names[0].identifier
assert name.names[0].identOrOp
assert not name.names[0].templateArgs
return name.names[0].identifier
return name.names[0].identOrOp
else:
return None
@ -1456,7 +1494,7 @@ class ASTTemplateIntroductionParameter(ASTBase):
def name(self):
# type: () -> ASTNestedName
id = self.get_identifier()
return ASTNestedName([ASTNestedNameElement(id, None)], rooted=False)
return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
@property
def isPack(self):
@ -1612,8 +1650,8 @@ class ASTOperatorBuildIn(ASTBase):
else:
return u'operator' + self.op
def describe_signature(self, signode, mode, env, prefix, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol):
# type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None
_verify_description_mode(mode)
identifier = text_type(self)
if mode == 'lastIsName':
@ -1646,8 +1684,8 @@ class ASTOperatorType(ASTBase):
# type: () -> unicode
return text_type(self)
def describe_signature(self, signode, mode, env, prefix, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol):
# type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None
_verify_description_mode(mode)
identifier = text_type(self)
if mode == 'lastIsName':
@ -1676,8 +1714,8 @@ class ASTOperatorLiteral(ASTBase):
# type: () -> unicode
return u'operator""' + text_type(self.identifier)
def describe_signature(self, signode, mode, env, prefix, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
def describe_signature(self, signode, mode, env, prefix, templateArgs, symbol):
# type: (addnodes.desc_signature, unicode, Any, unicode, unicode, Symbol) -> None
_verify_description_mode(mode)
identifier = text_type(self)
if mode == 'lastIsName':
@ -1750,9 +1788,9 @@ class ASTTemplateArgs(ASTBase):
class ASTNestedNameElement(ASTBase):
def __init__(self, identifier, templateArgs):
def __init__(self, identOrOp, templateArgs):
# type: (Any, Any) -> None
self.identifier = identifier
self.identOrOp = identOrOp
self.templateArgs = templateArgs
def is_operator(self):
@ -1761,14 +1799,14 @@ class ASTNestedNameElement(ASTBase):
def get_id(self, version):
# type: (int) -> unicode
res = self.identifier.get_id(version)
res = self.identOrOp.get_id(version)
if self.templateArgs:
res += self.templateArgs.get_id(version)
return res
def __unicode__(self):
# type: () -> unicode
res = text_type(self.identifier)
res = text_type(self.identOrOp)
if self.templateArgs:
res += text_type(self.templateArgs)
return res
@ -1776,16 +1814,18 @@ class ASTNestedNameElement(ASTBase):
def describe_signature(self, signode, mode, env, prefix, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, unicode, Symbol) -> None
tArgs = text_type(self.templateArgs) if self.templateArgs is not None else ''
self.identifier.describe_signature(signode, mode, env, prefix, tArgs, symbol)
self.identOrOp.describe_signature(signode, mode, env, prefix, tArgs, symbol)
if self.templateArgs is not None:
self.templateArgs.describe_signature(signode, mode, env, symbol)
class ASTNestedName(ASTBase):
def __init__(self, names, rooted):
# type: (List[Any], bool) -> None
def __init__(self, names, templates, rooted):
# type: (List[Any], List[bool], bool) -> None
assert len(names) > 0
self.names = names
self.templates = templates
assert len(self.names) == len(self.templates)
self.rooted = rooted
@property
@ -1826,8 +1866,13 @@ class ASTNestedName(ASTBase):
res = [] # type: List[unicode]
if self.rooted:
res.append('')
for n in self.names:
res.append(text_type(n))
for i in range(len(self.names)):
n = self.names[i]
t = self.templates[i]
if t:
res.append("template " + text_type(n))
else:
res.append(text_type(n))
return '::'.join(res)
def describe_signature(self, signode, mode, env, symbol):
@ -1854,10 +1899,14 @@ class ASTNestedName(ASTBase):
prefix = '' # type: unicode
first = True
names = self.names[:-1] if mode == 'lastIsName' else self.names
for name in names:
for i in range(len(names)):
name = names[i]
template = self.templates[i]
if not first:
signode += nodes.Text('::')
prefix += '::'
if template:
signode += nodes.Text("template ")
first = False
if name != '':
if (name.templateArgs and # type: ignore
@ -1870,6 +1919,8 @@ class ASTNestedName(ASTBase):
if mode == 'lastIsName':
if len(self.names) > 1:
signode += addnodes.desc_addname('::', '::')
if self.templates[-1]:
signode += nodes.Text("template ")
self.names[-1].describe_signature(signode, mode, env, '', symbol)
else:
raise Exception('Unknown description mode: %s' % mode)
@ -3259,23 +3310,20 @@ class Symbol(object):
# type: () -> None
if not self.parent:
# parent == None means global scope, so declaration means a parent
assert not self.identifier
assert not self.identOrOp
assert not self.templateParams
assert not self.templateArgs
assert not self.declaration
assert not self.docname
else:
if not self.identifier:
# in case it's an operator
assert self.declaration
if self.declaration:
assert self.docname
def __init__(self, parent, identifier,
def __init__(self, parent, identOrOp,
templateParams, templateArgs, declaration, docname):
# type: (Any, Any, Any, Any, Any, unicode) -> None
self.parent = parent
self.identifier = identifier
self.identOrOp = identOrOp
self.templateParams = templateParams # template<templateParams>
self.templateArgs = templateArgs # identifier<templateArgs>
self.declaration = declaration
@ -3300,7 +3348,7 @@ class Symbol(object):
else:
decl = None
nne = ASTNestedNameElement(p.get_identifier(), None)
nn = ASTNestedName([nne], rooted=False)
nn = ASTNestedName([nne], [False], rooted=False)
self._add_symbols(nn, [], decl, docname)
# add symbols for function parameters, if any
if declaration is not None and declaration.function_params is not None:
@ -3314,8 +3362,8 @@ class Symbol(object):
decl = ASTDeclaration('functionParam', None, None, p)
assert not nn.rooted
assert len(nn.names) == 1
identifier = nn.names[0].identifier
Symbol(parent=self, identifier=identifier,
identOrOp = nn.names[0].identOrOp
Symbol(parent=self, identOrOp=identOrOp,
templateParams=None, templateArgs=None,
declaration=decl, docname=docname)
@ -3339,12 +3387,7 @@ class Symbol(object):
if sChild.declaration and sChild.docname == docname:
sChild.declaration = None
sChild.docname = None
# Just remove operators, because there is no identification if
# they got removed.
# Don't remove other symbols because they may be used in namespace
# directives.
if sChild.identifier or sChild.declaration:
newChildren.append(sChild)
newChildren.append(sChild)
self.children = newChildren
def get_all_symbols(self):
@ -3364,26 +3407,22 @@ class Symbol(object):
symbols.reverse()
key = []
for s in symbols:
if s.identifier:
nne = ASTNestedNameElement(s.identifier, s.templateArgs)
else:
assert s.declaration
nne = s.declaration.name.names[-1]
nne = ASTNestedNameElement(s.identOrOp, s.templateArgs)
key.append((nne, s.templateParams))
return key
def get_full_nested_name(self):
# type: () -> ASTNestedName
names = []
templates = []
for nne, templateParams in self.get_lookup_key():
names.append(nne)
return ASTNestedName(names, rooted=False)
templates.append(False)
return ASTNestedName(names, templates, rooted=False)
def _find_named_symbol(self, identifier, templateParams,
templateArgs, operator,
def _find_named_symbol(self, identOrOp, templateParams, templateArgs,
templateShorthand, matchSelf):
# type: (Any, Any, Any, Any, Any, bool) -> Symbol
assert (identifier is None) != (operator is None)
# type: (Any, Any, Any, Any, bool) -> Symbol
def isSpecialization():
# the names of the template parameters must be given exactly as args
@ -3411,17 +3450,8 @@ class Symbol(object):
templateArgs = None
def matches(s):
if s.identifier != identifier:
if s.identOrOp != identOrOp:
return False
if not s.identifier:
if not s.declaration:
return False
assert operator
name = s.declaration.name.names[-1]
if not name.is_operator():
return False
if text_type(name) != text_type(operator):
return False
if (s.templateParams is None) != (templateParams is None):
if templateParams is not None:
# we query with params, they must match params
@ -3462,10 +3492,7 @@ class Symbol(object):
names = nestedName.names
iTemplateDecl = 0
for name in names[:-1]:
# there shouldn't be anything inside an operator
# (other than template parameters, which are not added this way, right?)
assert not name.is_operator()
identifier = name.identifier
identOrOp = name.identOrOp
templateArgs = name.templateArgs
if templateArgs:
assert iTemplateDecl < len(templateDecls)
@ -3473,27 +3500,20 @@ class Symbol(object):
iTemplateDecl += 1
else:
templateParams = None
symbol = parentSymbol._find_named_symbol(identifier,
symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams,
templateArgs,
operator=None,
templateShorthand=False,
matchSelf=False)
if symbol is None:
symbol = Symbol(parent=parentSymbol, identifier=identifier,
symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs, declaration=None,
docname=None)
parentSymbol = symbol
name = names[-1]
if name.is_operator():
identifier = None
templateArgs = None
operator = name
else:
identifier = name.identifier
templateArgs = name.templateArgs
operator = None
identOrOp = name.identOrOp
templateArgs = name.templateArgs
if iTemplateDecl < len(templateDecls):
if iTemplateDecl + 1 != len(templateDecls):
print(text_type(templateDecls))
@ -3503,10 +3523,9 @@ class Symbol(object):
else:
assert iTemplateDecl == len(templateDecls)
templateParams = None
symbol = parentSymbol._find_named_symbol(identifier,
symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams,
templateArgs,
operator,
templateShorthand=False,
matchSelf=False)
if symbol:
@ -3523,7 +3542,7 @@ class Symbol(object):
return symbol
# It may simply be a function overload, so let's compare ids.
isRedeclaration = True
candSymbol = Symbol(parent=parentSymbol, identifier=identifier,
candSymbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs,
declaration=declaration,
@ -3543,7 +3562,7 @@ class Symbol(object):
candSymbol.isRedeclaration = True
raise _DuplicateSymbolError(symbol, declaration)
else:
symbol = Symbol(parent=parentSymbol, identifier=identifier,
symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs,
declaration=declaration,
@ -3554,22 +3573,9 @@ class Symbol(object):
# type: (Any, List[unicode], BuildEnvironment) -> None
assert other is not None
for otherChild in other.children:
if not otherChild.identifier:
if not otherChild.declaration:
print("Problem in symbol tree merging")
print("OtherChild.dump:")
print(otherChild.dump(0))
print("Other.dump:")
print(other.dump(0))
assert otherChild.declaration
operator = otherChild.declaration.name.names[-1]
assert operator.is_operator()
else:
operator = None
ourChild = self._find_named_symbol(otherChild.identifier,
ourChild = self._find_named_symbol(otherChild.identOrOp,
otherChild.templateParams,
otherChild.templateArgs,
operator,
templateShorthand=False,
matchSelf=False)
if ourChild is None:
@ -3614,12 +3620,12 @@ class Symbol(object):
templateDecls = []
return self._add_symbols(nestedName, templateDecls, declaration, docname)
def find_identifier(self, identifier, matchSelf):
def find_identifier(self, identOrOp, matchSelf):
# type: (Any, bool) -> Symbol
if matchSelf and self.identifier and self.identifier == identifier:
if matchSelf and self.identOrOp == identOrOp:
return self
for s in self.children:
if s.identifier and s.identifier == identifier:
if s.identOrOp == identOrOp:
return s
return None
@ -3627,16 +3633,10 @@ class Symbol(object):
# type: (List[Tuple[Any, Any]]) -> Symbol
s = self
for name, templateParams in key:
if name.is_operator():
identifier = None
templateArgs = None
operator = name
else:
identifier = name.identifier
templateArgs = name.templateArgs
operator = None
s = s._find_named_symbol(identifier, templateParams,
templateArgs, operator,
identOrOp = name.identOrOp
templateArgs = name.templateArgs
s = s._find_named_symbol(identOrOp,
templateParams, templateArgs,
templateShorthand=False,
matchSelf=False)
if not s:
@ -3660,13 +3660,13 @@ class Symbol(object):
firstName = names[0]
if not firstName.is_operator():
while parentSymbol.parent:
if parentSymbol.find_identifier(firstName.identifier,
if parentSymbol.find_identifier(firstName.identOrOp,
matchSelf=matchSelf):
# if we are in the scope of a constructor but wants to reference the class
# we need to walk one extra up
if (len(names) == 1 and typ == 'class' and matchSelf and
parentSymbol.parent and parentSymbol.parent.identifier and
parentSymbol.parent.identifier == firstName.identifier):
parentSymbol.parent and
parentSymbol.parent.identOrOp == firstName.identOrOp):
pass
else:
break
@ -3675,48 +3675,36 @@ class Symbol(object):
for iName in range(len(names)):
name = names[iName]
if iName + 1 == len(names):
if name.is_operator():
identifier = None
templateArgs = None
operator = name
else:
identifier = name.identifier
templateArgs = name.templateArgs
operator = None
identOrOp = name.identOrOp
templateArgs = name.templateArgs
if iTemplateDecl < len(templateDecls):
assert iTemplateDecl + 1 == len(templateDecls)
templateParams = templateDecls[iTemplateDecl]
else:
assert iTemplateDecl == len(templateDecls)
templateParams = None
symbol = parentSymbol._find_named_symbol(identifier,
symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams, templateArgs,
operator,
templateShorthand=templateShorthand,
matchSelf=matchSelf)
if symbol is not None:
return symbol
# try without template params and args
symbol = parentSymbol._find_named_symbol(identifier,
symbol = parentSymbol._find_named_symbol(identOrOp,
None, None,
operator,
templateShorthand=templateShorthand,
matchSelf=matchSelf)
return symbol
else:
# there shouldn't be anything inside an operator
assert not name.is_operator()
identifier = name.identifier
identOrOp = name.identOrOp
templateArgs = name.templateArgs
if templateArgs and iTemplateDecl < len(templateDecls):
templateParams = templateDecls[iTemplateDecl]
iTemplateDecl += 1
else:
templateParams = None
symbol = parentSymbol._find_named_symbol(identifier,
templateParams,
templateArgs,
operator=None,
symbol = parentSymbol._find_named_symbol(identOrOp,
templateParams, templateArgs,
templateShorthand=templateShorthand,
matchSelf=matchSelf)
if symbol is None:
@ -3739,8 +3727,8 @@ class Symbol(object):
res.append(text_type(self.templateParams))
res.append('\n')
res.append('\t' * indent)
if self.identifier:
res.append(text_type(self.identifier))
if self.identOrOp:
res.append(text_type(self.identOrOp))
else:
res.append(text_type(self.declaration))
if self.templateArgs:
@ -3781,6 +3769,8 @@ class DefinitionParser(object):
self.last_match = None # type: Match
self._previous_state = (0, None) # type: Tuple[int, Match]
self.otherErrors = [] # type: List[DefinitionError]
# in our tests the following is set to False to capture bad parsing
self.allowFallbackExpressionParsing = True
self.warnEnv = warnEnv
self.config = config
@ -4121,6 +4111,13 @@ class DefinitionParser(object):
# TODO: hmm, would we need to try both with operatorCast and with None?
prefix = self._parse_type(False, 'operatorCast')
prefixType = 'typeOperatorCast'
# | simple-type-specifier "(" expression-list [opt] ")"
# | simple-type-specifier braced-init-list
# | typename-specifier "(" expression-list [opt] ")"
# | typename-specifier braced-init-list
self.skip_ws()
if self.current_char != '(' and self.current_char != '{':
self.fail("Expecting '(' or '{' after type in cast expression.")
except DefinitionError as eInner:
self.pos = pos
header = "Error in postfix expression, expected primary expression or type."
@ -4361,7 +4358,7 @@ class DefinitionParser(object):
# TODO: actually parse the second production
return self._parse_assignment_expression(inTemplate=inTemplate)
def _parse_expression_fallback(self, end, parser):
def _parse_expression_fallback(self, end, parser, allow=True):
# Stupidly "parse" an expression.
# 'end' should be a list of characters which ends the expression.
@ -4370,6 +4367,10 @@ class DefinitionParser(object):
try:
return parser()
except DefinitionError as e:
# some places (e.g., template parameters) we really don't want to use fallback,
# and for testing we may want to globally disable it
if not allow or not self.allowFallbackExpressionParsing:
raise
self.warn("Parsing of expression failed. Using fallback parser."
" Error was:\n%s" % e.description)
self.pos = prevPos
@ -4480,7 +4481,8 @@ class DefinitionParser(object):
def _parse_nested_name(self, memberPointer=False):
# type: (bool) -> ASTNestedName
names = []
names = [] # type: List[Any]
templates = [] # type: List[bool]
self.skip_ws()
rooted = False
@ -4488,14 +4490,17 @@ class DefinitionParser(object):
rooted = True
while 1:
self.skip_ws()
if self.skip_word_and_ws('template'):
self.fail("'template' in nested name not implemented.")
elif self.skip_word_and_ws('operator'):
op = self._parse_operator()
names.append(op)
if len(names) > 0:
template = self.skip_word_and_ws('template')
else:
template = False
templates.append(template)
if self.skip_word_and_ws('operator'):
identOrOp = self._parse_operator()
else:
if not self.match(_identifier_re):
if memberPointer and len(names) > 0:
templates.pop()
break
self.fail("Expected identifier in nested name.")
identifier = self.matched_text
@ -4503,24 +4508,24 @@ class DefinitionParser(object):
if identifier in _keywords:
self.fail("Expected identifier in nested name, "
"got keyword: %s" % identifier)
# try greedily to get template parameters,
# but otherwise a < might be because we are in an expression
pos = self.pos
try:
templateArgs = self._parse_template_argument_list()
except DefinitionError as ex:
self.pos = pos
templateArgs = None
self.otherErrors.append(ex)
identifier = ASTIdentifier(identifier) # type: ignore
names.append(ASTNestedNameElement(identifier, templateArgs))
identOrOp = ASTIdentifier(identifier)
# try greedily to get template arguments,
# but otherwise a < might be because we are in an expression
pos = self.pos
try:
templateArgs = self._parse_template_argument_list()
except DefinitionError as ex:
self.pos = pos
templateArgs = None
self.otherErrors.append(ex)
names.append(ASTNestedNameElement(identOrOp, templateArgs))
self.skip_ws()
if not self.skip_string('::'):
if memberPointer:
self.fail("Expected '::' in pointer to member (function).")
break
return ASTNestedName(names, rooted)
return ASTNestedName(names, templates, rooted)
def _parse_trailing_type_spec(self):
# type: () -> Any
@ -4598,7 +4603,7 @@ class DefinitionParser(object):
self.fail('Expected ")" after "..." in '
'parameters_and_qualifiers.')
break
# note: it seems that function arguments can always sbe named,
# note: it seems that function arguments can always be named,
# even in function pointers and similar.
arg = self._parse_type_with_init(outer=None, named='single')
# TODO: parse default parameters # TODO: didn't we just do that?
@ -4785,7 +4790,7 @@ class DefinitionParser(object):
if self.match(_identifier_re):
identifier = ASTIdentifier(self.matched_text)
nne = ASTNestedNameElement(identifier, None)
declId = ASTNestedName([nne], rooted=False)
declId = ASTNestedName([nne], [False], rooted=False)
# if it's a member pointer, we may have '::', which should be an error
self.skip_ws()
if self.current_char == ':':
@ -4919,8 +4924,8 @@ class DefinitionParser(object):
header = "Error in declarator or parameters and qualifiers"
raise self._make_multi_error(prevErrors, header)
def _parse_initializer(self, outer=None):
# type: (unicode) -> ASTInitializer
def _parse_initializer(self, outer=None, allowFallback=True):
# type: (unicode, bool) -> ASTInitializer
self.skip_ws()
# TODO: support paren and brace initialization for memberObject
if not self.skip_string('='):
@ -4929,15 +4934,18 @@ class DefinitionParser(object):
if outer == 'member':
def parser():
return self._parse_assignment_expression(inTemplate=False)
value = self._parse_expression_fallback([], parser)
value = self._parse_expression_fallback([], parser,
allow=allowFallback)
elif outer == 'templateParam':
def parser():
return self._parse_assignment_expression(inTemplate=True)
value = self._parse_expression_fallback([',', '>'], parser)
value = self._parse_expression_fallback([',', '>'], parser,
allow=allowFallback)
elif outer is None: # function parameter
def parser():
return self._parse_assignment_expression(inTemplate=False)
value = self._parse_expression_fallback([',', ')'], parser)
value = self._parse_expression_fallback([',', ')'], parser,
allow=allowFallback)
else:
self.fail("Internal error, initializer for outer '%s' not "
"implemented." % outer)
@ -5027,12 +5035,48 @@ class DefinitionParser(object):
return ASTType(declSpecs, decl)
def _parse_type_with_init(self, named, outer):
# type: (Union[bool, unicode], unicode) -> ASTTypeWithInit
# type: (Union[bool, unicode], unicode) -> Any
if outer:
assert outer in ('type', 'member', 'function', 'templateParam')
type = self._parse_type(outer=outer, named=named)
init = self._parse_initializer(outer=outer)
return ASTTypeWithInit(type, init)
if outer != 'templateParam':
init = self._parse_initializer(outer=outer)
return ASTTypeWithInit(type, init)
# it could also be a constrained type parameter, e.g., C T = int&
pos = self.pos
eExpr = None
try:
init = self._parse_initializer(outer=outer, allowFallback=False)
# note: init may be None if there is no =
if init is None:
return ASTTypeWithInit(type, None)
# we parsed an expression, so we must have a , or a >,
# otherwise the expression didn't get everything
self.skip_ws()
if self.current_char != ',' and self.current_char != '>':
# pretend it didn't happen
self.pos = pos
init = None
else:
# we assume that it was indeed an expression
return ASTTypeWithInit(type, init)
except DefinitionError as e:
self.pos = pos
eExpr = e
if not self.skip_string("="):
return ASTTypeWithInit(type, None)
try:
typeInit = self._parse_type(named=False, outer=None)
return ASTTemplateParamConstrainedTypeWithInit(type, typeInit)
except DefinitionError as eType:
if eExpr is None:
raise eType
errs = []
errs.append((eExpr, "If default is an expression"))
errs.append((eType, "If default is a type"))
msg = "Error in non-type template parameter"
msg += " or constrianted template paramter."
raise self._make_multi_error(errs, msg)
def _parse_type_using(self):
# type: () -> ASTTypeUsing
@ -5156,13 +5200,14 @@ class DefinitionParser(object):
param = ASTTemplateParamType(data)
templateParams.append(param)
else:
# declare a non-type parameter
# declare a non-type parameter, or constrained type parameter
pos = self.pos
try:
param = self._parse_type_with_init('maybe', 'templateParam')
templateParams.append(ASTTemplateParamNonType(param))
except DefinitionError as e:
prevErrors.append((e, "If non-type template parameter"))
msg = "If non-type template parameter or constrained template parameter"
prevErrors.append((e, msg))
self.pos = pos
self.skip_ws()
if self.skip_string('>'):
@ -5386,7 +5431,7 @@ class DefinitionParser(object):
def _make_phony_error_name():
# type: () -> ASTNestedName
nne = ASTNestedNameElement(ASTIdentifier("PhonyNameDueToError"), None)
return ASTNestedName([nne], rooted=False)
return ASTNestedName([nne], [False], rooted=False)
class CPPObject(ObjectDescription):
@ -5421,7 +5466,7 @@ class CPPObject(ObjectDescription):
# then add the name to the parent scope
symbol = ast.symbol
assert symbol
assert symbol.identifier is not None
assert symbol.identOrOp is not None
assert symbol.templateParams is None
assert symbol.templateArgs is None
parentSymbol = symbol.parent
@ -5434,7 +5479,7 @@ class CPPObject(ObjectDescription):
if parentDecl is None:
# the parent is not explicitly declared
# TODO: we could warn, but it could be a style to just assume
# enumerator parnets to be scoped
# enumerator parents to be scoped
return
if parentDecl.objectType != 'enum':
# TODO: maybe issue a warning, enumerators in non-enums is weird,
@ -5444,13 +5489,13 @@ class CPPObject(ObjectDescription):
return
targetSymbol = parentSymbol.parent
s = targetSymbol.find_identifier(symbol.identifier, matchSelf=False)
s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False)
if s is not None:
# something is already declared with that name
return
declClone = symbol.declaration.clone()
declClone.enumeratorScopedSymbol = symbol
Symbol(parent=targetSymbol, identifier=symbol.identifier,
Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp,
templateParams=None, templateArgs=None,
declaration=declClone,
docname=self.env.docname)

View File

@ -5,7 +5,7 @@
The JavaScript domain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The Python domain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The reStructuredText domain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The standard domain.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -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):

View File

@ -5,7 +5,7 @@
Global creation environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -40,7 +40,6 @@ from sphinx.util.matching import compile_matchers
from sphinx.util.parallel import ParallelTasks, parallel_available, make_chunks
from sphinx.util.websupport import is_commentable
from sphinx.errors import SphinxError, ExtensionError
from sphinx.locale import __
from sphinx.transforms import SphinxTransformer
from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment.adapters.indexentries import IndexEntries
@ -558,21 +557,10 @@ class BuildEnvironment(object):
self.app.emit('env-before-read-docs', self, docnames)
# check if we should do parallel or serial read
par_ok = False
if parallel_available and len(docnames) > 5 and self.app.parallel > 1:
for ext in itervalues(self.app.extensions):
if ext.parallel_read_safe is None:
logger.warning(__('the %s extension does not declare if it is safe '
'for parallel reading, assuming it isn\'t - please '
'ask the extension author to check and make it '
'explicit'), ext.name)
logger.warning('doing serial read')
break
elif ext.parallel_read_safe is False:
break
else:
# all extensions support parallel-read
par_ok = True
par_ok = self.app.is_parallel_allowed('read')
else:
par_ok = False
if par_ok:
self._read_parallel(docnames, self.app, nproc=self.app.parallel)
@ -878,7 +866,7 @@ class BuildEnvironment(object):
transformer = SphinxTransformer(doctree)
transformer.set_environment(self)
transformer.add_transforms(self.app.post_transforms)
transformer.add_transforms(self.app.registry.get_post_transforms())
transformer.apply_transforms()
finally:
self.temp_data = backup

View File

@ -5,6 +5,6 @@
Sphinx environment adapters
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Assets adapter for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Index entries adapters for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re

View File

@ -5,7 +5,7 @@
Toctree adapter for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The data collector components for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The image collector for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The dependencies collector components for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Index entries collector for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The metadata collector components for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
The title collector components for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Toctree collector for sphinx.environment.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -6,7 +6,7 @@
Contains SphinxError and a few subclasses (in an extra module to avoid
circular import problems).
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -7,7 +7,7 @@
Gracefully adapted from the TextPress system by Armin.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function

View File

@ -5,6 +5,6 @@
Contains Sphinx features not activated by default.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -11,7 +11,7 @@
Copyright 2008 Société des arts technologiques (SAT),
http://www.sat.qc.ca/
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -27,7 +27,7 @@ from fnmatch import fnmatch
from sphinx import __display_version__
from sphinx.cmd.quickstart import EXTENSIONS
from sphinx.util import rst
from sphinx.util.osutil import FileAvoidWrite, walk
from sphinx.util.osutil import FileAvoidWrite, ensuredir, walk
if False:
# For type annotation
@ -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')
@ -382,8 +386,8 @@ def main(argv=sys.argv[1:]):
if not path.isdir(rootpath):
print('%s is not a directory.' % rootpath, file=sys.stderr)
sys.exit(1)
if not path.isdir(args.destdir) and not args.dryrun:
os.makedirs(args.destdir)
if not args.dryrun:
ensuredir(args.destdir)
excludes = [path.abspath(exclude) for exclude in args.exclude_pattern]
modules = recurse_tree(rootpath, excludes, args)

View File

@ -7,24 +7,22 @@
the doctree, thus avoiding duplication between docstrings and documentation
for those who like elaborate docstrings.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
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."""
@ -383,55 +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.warning(errmsg)
except ImportError as exc:
logger.warning(exc.args[0])
self.env.note_reread()
return False
@ -604,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:
logger.warning('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]]
@ -713,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
@ -767,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
@ -896,7 +796,7 @@ class ModuleDocumenter(Documenter):
'platform': identity, 'deprecated': bool_option,
'member-order': identity, 'exclude-members': members_set_option,
'private-members': bool_option, 'special-members': members_option,
'imported-members': bool_option,
'imported-members': bool_option, 'ignore-module-all': bool_option
} # type: Dict[unicode, Callable]
@classmethod
@ -938,7 +838,8 @@ class ModuleDocumenter(Documenter):
def get_object_members(self, want_all):
# type: (bool) -> Tuple[bool, List[Tuple[unicode, object]]]
if want_all:
if not hasattr(self.object, '__all__'):
if (self.options.ignore_module_all or not
hasattr(self.object, '__all__')):
# for implicit module members, check __module__ to avoid
# documenting imported objects
return True, safe_getmembers(self.object)
@ -1502,117 +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',
])
# 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
logger.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.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 []
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 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)
@ -1623,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)

View File

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

View File

@ -5,7 +5,7 @@
Importer utilities for autodoc
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -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, Set # NOQA
logger = logging.getLogger(__name__)
@ -144,3 +148,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

View File

@ -5,7 +5,7 @@
Inspect utilities for autodoc
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Allow reference sections by :ref: role using its title.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -49,7 +49,7 @@
resolved to a Python object, and otherwise it becomes simple emphasis.
This can be used as the default role to make links 'smart'.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -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):

View File

@ -14,7 +14,7 @@
generate:
sphinx-autogen -o source/generated source/*.rst
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import print_function
@ -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__':

View File

@ -6,7 +6,7 @@
Check Python modules and C API for coverage. Mostly written by Josip
Dzolonga for the Google Highly Open Participation contest.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -6,7 +6,7 @@
Mimic doctest by automatically executing code snippets and checking
their results.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
from __future__ import absolute_import

View File

@ -20,7 +20,7 @@
You can also give an explicit caption, e.g. :exmpl:`Foo <foo>`.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
To publish HTML docs at GitHub Pages, create .nojekyll file.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -6,7 +6,7 @@
Allow graphviz-formatted graphs to be included in Sphinx-generated
documents inline.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -16,7 +16,7 @@
namespace of the project configuration (that is, all variables from
``conf.py`` are available.)
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -5,7 +5,7 @@
Image converter extension for Sphinx
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import subprocess

View File

@ -5,7 +5,7 @@
Render math in HTML via dvipng or dvisvgm.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -30,6 +30,7 @@ from sphinx.util.png import read_png_depth, write_png_depth
from sphinx.util.osutil import ensuredir, ENOENT, cd
from sphinx.util.pycompat import sys_encoding
from sphinx.ext.mathbase import setup_math as mathbase_setup, wrap_displaymath
from sphinx.ext.mathbase import get_node_equation_number
if False:
# For type annotation
@ -333,7 +334,8 @@ def html_visit_displaymath(self, node):
self.body.append(self.starttag(node, 'div', CLASS='math'))
self.body.append('<p>')
if node['number']:
self.body.append('<span class="eqno">(%s)' % node['number'])
number = get_node_equation_number(self, node)
self.body.append('<span class="eqno">(%s)' % number)
self.add_permalink_ref(node, _('Permalink to this equation'))
self.body.append('</span>')
if fname is None:

View File

@ -32,7 +32,7 @@ r"""
The graph is inserted as a PNG+image map into HTML and a PDF in
LaTeX.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

View File

@ -20,7 +20,7 @@
also be specified individually, e.g. if the docs should be buildable
without Internet access.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -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))

View File

@ -6,7 +6,7 @@
Set up everything for use of JSMath to display math in HTML
via JavaScript.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@ -16,6 +16,7 @@ import sphinx
from sphinx.locale import _
from sphinx.application import ExtensionError
from sphinx.ext.mathbase import setup_math as mathbase_setup
from sphinx.ext.mathbase import get_node_equation_number
def html_visit_math(self, node):
@ -35,7 +36,8 @@ def html_visit_displaymath(self, node):
if i == 0:
# necessary to e.g. set the id property correctly
if node['number']:
self.body.append('<span class="eqno">(%s)' % node['number'])
number = get_node_equation_number(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'))

View File

@ -5,7 +5,7 @@
Add external links to module code in Python object descriptions.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""

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