Merge branch 'master' of github.com:sphinx-doc/sphinx

This commit is contained in:
Jakob Lykke Andersen 2017-12-20 09:06:22 +01:00
commit 42f557d4b0
54 changed files with 395 additions and 405 deletions

View File

@ -2,46 +2,40 @@ language: python
sudo: false sudo: false
dist: trusty dist: trusty
cache: pip cache: pip
python:
- "pypy-5.4.1"
- "3.6"
- "3.5"
- "3.4"
- "2.7"
- "nightly"
env: env:
global: global:
- TEST='-v --durations 25'
- PYTHONFAULTHANDLER=x - PYTHONFAULTHANDLER=x
- PYTHONWARNINGS=all - PYTHONWARNINGS=all
- SKIP_LATEX_BUILD=1 - SKIP_LATEX_BUILD=1
matrix:
- DOCUTILS=0.13.1
- DOCUTILS=0.14
matrix: matrix:
exclude: include:
- python: "3.4" - python: 'pypy'
env: DOCUTILS=0.13.1 env: TOXENV=pypy
- python: "3.5" - python: '2.7'
env: DOCUTILS=0.13.1 env: TOXENV=du13
- python: "3.6" - python: '3.4'
env: DOCUTILS=0.13.1 env: TOXENV=py34
- python: nightly - python: '3.5'
env: DOCUTILS=0.13.1 env: TOXENV=py35
- python: "pypy-5.4.1" - python: '3.6'
env: DOCUTILS=0.13.1 env: TOXENV=py36
- python: 'nightly'
env: TOXENV=py37
- python: '3.6'
env: TOXENV=mypy
- python: '2.7'
env: TOXENV=flake8
addons: addons:
apt: apt:
packages: packages:
- graphviz - graphviz
- imagemagick - imagemagick
install: install:
- pip install -U pip setuptools - pip install -U tox
- 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
script: script:
- flake8 - tox -- -v
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then make type-check test-async; fi
- if [[ $TRAVIS_PYTHON_VERSION != '3.6' ]]; then make test; fi

View File

@ -19,6 +19,8 @@ Deprecated
* using a string value for :confval:`html_sidebars` is deprecated and only list * using a string value for :confval:`html_sidebars` is deprecated and only list
values will be accepted at 2.0. values will be accepted at 2.0.
* ``format_annotation()`` and ``formatargspec()`` is deprecated. Please use
``sphinx.util.inspect.Signature`` instead.
Features added Features added
-------------- --------------
@ -129,6 +131,7 @@ Bugs fixed
* #4279: Sphinx crashes with pickling error when run with multiple processes and * #4279: Sphinx crashes with pickling error when run with multiple processes and
remote image remote image
* #1421: Respect the quiet flag in sphinx-quickstart * #1421: Respect the quiet flag in sphinx-quickstart
* #4281: Race conditions when creating output directory
Testing 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 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 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 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 exception. The location of this file should be shown towards the end of the
error message. error message.
@ -45,6 +45,7 @@ issue. If possible, try to create a minimal project that produces the error
and post that instead. and post that instead.
.. _`issue tracker`: https://github.com/sphinx-doc/sphinx/issues .. _`issue tracker`: https://github.com/sphinx-doc/sphinx/issues
.. _`sphinx-dev`: mailto:sphinx-dev@googlegroups.com
Contributing to Sphinx 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 #. Check for open issues or open a fresh issue to start a discussion around a
feature idea or a bug. feature idea or a bug.
#. If you feel uncomfortable or uncertain about an issue or your changes, feel #. 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 #. Fork `the repository`_ on GitHub to start making your changes to the
**master** branch for next major version, or **stable** branch for next **master** branch for next major version, or **stable** branch for next
minor version. 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 For new features or other substantial changes that should wait until the
next major release, use the ``master`` branch. next major release, use the ``master`` branch.
#. Optional: setup a virtual environment. :: #. Setup a virtual environment.
virtualenv ~/sphinxenv This is not necessary for unit testing, thanks to ``tox``, but it is
. ~/sphinxenv/bin/activate 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 . pip install -e .
#. Create a new working branch. Choose any name you like. :: #. 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`_. 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] * To list all possible targets::
make test
* Again, it's useful to turn on deprecation warnings on so they're shown in tox -av
the test output::
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:: 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 tox -e docs -- -b html,latexpdf
make type-check
* Run the unit tests under different Python environments using You can also test by installing dependencies in your local environment. ::
:program:`tox`::
pip install tox pip install .[test]
tox -v
* 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 * For bug fixes, first add a test that fails without your changes and passes
after they are applied. 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 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 then ``build_all`` for a few assertions are not good since *the test suite
should not take more than a minute to run*. 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 code by running the command ``make clean`` or using the
:option:`sphinx-build -E` option. :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 * Use ``node.pformat()`` and ``node.asdom().toxml()`` to generate a printable
representation of the document structure. representation of the document structure.

View File

@ -34,6 +34,8 @@ Documentation using the alabaster theme
* pytest: https://docs.pytest.org/ (customized) * pytest: https://docs.pytest.org/ (customized)
* python-apt: https://apt.alioth.debian.org/python-apt-doc/ * python-apt: https://apt.alioth.debian.org/python-apt-doc/
* PyVisfile: https://documen.tician.de/pyvisfile/ * PyVisfile: https://documen.tician.de/pyvisfile/
* Requests: http://www.python-requests.org/
* searx: https://asciimoo.github.io/searx/
* Tablib: http://docs.python-tablib.org/ * Tablib: http://docs.python-tablib.org/
* urllib3: https://urllib3.readthedocs.io/ (customized) * urllib3: https://urllib3.readthedocs.io/ (customized)
* Werkzeug: http://werkzeug.pocoo.org/docs/ (customized) * Werkzeug: http://werkzeug.pocoo.org/docs/ (customized)
@ -46,6 +48,7 @@ Documentation using the classic theme
* APSW: https://rogerbinns.github.io/apsw/ * APSW: https://rogerbinns.github.io/apsw/
* Arb: http://arblib.org/ * Arb: http://arblib.org/
* Bazaar: http://doc.bazaar.canonical.com/ (customized) * Bazaar: http://doc.bazaar.canonical.com/ (customized)
* Beautiful Soup: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
* Blender: https://docs.blender.org/api/current/ * Blender: https://docs.blender.org/api/current/
* Bugzilla: https://bugzilla.readthedocs.io/ * Bugzilla: https://bugzilla.readthedocs.io/
* Buildbot: https://docs.buildbot.net/latest/ * Buildbot: https://docs.buildbot.net/latest/
@ -79,6 +82,8 @@ Documentation using the classic theme
* Pyevolve: http://pyevolve.sourceforge.net/ * Pyevolve: http://pyevolve.sourceforge.net/
* Pygame: https://www.pygame.org/docs/ (customized) * Pygame: https://www.pygame.org/docs/ (customized)
* PyMQI: https://pythonhosted.org/pymqi/ * PyMQI: https://pythonhosted.org/pymqi/
* PyQt4: http://pyqt.sourceforge.net/Docs/PyQt4/ (customized)
* PyQt5: http://pyqt.sourceforge.net/Docs/PyQt5/ (customized)
* Python 2: https://docs.python.org/2/ * Python 2: https://docs.python.org/2/
* Python 3: https://docs.python.org/3/ (customized) * Python 3: https://docs.python.org/3/ (customized)
* Python Packaging Authority: https://www.pypa.io/ (customized) * Python Packaging Authority: https://www.pypa.io/ (customized)
@ -121,11 +126,16 @@ Documentation using the nature theme
* Alembic: http://alembic.zzzcomputing.com/ * Alembic: http://alembic.zzzcomputing.com/
* Cython: http://docs.cython.org/ * Cython: http://docs.cython.org/
* easybuild: https://easybuild.readthedocs.io/
* jsFiddle: http://doc.jsfiddle.net/ * jsFiddle: http://doc.jsfiddle.net/
* libLAS: https://www.liblas.org/ (customized) * libLAS: https://www.liblas.org/ (customized)
* Lmod: https://lmod.readthedocs.io/
* MapServer: http://mapserver.org/ (customized) * MapServer: http://mapserver.org/ (customized)
* Pandas: https://pandas.pydata.org/pandas-docs/stable/
* pyglet: https://pyglet.readthedocs.io/ (customized)
* Setuptools: https://setuptools.readthedocs.io/ * Setuptools: https://setuptools.readthedocs.io/
* Spring Python: https://docs.spring.io/spring-python/1.2.x/sphinx/html/ * Spring Python: https://docs.spring.io/spring-python/1.2.x/sphinx/html/
* StatsModels: http://www.statsmodels.org/ (customized)
* Sylli: http://sylli.sourceforge.net/ * Sylli: http://sylli.sourceforge.net/
Documentation using another builtin theme Documentation using another builtin theme
@ -133,6 +143,7 @@ Documentation using another builtin theme
* Breathe: https://breathe.readthedocs.io/ (haiku) * Breathe: https://breathe.readthedocs.io/ (haiku)
* MPipe: https://vmlaker.github.io/mpipe/ (sphinx13) * MPipe: https://vmlaker.github.io/mpipe/ (sphinx13)
* NLTK: http://www.nltk.org/ (agogo)
* Programmieren mit PyGTK und Glade (German): * Programmieren mit PyGTK und Glade (German):
http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo, customized) http://www.florian-diesch.de/doc/python-und-glade/online/ (agogo, customized)
* PyPubSub: https://pypubsub.readthedocs.io/ (bizstyle) * PyPubSub: https://pypubsub.readthedocs.io/ (bizstyle)
@ -150,8 +161,10 @@ Documentation using sphinx_rtd_theme
* ASE: https://wiki.fysik.dtu.dk/ase/ * ASE: https://wiki.fysik.dtu.dk/ase/
* Autofac: http://docs.autofac.org/ * Autofac: http://docs.autofac.org/
* BigchainDB: https://docs.bigchaindb.com/ * BigchainDB: https://docs.bigchaindb.com/
* Blocks: https://blocks.readthedocs.io/
* bootstrap-datepicker: https://bootstrap-datepicker.readthedocs.io/ * bootstrap-datepicker: https://bootstrap-datepicker.readthedocs.io/
* Certbot: https://letsencrypt.readthedocs.io/ * Certbot: https://letsencrypt.readthedocs.io/
* Chainer: https://docs.chainer.org/ (customized)
* CherryPy: http://docs.cherrypy.org/ * CherryPy: http://docs.cherrypy.org/
* Chainer: https://docs.chainer.org/ * Chainer: https://docs.chainer.org/
* CodeIgniter: https://www.codeigniter.com/user_guide/ * CodeIgniter: https://www.codeigniter.com/user_guide/
@ -178,14 +191,18 @@ Documentation using sphinx_rtd_theme
* Idris: http://docs.idris-lang.org/ * Idris: http://docs.idris-lang.org/
* javasphinx: https://bronto-javasphinx.readthedocs.io/ * javasphinx: https://bronto-javasphinx.readthedocs.io/
* Julia: https://julia.readthedocs.io/ * Julia: https://julia.readthedocs.io/
* Jupyter Notebook: https://jupyter-notebook.readthedocs.io/
* Lasagne: https://lasagne.readthedocs.io/
* Linguistica: https://linguistica-uchicago.github.io/lxa5/ * Linguistica: https://linguistica-uchicago.github.io/lxa5/
* Linux kernel: https://www.kernel.org/doc/html/latest/index.html * Linux kernel: https://www.kernel.org/doc/html/latest/index.html
* MathJax: https://docs.mathjax.org/ * MathJax: https://docs.mathjax.org/
* MDTraj: http://mdtraj.org/latest/ (customized) * MDTraj: http://mdtraj.org/latest/ (customized)
* MICrobial Community Analysis (micca): http://micca.org/docs/latest/ * MICrobial Community Analysis (micca): http://micca.org/docs/latest/
* MicroPython: https://docs.micropython.org/ * MicroPython: https://docs.micropython.org/
* Minds: https://www.minds.org/docs/ (customized)
* Mink: http://mink.behat.org/ * Mink: http://mink.behat.org/
* Mockery: http://docs.mockery.io/ * Mockery: http://docs.mockery.io/
* mod_wsgi: https://modwsgi.readthedocs.io/
* MoinMoin: https://moin-20.readthedocs.io/ * MoinMoin: https://moin-20.readthedocs.io/
* Mopidy: https://docs.mopidy.com/ * Mopidy: https://docs.mopidy.com/
* MyHDL: http://docs.myhdl.org/ * MyHDL: http://docs.myhdl.org/
@ -224,13 +241,16 @@ Documentation using sphinx_rtd_theme
* Sylius: http://docs.sylius.org/ * Sylius: http://docs.sylius.org/
* Tango Controls: https://tango-controls.readthedocs.io/ (customized) * Tango Controls: https://tango-controls.readthedocs.io/ (customized)
* Topshelf: http://docs.topshelf-project.com/ * Topshelf: http://docs.topshelf-project.com/
* Theano: http://www.deeplearning.net/software/theano/
* ThreatConnect: https://docs.threatconnect.com/ * ThreatConnect: https://docs.threatconnect.com/
* Tuleap: https://tuleap.net/doc/en/ * Tuleap: https://tuleap.net/doc/en/
* TYPO3: https://docs.typo3.org/ (customized) * TYPO3: https://docs.typo3.org/ (customized)
* uWSGI: https://uwsgi-docs.readthedocs.io/
* Wagtail: http://docs.wagtail.io/ * Wagtail: http://docs.wagtail.io/
* Web Application Attack and Audit Framework (w3af): http://docs.w3af.org/ * Web Application Attack and Audit Framework (w3af): http://docs.w3af.org/
* Weblate: https://docs.weblate.org/ * Weblate: https://docs.weblate.org/
* x265: https://x265.readthedocs.io/ * x265: https://x265.readthedocs.io/
* ZeroNet: https://zeronet.readthedocs.io/
Documentation using sphinx_bootstrap_theme Documentation using sphinx_bootstrap_theme
------------------------------------------ ------------------------------------------
@ -245,12 +265,14 @@ Documentation using sphinx_bootstrap_theme
* Open Dylan: https://opendylan.org/documentation/ * Open Dylan: https://opendylan.org/documentation/
* Pootle: http://docs.translatehouse.org/projects/pootle/ * Pootle: http://docs.translatehouse.org/projects/pootle/
* PyUblas: https://documen.tician.de/pyublas/ * PyUblas: https://documen.tician.de/pyublas/
* seaborn: https://seaborn.pydata.org/
Documentation using a custom theme or integrated in a website Documentation using a custom theme or integrated in a website
------------------------------------------------------------- -------------------------------------------------------------
* Apache Cassandra: https://cassandra.apache.org/doc/ * Apache Cassandra: https://cassandra.apache.org/doc/
* Astropy: http://docs.astropy.org/ * Astropy: http://docs.astropy.org/
* Bokeh: https://bokeh.pydata.org/
* Boto 3: https://boto3.readthedocs.io/ * Boto 3: https://boto3.readthedocs.io/
* CakePHP: https://book.cakephp.org/ * CakePHP: https://book.cakephp.org/
* CasperJS: http://docs.casperjs.org/ * CasperJS: http://docs.casperjs.org/
@ -263,6 +285,7 @@ Documentation using a custom theme or integrated in a website
* Enterprise Toolkit for Acrobat products: * Enterprise Toolkit for Acrobat products:
https://www.adobe.com/devnet-docs/acrobatetk/ https://www.adobe.com/devnet-docs/acrobatetk/
* Gameduino: http://excamera.com/sphinx/gameduino/ * Gameduino: http://excamera.com/sphinx/gameduino/
* gensim: https://radimrehurek.com/gensim/
* GeoServer: http://docs.geoserver.org/ * GeoServer: http://docs.geoserver.org/
* gevent: http://www.gevent.org/ * gevent: http://www.gevent.org/
* GHC - Glasgow Haskell Compiler: http://downloads.haskell.org/~ghc/master/users-guide/ * GHC - Glasgow Haskell Compiler: http://downloads.haskell.org/~ghc/master/users-guide/
@ -307,6 +330,7 @@ Documentation using a custom theme or integrated in a website
* Sulu: http://docs.sulu.io/ * Sulu: http://docs.sulu.io/
* SQLAlchemy: https://docs.sqlalchemy.org/ * SQLAlchemy: https://docs.sqlalchemy.org/
* tinyTiM: http://tinytim.sourceforge.net/docs/2.0/ * tinyTiM: http://tinytim.sourceforge.net/docs/2.0/
* Twisted: http://twistedmatrix.com/documents/current/
* Ubuntu Packaging Guide: http://packaging.ubuntu.com/html/ * Ubuntu Packaging Guide: http://packaging.ubuntu.com/html/
* WebFaction: https://docs.webfaction.com/ * WebFaction: https://docs.webfaction.com/
* WTForms: https://wtforms.readthedocs.io/ * WTForms: https://wtforms.readthedocs.io/
@ -320,8 +344,10 @@ Homepages and other non-documentation sites
* Benoit Boissinot: https://bboissin.appspot.com/ (classic, customized) * Benoit Boissinot: https://bboissin.appspot.com/ (classic, customized)
* Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab): * Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab):
https://lab.miletic.net/ (sphinx_rtd_theme) https://lab.miletic.net/ (sphinx_rtd_theme)
* Deep Learning Tutorials: http://www.deeplearning.net/tutorial/ (sphinxdoc)
* Loyola University Chicago COMP 339-439 Distributed Systems course: * Loyola University Chicago COMP 339-439 Distributed Systems course:
http://books.cs.luc.edu/distributedsystems/ (sphinx_bootstrap_theme) http://books.cs.luc.edu/distributedsystems/ (sphinx_bootstrap_theme)
* Pylearn2: http://www.deeplearning.net/software/pylearn2/ (sphinxdoc, customized)
* SciPy Cookbook: https://scipy-cookbook.readthedocs.io/ (sphinx_rtd_theme) * SciPy Cookbook: https://scipy-cookbook.readthedocs.io/ (sphinx_rtd_theme)
* The Wine Cellar Book: https://www.thewinecellarbook.com/doc/en/ (sphinxdoc) * The Wine Cellar Book: https://www.thewinecellarbook.com/doc/en/ (sphinxdoc)
* Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials: * Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials:

View File

@ -69,11 +69,11 @@ reindent:
.PHONY: test .PHONY: test
test: test:
@cd tests; $(PYTHON) run.py --ignore py35 -v $(TEST) @cd tests; $(PYTHON) run.py -v $(TEST)
.PHONY: test-async .PHONY: test-async
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 .PHONY: covertest
covertest: covertest:

View File

@ -1,45 +1,102 @@
========
Sphinx
========
.. image:: https://img.shields.io/pypi/v/sphinx.svg .. image:: https://img.shields.io/pypi/v/sphinx.svg
:target: https://pypi.python.org/pypi/Sphinx :target: https://pypi.python.org/pypi/Sphinx
:alt: Package on PyPi
.. image:: https://readthedocs.org/projects/sphinx/badge/ .. image:: https://readthedocs.org/projects/sphinx/badge/
:target: http://www.sphinx-doc.org/ :target: http://www.sphinx-doc.org/
:alt: Documentation Status :alt: Documentation Status
.. image:: https://travis-ci.org/sphinx-doc/sphinx.svg?branch=master .. image:: https://travis-ci.org/sphinx-doc/sphinx.svg?branch=master
:target: https://travis-ci.org/sphinx-doc/sphinx :target: https://travis-ci.org/sphinx-doc/sphinx
:alt: Build Status (Travis CI)
================= .. image:: https://ci.appveyor.com/api/projects/status/github/sphinx-doc/sphinx?branch=master&svg=true
README for Sphinx :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)
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.
Installing 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.
Install from PyPI to use stable version:: 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 pip install -U sphinx
Install from PyPI to use beta version:: We also publish beta releases::
pip install -U --pre sphinx 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 Release signatures
================== ==================
@ -48,37 +105,3 @@ Releases are signed with following keys:
* `498D6B9E <https://pgp.mit.edu/pks/lookup?op=vindex&search=0x102C2C17498D6B9E>`_ * `498D6B9E <https://pgp.mit.edu/pks/lookup?op=vindex&search=0x102C2C17498D6B9E>`_
* `5EBA0E07 <https://pgp.mit.edu/pks/lookup?op=vindex&search=0x1425F8CE5EBA0E07>`_ * `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

@ -138,12 +138,10 @@ General configuration
- ``'library/xml.rst'`` -- ignores the ``library/xml.rst`` file (replaces - ``'library/xml.rst'`` -- ignores the ``library/xml.rst`` file (replaces
entry in :confval:`unused_docs`) entry in :confval:`unused_docs`)
- ``'library/xml'`` -- ignores the ``library/xml`` directory (replaces entry - ``'library/xml'`` -- ignores the ``library/xml`` directory
in :confval:`exclude_trees`)
- ``'library/xml*'`` -- ignores all files and directories starting with - ``'library/xml*'`` -- ignores all files and directories starting with
``library/xml`` ``library/xml``
- ``'**/.svn'`` -- ignores all ``.svn`` directories (replaces entry in - ``'**/.svn'`` -- ignores all ``.svn`` directories
:confval:`exclude_dirnames`)
:confval:`exclude_patterns` is also consulted when looking for static files :confval:`exclude_patterns` is also consulted when looking for static files
in :confval:`html_static_path` and :confval:`html_extra_path`. in :confval:`html_static_path` and :confval:`html_extra_path`.
@ -315,8 +313,8 @@ General configuration
.. confval:: numfig .. confval:: numfig
If true, figures, tables and code-blocks are automatically numbered if they 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 have a caption. The :rst:role:`numref` role is enabled.
works only with the HTML builder and LaTeX builder. Default is ``False``. Obeyed so far only by HTML and LaTeX builders. Default is ``False``.
.. note:: .. note::
@ -339,10 +337,21 @@ General configuration
.. confval:: numfig_secnum_depth .. confval:: numfig_secnum_depth
The scope of figure numbers, that is, the numfig feature numbers figures - if set to ``0``, figures, tables and code-blocks are continuously numbered
in which scope. ``0`` means "whole document". ``1`` means "in a section". starting at ``1``.
Sphinx numbers like x.1, x.2, x.3... ``2`` means "in a subsection". Sphinx - if ``1`` (default) numbers will be ``x.1``, ``x.2``, ... with ``x``
numbers like x.x.1, x.x.2, x.x.3..., and so on. Default is ``1``. 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...
.. note::
The LaTeX builder currently ignores this configuration setting. It will
obey it at Sphinx 1.7.
.. versionadded:: 1.3 .. versionadded:: 1.3

View File

@ -85,7 +85,7 @@ or use Python raw strings (``r"raw"``).
Normally, equations are not numbered. If you want your equation to get a Normally, equations are not numbered. If you want your equation to get a
number, use the ``label`` option. When given, it selects an internal label number, use the ``label`` option. When given, it selects an internal label
for the equation, by which it can be cross-referenced, and causes an equation for the equation, by which it can be cross-referenced, and causes an equation
number to be issued. See :rst:role:`eqref` for an example. The numbering number to be issued. See :rst:role:`eq` for an example. The numbering
style depends on the output format. style depends on the output format.
There is also an option ``nowrap`` that prevents any wrapping of the given There is also an option ``nowrap`` that prevents any wrapping of the given
@ -102,8 +102,7 @@ or use Python raw strings (``r"raw"``).
.. rst:role:: eq .. rst:role:: eq
Role for cross-referencing equations via their label. This currently works Role for cross-referencing equations via their label. Example::
only within the same document. Example::
.. math:: e^{i\pi} + 1 = 0 .. math:: e^{i\pi} + 1 = 0
:label: euler :label: euler

View File

@ -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 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". 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. If an explicit link text is given (as usual: ``:numref:`Image of Sphinx (Fig.
%s) <my-figure>```), the link caption will be the title of the reference. %s) <my-figure>```), the link caption will serve as title of the reference.
As a special character, `%s` and `{number}` will be replaced to figure As placeholders, `%s` and `{number}` get replaced by the figure
number. `{name}` will be replaced to figure caption. number and `{name}` by the figure caption.
If no explicit link text is given, the value of :confval:`numfig_format` is If no explicit link text is given, the :confval:`numfig_format` setting is
used to default value of link text. used as fall-back default.
If :confval:`numfig` is ``False``, figures are not numbered. If :confval:`numfig` is ``False``, figures are not numbered,
so this role inserts not a reference but labels or link text. so this role inserts not a reference but the label or the link text.
Cross-referencing other items of interest Cross-referencing other items of interest
----------------------------------------- -----------------------------------------

View File

@ -1,11 +1,20 @@
[metadata]
license_file = LICENSE
[egg_info] [egg_info]
tag_build = .dev tag_build = .dev
tag_date = true tag_date = true
[bdist_wheel]
universal = 1
[aliases] [aliases]
release = egg_info -Db '' release = egg_info -Db ''
upload = upload --sign --identity=36580288 upload = upload --sign --identity=36580288
[build_sphinx]
warning-is-error = 1
[extract_messages] [extract_messages]
mapping_file = babel.cfg mapping_file = babel.cfg
output_file = sphinx/locale/sphinx.pot output_file = sphinx/locale/sphinx.pot
@ -20,12 +29,6 @@ output_dir = sphinx/locale/
domain = sphinx domain = sphinx
directory = sphinx/locale/ directory = sphinx/locale/
[bdist_wheel]
universal = 1
[metadata]
license_file = LICENSE
[flake8] [flake8]
max-line-length = 95 max-line-length = 95
ignore = E116,E241,E251,E741 ignore = E116,E241,E251,E741
@ -40,6 +43,3 @@ follow_imports = skip
incremental = True incremental = True
check_untyped_defs = True check_untyped_defs = True
warn_unused_ignores = True warn_unused_ignores = True
[build_sphinx]
warning-is-error = 1

View File

@ -8,34 +8,8 @@ from distutils.cmd import Command
import sphinx import sphinx
long_desc = ''' with open('README.rst') as f:
Sphinx is a tool that makes it easy to create intelligent and beautiful long_desc = f.read()
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
'''
if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 4): 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.') print('ERROR: Sphinx requires at least Python 2.7 or 3.4 to run.')
@ -72,6 +46,7 @@ extras_require = {
'pytest', 'pytest',
'pytest-cov', 'pytest-cov',
'html5lib', 'html5lib',
'flake8',
], ],
'test:python_version<"3"': [ 'test:python_version<"3"': [
'enum34', 'enum34',

View File

@ -40,7 +40,7 @@ from sphinx.util import pycompat # noqa: F401
from sphinx.util import import_object from sphinx.util import import_object
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.tags import Tags 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.console import bold # type: ignore
from sphinx.util.docutils import is_html5_writer_available, directive_helper from sphinx.util.docutils import is_html5_writer_available, directive_helper
from sphinx.util.i18n import find_catalog_source_files from sphinx.util.i18n import find_catalog_source_files
@ -159,7 +159,7 @@ class Sphinx(object):
if not path.isdir(outdir): if not path.isdir(outdir):
logger.info('making output directory...') logger.info('making output directory...')
os.makedirs(outdir) ensuredir(outdir)
# read config # read config
self.tags = Tags(tags) self.tags = Tags(tags)

View File

@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import os
from os import path from os import path
import warnings import warnings
@ -24,7 +23,7 @@ from docutils import nodes
from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment.adapters.asset import ImageAdapter from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.util import i18n, path_stabilize, logging, status_iterator 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.i18n import find_catalog
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \ from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
@ -79,8 +78,7 @@ class Builder(object):
self.confdir = app.confdir self.confdir = app.confdir
self.outdir = app.outdir self.outdir = app.outdir
self.doctreedir = app.doctreedir self.doctreedir = app.doctreedir
if not path.isdir(self.doctreedir): ensuredir(self.doctreedir)
os.makedirs(self.doctreedir)
self.app = app # type: Sphinx self.app = app # type: Sphinx
self.env = None # type: BuildEnvironment self.env = None # type: BuildEnvironment

View File

@ -274,7 +274,7 @@ class StandaloneHTMLBuilder(Builder):
# type: () -> Iterator[unicode] # type: () -> Iterator[unicode]
cfgdict = dict((confval.name, confval.value) for confval in self.config.filter('html')) cfgdict = dict((confval.name, confval.value) for confval in self.config.filter('html'))
self.config_hash = get_stable_hash(cfgdict) self.config_hash = get_stable_hash(cfgdict)
self.tags_hash = get_stable_hash(sorted(self.tags)) # type: ignore self.tags_hash = get_stable_hash(sorted(self.tags))
old_config_hash = old_tags_hash = '' old_config_hash = old_tags_hash = ''
try: try:
with open(path.join(self.outdir, '.buildinfo')) as fp: with open(path.join(self.outdir, '.buildinfo')) as fp:

View File

@ -269,7 +269,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
link = node['refuri'] link = node['refuri']
title = htmlescape(node.astext()).replace('"', '&quot;') title = htmlescape(node.astext()).replace('"', '&quot;')
item = section_template % {'title': title, 'ref': link} item = section_template % {'title': title, 'ref': link}
item = u' ' * 4 * indentlevel + item # type: ignore item = u' ' * 4 * indentlevel + item
parts.append(item.encode('ascii', 'xmlcharrefreplace')) parts.append(item.encode('ascii', 'xmlcharrefreplace'))
elif isinstance(node, nodes.bullet_list): elif isinstance(node, nodes.bullet_list):
for subnode in node: for subnode in node:

View File

@ -36,7 +36,7 @@ from six.moves.urllib.parse import quote as urlquote
from docutils.utils import column_width from docutils.utils import column_width
from sphinx import __display_version__, package_dir 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 from sphinx.util.console import ( # type: ignore
purple, bold, red, turquoise, nocolor, color_terminal purple, bold, red, turquoise, nocolor, color_terminal
) )
@ -79,13 +79,6 @@ DEFAULTS = {
PROMPT_PREFIX = '> ' 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 # function to get input from terminal -- overridden by the test suite
def term_input(prompt): def term_input(prompt):
# type: (unicode) -> unicode # type: (unicode) -> unicode
@ -413,11 +406,11 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'") d[key + '_str'] = d[key].replace('\\', '\\\\').replace("'", "\\'")
if not path.isdir(d['path']): 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'] srcdir = d['sep'] and path.join(d['path'], 'source') or d['path']
mkdir_p(srcdir) ensuredir(srcdir)
if d['sep']: if d['sep']:
builddir = path.join(d['path'], 'build') builddir = path.join(d['path'], 'build')
d['exclude_patterns'] = '' d['exclude_patterns'] = ''
@ -428,9 +421,9 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
'Thumbs.db', '.DS_Store', 'Thumbs.db', '.DS_Store',
]) ])
d['exclude_patterns'] = ', '.join(exclude_patterns) d['exclude_patterns'] = ', '.join(exclude_patterns)
mkdir_p(builddir) ensuredir(builddir)
mkdir_p(path.join(srcdir, d['dot'] + 'templates')) ensuredir(path.join(srcdir, d['dot'] + 'templates'))
mkdir_p(path.join(srcdir, d['dot'] + 'static')) ensuredir(path.join(srcdir, d['dot'] + 'static'))
def write_file(fpath, content, newline=None): def write_file(fpath, content, newline=None):
# type: (unicode, unicode, unicode) -> None # type: (unicode, unicode, unicode) -> None
@ -586,7 +579,7 @@ Makefile to be used with sphinx-build.
dest='batchfile', dest='batchfile',
help='do not create batchfile') help='do not create batchfile')
group.add_argument('-m', '--use-make-mode', action='store_true', group.add_argument('-m', '--use-make-mode', action='store_true',
dest='make_mode', dest='make_mode', default=True,
help='use make-mode for Makefile/make.bat') help='use make-mode for Makefile/make.bat')
group.add_argument('-M', '--no-use-make-mode', action='store_false', group.add_argument('-M', '--no-use-make-mode', action='store_false',
dest='make_mode', dest='make_mode',

View File

@ -291,7 +291,7 @@ class Config(object):
logger.warning("%s", exc) logger.warning("%s", exc)
for name in config: for name in config:
if name in self.values: if name in self.values:
self.__dict__[name] = config[name] self.__dict__[name] = config[name] # type: ignore
if isinstance(self.source_suffix, string_types): # type: ignore if isinstance(self.source_suffix, string_types): # type: ignore
self.source_suffix = [self.source_suffix] # type: ignore self.source_suffix = [self.source_suffix] # type: ignore

View File

@ -573,7 +573,7 @@ class ASTBase(UnicodeMixin):
if type(self) is not type(other): if type(self) is not type(other):
return False return False
try: try:
for key, value in iteritems(self.__dict__): # type: ignore for key, value in iteritems(self.__dict__):
if value != getattr(other, key): if value != getattr(other, key):
return False return False
except AttributeError: except AttributeError:

View File

@ -262,7 +262,7 @@ class TocTreeCollector(EnvironmentCollector):
continue continue
figtype = env.get_domain('std').get_figtype(subnode) # type: ignore figtype = env.get_domain('std').get_figtype(subnode)
if figtype and subnode['ids']: if figtype and subnode['ids']:
register_fignumber(docname, secnum, figtype, subnode) register_fignumber(docname, secnum, figtype, subnode)

View File

@ -27,7 +27,7 @@ from fnmatch import fnmatch
from sphinx import __display_version__ from sphinx import __display_version__
from sphinx.cmd.quickstart import EXTENSIONS from sphinx.cmd.quickstart import EXTENSIONS
from sphinx.util import rst from sphinx.util import rst
from sphinx.util.osutil import FileAvoidWrite, walk from sphinx.util.osutil import FileAvoidWrite, ensuredir, walk
if False: if False:
# For type annotation # For type annotation
@ -382,8 +382,8 @@ def main(argv=sys.argv[1:]):
if not path.isdir(rootpath): if not path.isdir(rootpath):
print('%s is not a directory.' % rootpath, file=sys.stderr) print('%s is not a directory.' % rootpath, file=sys.stderr)
sys.exit(1) sys.exit(1)
if not path.isdir(args.destdir) and not args.dryrun: if not args.dryrun:
os.makedirs(args.destdir) ensuredir(args.destdir)
excludes = [path.abspath(exclude) for exclude in args.exclude_pattern] excludes = [path.abspath(exclude) for exclude in args.exclude_pattern]
modules = recurse_tree(rootpath, excludes, args) modules = recurse_tree(rootpath, excludes, args)

View File

@ -10,9 +10,11 @@
""" """
import typing import typing
import warnings
from six import StringIO, string_types from six import StringIO, string_types
from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.util.inspect import object_description from sphinx.util.inspect import object_description
if False: if False:
@ -29,6 +31,9 @@ def format_annotation(annotation):
Displaying complex types from ``typing`` relies on its private API. Displaying complex types from ``typing`` relies on its private API.
""" """
warnings.warn('format_annotation() is now deprecated. '
'Please use sphinx.util.inspect.Signature instead.',
RemovedInSphinx20Warning)
if isinstance(annotation, typing.TypeVar): # type: ignore if isinstance(annotation, typing.TypeVar): # type: ignore
return annotation.__name__ return annotation.__name__
if annotation == Ellipsis: if annotation == Ellipsis:
@ -65,7 +70,7 @@ def format_annotation(annotation):
elif (hasattr(typing, 'UnionMeta') and elif (hasattr(typing, 'UnionMeta') and
isinstance(annotation, typing.UnionMeta) and # type: ignore isinstance(annotation, typing.UnionMeta) and # type: ignore
hasattr(annotation, '__union_params__')): hasattr(annotation, '__union_params__')):
params = annotation.__union_params__ # type: ignore params = annotation.__union_params__
if params is not None: if params is not None:
param_str = ', '.join(format_annotation(p) for p in params) param_str = ', '.join(format_annotation(p) for p in params)
return '%s[%s]' % (qualified_name, param_str) return '%s[%s]' % (qualified_name, param_str)
@ -74,7 +79,7 @@ def format_annotation(annotation):
getattr(annotation, '__args__', None) is not None and getattr(annotation, '__args__', None) is not None and
hasattr(annotation, '__result__')): hasattr(annotation, '__result__')):
# Skipped in the case of plain typing.Callable # Skipped in the case of plain typing.Callable
args = annotation.__args__ # type: ignore args = annotation.__args__
if args is None: if args is None:
return qualified_name return qualified_name
elif args is Ellipsis: elif args is Ellipsis:
@ -84,15 +89,15 @@ def format_annotation(annotation):
args_str = '[%s]' % ', '.join(formatted_args) args_str = '[%s]' % ', '.join(formatted_args)
return '%s[%s, %s]' % (qualified_name, return '%s[%s, %s]' % (qualified_name,
args_str, args_str,
format_annotation(annotation.__result__)) # type: ignore format_annotation(annotation.__result__))
elif (hasattr(typing, 'TupleMeta') and elif (hasattr(typing, 'TupleMeta') and
isinstance(annotation, typing.TupleMeta) and # type: ignore isinstance(annotation, typing.TupleMeta) and # type: ignore
hasattr(annotation, '__tuple_params__') and hasattr(annotation, '__tuple_params__') and
hasattr(annotation, '__tuple_use_ellipsis__')): hasattr(annotation, '__tuple_use_ellipsis__')):
params = annotation.__tuple_params__ # type: ignore params = annotation.__tuple_params__
if params is not None: if params is not None:
param_strings = [format_annotation(p) for p in params] param_strings = [format_annotation(p) for p in params]
if annotation.__tuple_use_ellipsis__: # type: ignore if annotation.__tuple_use_ellipsis__:
param_strings.append('...') param_strings.append('...')
return '%s[%s]' % (qualified_name, return '%s[%s]' % (qualified_name,
', '.join(param_strings)) ', '.join(param_strings))
@ -107,6 +112,9 @@ def formatargspec(function, args, varargs=None, varkw=None, defaults=None,
An enhanced version of ``inspect.formatargspec()`` that handles typing An enhanced version of ``inspect.formatargspec()`` that handles typing
annotations better. annotations better.
""" """
warnings.warn('formatargspec() is now deprecated. '
'Please use sphinx.util.inspect.Signature instead.',
RemovedInSphinx20Warning)
def format_arg_with_annotation(name): def format_arg_with_annotation(name):
# type: (str) -> str # type: (str) -> str

View File

@ -194,7 +194,7 @@ class GoogleDocstring(UnicodeMixin):
line = self._line_iter.peek() line = self._line_iter.peek()
while(not self._is_section_break() and while(not self._is_section_break() and
(not line or self._is_indented(line, indent))): (not line or self._is_indented(line, indent))):
lines.append(next(self._line_iter)) # type: ignore lines.append(next(self._line_iter))
line = self._line_iter.peek() line = self._line_iter.peek()
return lines return lines
@ -204,7 +204,7 @@ class GoogleDocstring(UnicodeMixin):
while (self._line_iter.has_next() and while (self._line_iter.has_next() and
self._line_iter.peek() and self._line_iter.peek() and
not self._is_section_header()): not self._is_section_header()):
lines.append(next(self._line_iter)) # type: ignore lines.append(next(self._line_iter))
return lines return lines
def _consume_empty(self): def _consume_empty(self):
@ -212,13 +212,13 @@ class GoogleDocstring(UnicodeMixin):
lines = [] lines = []
line = self._line_iter.peek() line = self._line_iter.peek()
while self._line_iter.has_next() and not line: while self._line_iter.has_next() and not line:
lines.append(next(self._line_iter)) # type: ignore lines.append(next(self._line_iter))
line = self._line_iter.peek() line = self._line_iter.peek()
return lines return lines
def _consume_field(self, parse_type=True, prefer_type=False): def _consume_field(self, parse_type=True, prefer_type=False):
# type: (bool, bool) -> Tuple[unicode, unicode, List[unicode]] # type: (bool, bool) -> Tuple[unicode, unicode, List[unicode]]
line = next(self._line_iter) # type: ignore line = next(self._line_iter)
before, colon, after = self._partition_field_on_colon(line) before, colon, after = self._partition_field_on_colon(line)
_name, _type, _desc = before, '', after # type: unicode, unicode, unicode _name, _type, _desc = before, '', after # type: unicode, unicode, unicode
@ -250,7 +250,7 @@ class GoogleDocstring(UnicodeMixin):
def _consume_inline_attribute(self): def _consume_inline_attribute(self):
# type: () -> Tuple[unicode, List[unicode]] # type: () -> Tuple[unicode, List[unicode]]
line = next(self._line_iter) # type: ignore line = next(self._line_iter)
_type, colon, _desc = self._partition_field_on_colon(line) _type, colon, _desc = self._partition_field_on_colon(line)
if not colon: if not colon:
_type, _desc = _desc, _type _type, _desc = _desc, _type
@ -285,7 +285,7 @@ class GoogleDocstring(UnicodeMixin):
def _consume_section_header(self): def _consume_section_header(self):
# type: () -> unicode # type: () -> unicode
section = next(self._line_iter) # type: ignore section = next(self._line_iter)
stripped_section = section.strip(':') stripped_section = section.strip(':')
if stripped_section.lower() in self._sections: if stripped_section.lower() in self._sections:
section = stripped_section section = stripped_section
@ -295,7 +295,7 @@ class GoogleDocstring(UnicodeMixin):
# type: () -> List[unicode] # type: () -> List[unicode]
lines = [] lines = []
while self._line_iter.has_next(): while self._line_iter.has_next():
lines.append(next(self._line_iter)) # type: ignore lines.append(next(self._line_iter))
return lines return lines
def _consume_to_next_section(self): def _consume_to_next_section(self):
@ -303,7 +303,7 @@ class GoogleDocstring(UnicodeMixin):
self._consume_empty() self._consume_empty()
lines = [] lines = []
while not self._is_section_break(): while not self._is_section_break():
lines.append(next(self._line_iter)) # type: ignore lines.append(next(self._line_iter))
return lines + self._consume_empty() return lines + self._consume_empty()
def _dedent(self, lines, full=False): def _dedent(self, lines, full=False):
@ -886,7 +886,7 @@ class NumpyDocstring(GoogleDocstring):
def _consume_field(self, parse_type=True, prefer_type=False): def _consume_field(self, parse_type=True, prefer_type=False):
# type: (bool, bool) -> Tuple[unicode, unicode, List[unicode]] # type: (bool, bool) -> Tuple[unicode, unicode, List[unicode]]
line = next(self._line_iter) # type: ignore line = next(self._line_iter)
if parse_type: if parse_type:
_name, _, _type = self._partition_field_on_colon(line) _name, _, _type = self._partition_field_on_colon(line)
else: else:
@ -907,10 +907,10 @@ class NumpyDocstring(GoogleDocstring):
def _consume_section_header(self): def _consume_section_header(self):
# type: () -> unicode # type: () -> unicode
section = next(self._line_iter) # type: ignore section = next(self._line_iter)
if not _directive_regex.match(section): if not _directive_regex.match(section):
# Consume the header underline # Consume the header underline
next(self._line_iter) # type: ignore next(self._line_iter)
return section return section
def _is_section_break(self): def _is_section_break(self):

View File

@ -36,11 +36,11 @@ class ModuleAnalyzer(object):
if ('file', filename) in cls.cache: if ('file', filename) in cls.cache:
return cls.cache['file', filename] return cls.cache['file', filename]
try: try:
fileobj = open(filename, 'rb') with open(filename, 'rb') as f:
obj = cls(f, modname, filename)
cls.cache['file', filename] = obj
except Exception as err: except Exception as err:
raise PycodeError('error opening %r' % filename, err) raise PycodeError('error opening %r' % filename, err)
obj = cls(fileobj, modname, filename)
cls.cache['file', filename] = obj
return obj return obj
@classmethod @classmethod

View File

@ -136,8 +136,8 @@ class BuildDoc(Command):
# type: () -> None # type: () -> None
if self.source_dir is None: if self.source_dir is None:
self.source_dir = self._guess_source_dir() self.source_dir = self._guess_source_dir()
self.announce('Using source directory %s' % self.source_dir) # type: ignore self.announce('Using source directory %s' % self.source_dir)
self.ensure_dirname('source_dir') # type: ignore self.ensure_dirname('source_dir')
if self.source_dir is None: if self.source_dir is None:
self.source_dir = os.curdir self.source_dir = os.curdir
self.source_dir = abspath(self.source_dir) self.source_dir = abspath(self.source_dir)
@ -145,10 +145,10 @@ class BuildDoc(Command):
self.config_dir = self.source_dir self.config_dir = self.source_dir
self.config_dir = abspath(self.config_dir) self.config_dir = abspath(self.config_dir)
self.ensure_string_list('builder') # type: ignore self.ensure_string_list('builder')
if self.build_dir is None: if self.build_dir is None:
build = self.get_finalized_command('build') # type: ignore build = self.get_finalized_command('build')
self.build_dir = os.path.join(abspath(build.build_base), 'sphinx') self.build_dir = os.path.join(abspath(build.build_base), 'sphinx') # type: ignore
self.mkpath(self.build_dir) # type: ignore self.mkpath(self.build_dir) # type: ignore
self.build_dir = abspath(self.build_dir) self.build_dir = abspath(self.build_dir)
self.doctree_dir = os.path.join(self.build_dir, 'doctrees') self.doctree_dir = os.path.join(self.build_dir, 'doctrees')

View File

@ -14,6 +14,10 @@ from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.transforms import SphinxTransform from sphinx.transforms import SphinxTransform
if False:
# For type annotation
from typing import List # NOQA
class RefOnlyListChecker(nodes.GenericNodeVisitor): class RefOnlyListChecker(nodes.GenericNodeVisitor):
"""Raise `nodes.NodeFound` if non-simple list item is encountered. """Raise `nodes.NodeFound` if non-simple list item is encountered.
@ -32,7 +36,7 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
def visit_list_item(self, node): def visit_list_item(self, node):
# type: (nodes.Node) -> None # type: (nodes.Node) -> None
children = [] children = [] # type: List[nodes.Node]
for child in node.children: for child in node.children:
if not isinstance(child, nodes.Invisible): if not isinstance(child, nodes.Invisible):
children.append(child) children.append(child)

View File

@ -398,10 +398,8 @@ def parselinenos(spec, total):
elif len(begend) == 1: elif len(begend) == 1:
items.append(int(begend[0]) - 1) items.append(int(begend[0]) - 1)
elif len(begend) == 2: elif len(begend) == 2:
start = int(begend[0] or 1) # type: ignore start = int(begend[0] or 1) # left half open (cf. -10)
# left half open (cf. -10) end = int(begend[1] or max(start, total)) # right half open (cf. 10-)
end = int(begend[1] or max(start, total)) # type: ignore
# right half open (cf. 10-)
if start > end: # invalid range (cf. 10-1) if start > end: # invalid range (cf. 10-1)
raise ValueError raise ValueError
items.extend(range(start - 1, end)) items.extend(range(start - 1, end))
@ -528,7 +526,7 @@ class PeekableIterator(object):
def peek(self): def peek(self):
# type: () -> Any # type: () -> Any
"""Return the next item without changing the state of the iterator.""" """Return the next item without changing the state of the iterator."""
item = next(self) # type: ignore item = next(self)
self.push(item) self.push(item)
return item return item

View File

@ -434,7 +434,7 @@ class Signature(object):
elif (hasattr(typing, 'UnionMeta') and # for py35 or below elif (hasattr(typing, 'UnionMeta') and # for py35 or below
isinstance(annotation, typing.UnionMeta) and # type: ignore isinstance(annotation, typing.UnionMeta) and # type: ignore
hasattr(annotation, '__union_params__')): hasattr(annotation, '__union_params__')):
params = annotation.__union_params__ # type: ignore params = annotation.__union_params__
if params is not None: if params is not None:
param_str = ', '.join(self.format_annotation(p) for p in params) param_str = ', '.join(self.format_annotation(p) for p in params)
return '%s[%s]' % (qualified_name, param_str) return '%s[%s]' % (qualified_name, param_str)
@ -442,7 +442,7 @@ class Signature(object):
getattr(annotation, '__args__', None) is not None and getattr(annotation, '__args__', None) is not None and
hasattr(annotation, '__result__')): hasattr(annotation, '__result__')):
# Skipped in the case of plain typing.Callable # Skipped in the case of plain typing.Callable
args = annotation.__args__ # type: ignore args = annotation.__args__
if args is None: if args is None:
return qualified_name return qualified_name
elif args is Ellipsis: elif args is Ellipsis:
@ -452,14 +452,14 @@ class Signature(object):
args_str = '[%s]' % ', '.join(formatted_args) args_str = '[%s]' % ', '.join(formatted_args)
return '%s[%s, %s]' % (qualified_name, return '%s[%s, %s]' % (qualified_name,
args_str, args_str,
self.format_annotation(annotation.__result__)) # type: ignore # NOQA self.format_annotation(annotation.__result__))
elif (isinstance(annotation, typing.TupleMeta) and # type: ignore elif (isinstance(annotation, typing.TupleMeta) and # type: ignore
hasattr(annotation, '__tuple_params__') and hasattr(annotation, '__tuple_params__') and
hasattr(annotation, '__tuple_use_ellipsis__')): hasattr(annotation, '__tuple_use_ellipsis__')):
params = annotation.__tuple_params__ # type: ignore params = annotation.__tuple_params__
if params is not None: if params is not None:
param_strings = [self.format_annotation(p) for p in params] param_strings = [self.format_annotation(p) for p in params]
if annotation.__tuple_use_ellipsis__: # type: ignore if annotation.__tuple_use_ellipsis__:
param_strings.append('...') param_strings.append('...')
return '%s[%s]' % (qualified_name, return '%s[%s]' % (qualified_name,
', '.join(param_strings)) ', '.join(param_strings))

View File

@ -156,8 +156,8 @@ class NewLineStreamHandlerPY2(logging.StreamHandler):
# remove return code forcely when nonl=True # remove return code forcely when nonl=True
self.stream = StringIO() self.stream = StringIO()
super(NewLineStreamHandlerPY2, self).emit(record) super(NewLineStreamHandlerPY2, self).emit(record)
stream.write(self.stream.getvalue()[:-1]) # type: ignore stream.write(self.stream.getvalue()[:-1])
stream.flush() # type: ignore stream.flush()
else: else:
super(NewLineStreamHandlerPY2, self).emit(record) super(NewLineStreamHandlerPY2, self).emit(record)
finally: finally:

View File

@ -8,12 +8,20 @@
""" """
import os import os
import sys
import pytest import pytest
from sphinx.testing.path import path from sphinx.testing.path import path
pytest_plugins = 'sphinx.testing.fixtures' pytest_plugins = 'sphinx.testing.fixtures'
# Exclude 'roots' dirs for pytest test collector
collect_ignore = ['roots']
# Disable Python version-specific
if sys.version_info < (3, 5):
collect_ignore += ['py35']
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def rootdir(): def rootdir():

View File

@ -0,0 +1,5 @@
File with UTF-8 BOM
===================
This file has a UTF-8 "BOM".

View File

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
master_doc = 'index'
latex_documents = [
(master_doc, 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
]

View File

@ -0,0 +1,6 @@
The basic Sphinx documentation for testing
==========================================
.. toctree::
bom

View File

@ -1 +0,0 @@
This whole directory is there to test html_static_path.

View File

@ -1 +0,0 @@
/* This file should be excluded from being copied over */

View File

@ -1 +0,0 @@
/* Stub file */

View File

@ -29,16 +29,11 @@ numfig = True
rst_epilog = '.. |subst| replace:: global substitution' rst_epilog = '.. |subst| replace:: global substitution'
html_theme = 'testtheme'
html_theme_path = ['.']
html_theme_options = {'testopt': 'testoverride'}
html_sidebars = {'**': ['localtoc.html', 'relations.html', 'sourcelink.html', html_sidebars = {'**': ['localtoc.html', 'relations.html', 'sourcelink.html',
'customsb.html', 'searchbox.html'], 'customsb.html', 'searchbox.html'],
'contents': ['contentssb.html', 'localtoc.html', 'contents': ['contentssb.html', 'localtoc.html',
'globaltoc.html']} 'globaltoc.html']}
html_style = 'default.css' html_style = 'default.css'
html_static_path = ['_static', 'templated.css_t']
html_extra_path = ['robots.txt']
html_last_updated_fmt = '%b %d, %Y' html_last_updated_fmt = '%b %d, %Y'
html_context = {'hckey': 'hcval', 'hckey_co': 'wrong_hcval_co'} html_context = {'hckey': 'hcval', 'hckey_co': 'wrong_hcval_co'}

View File

@ -1,2 +0,0 @@
User-agent: *
Disallow: /cgi-bin/

View File

@ -1,9 +0,0 @@
#, fuzzy
msgid ""
msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Including in subdir"
msgstr "translation"

View File

@ -1,2 +0,0 @@
/* Stub file, templated */
{{ sphinx_version }}

View File

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 120 B

View File

@ -55,14 +55,5 @@ os.makedirs(tempdir)
print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0]) print('Running Sphinx test suite (with Python %s)...' % sys.version.split()[0])
sys.stdout.flush() sys.stdout.flush()
# exclude 'roots' dirs for pytest test collector
ignore_paths = [
os.path.relpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), sub))
for sub in ('roots',)
]
args = sys.argv[1:]
for ignore_path in ignore_paths:
args.extend(['--ignore', ignore_path])
import pytest # NOQA import pytest # NOQA
sys.exit(pytest.main(args)) sys.exit(pytest.main(sys.argv[1:]))

View File

@ -1108,53 +1108,3 @@ class EnumCls(enum.Enum):
val2 = 23 #: doc for val2 val2 = 23 #: doc for val2
val3 = 34 val3 = 34
"""doc for val3""" """doc for val3"""
def test_type_hints():
from sphinx.ext.autodoc import formatargspec
from sphinx.util.inspect import getargspec
try:
from typing_test_data import f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11
except (ImportError, SyntaxError):
pytest.skip('Cannot import Python code with function annotations')
def verify_arg_spec(f, expected):
assert formatargspec(f, *getargspec(f)) == expected
# Class annotations
verify_arg_spec(f0, '(x: int, y: numbers.Integral) -> None')
# Generic types with concrete parameters
verify_arg_spec(f1, '(x: typing.List[int]) -> typing.List[int]')
# TypeVars and generic types with TypeVars
verify_arg_spec(f2, '(x: typing.List[T],'
' y: typing.List[T_co],'
' z: T) -> typing.List[T_contra]')
# Union types
verify_arg_spec(f3, '(x: typing.Union[str, numbers.Integral]) -> None')
# Quoted annotations
verify_arg_spec(f4, '(x: str, y: str) -> None')
# Keyword-only arguments
verify_arg_spec(f5, '(x: int, *, y: str, z: str) -> None')
# Keyword-only arguments with varargs
verify_arg_spec(f6, '(x: int, *args, y: str, z: str) -> None')
# Space around '=' for defaults
verify_arg_spec(f7, '(x: int = None, y: dict = {}) -> None')
# Callable types
verify_arg_spec(f8, '(x: typing.Callable[[int, str], int]) -> None')
verify_arg_spec(f9, '(x: typing.Callable) -> None')
# Tuple types
verify_arg_spec(f10, '(x: typing.Tuple[int, str],'
' y: typing.Tuple[int, ...]) -> None')
# Instance annotations
verify_arg_spec(f11, '(x: CustomAnnotation, y: 123) -> None')

View File

@ -59,13 +59,14 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
return srcdir return srcdir
# note: this test skips building docs for some builders because they have independent testcase.
# (html, latex, texinfo and manpage)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"buildername", "buildername",
[ [
# note: no 'html' - if it's ok with dirhtml it's ok with html # note: no 'html' - if it's ok with dirhtml it's ok with html
'dirhtml', 'singlehtml', 'latex', 'texinfo', 'pickle', 'json', 'text', 'dirhtml', 'singlehtml', 'pickle', 'json', 'text', 'htmlhelp', 'qthelp',
'htmlhelp', 'qthelp', 'epub', 'applehelp', 'changes', 'xml', 'epub', 'applehelp', 'changes', 'xml', 'pseudoxml', 'linkcheck',
'pseudoxml', 'man', 'linkcheck',
], ],
) )
@mock.patch('sphinx.builders.linkcheck.requests.head', @mock.patch('sphinx.builders.linkcheck.requests.head',

View File

@ -126,24 +126,6 @@ def check_xpath(etree, fname, path, check, be_found=True):
[node.text for node in nodes])) [node.text for node in nodes]))
def check_static_entries(outdir):
staticdir = outdir / '_static'
assert staticdir.isdir()
# a file from a directory entry in html_static_path
assert (staticdir / 'README').isfile()
# a directory from a directory entry in html_static_path
assert (staticdir / 'subdir' / 'foo.css').isfile()
# a file from a file entry in html_static_path
assert (staticdir / 'templated.css').isfile()
assert (staticdir / 'templated.css').text().splitlines()[1] == __display_version__
# a file from _static, but matches exclude_patterns
assert not (staticdir / 'excluded.css').exists()
def check_extra_entries(outdir):
assert (outdir / 'robots.txt').isfile()
@pytest.mark.sphinx('html', testroot='warnings') @pytest.mark.sphinx('html', testroot='warnings')
def test_html_warnings(app, warning): def test_html_warnings(app, warning):
app.build() app.build()
@ -156,15 +138,6 @@ def test_html_warnings(app, warning):
'--- Got:\n' + html_warnings '--- Got:\n' + html_warnings
@pytest.mark.sphinx('html', tags=['testtag'], confoverrides={
'html_context.hckey_co': 'hcval_co'})
@pytest.mark.test_params(shared_result='test_build_html_output')
def test_static_output(app):
app.build()
check_static_entries(app.builder.outdir)
check_extra_entries(app.builder.outdir)
@pytest.mark.parametrize("fname,expect", flat_dict({ @pytest.mark.parametrize("fname,expect", flat_dict({
'images.html': [ 'images.html': [
(".//img[@src='_images/img.png']", ''), (".//img[@src='_images/img.png']", ''),
@ -377,7 +350,6 @@ def test_static_output(app):
'contents.html': [ 'contents.html': [
(".//meta[@name='hc'][@content='hcval']", ''), (".//meta[@name='hc'][@content='hcval']", ''),
(".//meta[@name='hc_co'][@content='hcval_co']", ''), (".//meta[@name='hc_co'][@content='hcval_co']", ''),
(".//meta[@name='testopt'][@content='testoverride']", ''),
(".//td[@class='label']", r'\[Ref1\]'), (".//td[@class='label']", r'\[Ref1\]'),
(".//td[@class='label']", ''), (".//td[@class='label']", ''),
(".//li[@class='toctree-l1']/a", 'Testing various markup'), (".//li[@class='toctree-l1']/a", 'Testing various markup'),
@ -410,9 +382,6 @@ def test_static_output(app):
(".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"), (".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"),
(".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"), (".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"),
], ],
'_static/statictmpl.html': [
(".//project", 'Sphinx <Tests>'),
],
'genindex.html': [ 'genindex.html': [
# index entries # index entries
(".//a/strong", "Main"), (".//a/strong", "Main"),
@ -1145,16 +1114,28 @@ def test_html_assets(app):
assert not (app.outdir / 'subdir' / '.htpasswd').exists() assert not (app.outdir / 'subdir' / '.htpasswd').exists()
@pytest.mark.sphinx('html', confoverrides={'html_sourcelink_suffix': ''}) @pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_copy_source': False})
def test_html_copy_source(app):
app.builder.build_all()
assert not (app.outdir / '_sources' / 'index.rst.txt').exists()
@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': '.txt'})
def test_html_sourcelink_suffix(app): def test_html_sourcelink_suffix(app):
app.builder.build_all() app.builder.build_all()
content_otherext = (app.outdir / 'otherext.html').text() assert (app.outdir / '_sources' / 'index.rst.txt').exists()
content_images = (app.outdir / 'images.html').text()
assert '<a href="_sources/otherext.foo"' in content_otherext
assert '<a href="_sources/images.txt"' in content_images @pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': '.rst'})
assert (app.outdir / '_sources' / 'otherext.foo').exists() def test_html_sourcelink_suffix_same(app):
assert (app.outdir / '_sources' / 'images.txt').exists() app.builder.build_all()
assert (app.outdir / '_sources' / 'index.rst').exists()
@pytest.mark.sphinx('html', testroot='basic', confoverrides={'html_sourcelink_suffix': ''})
def test_html_sourcelink_suffix_empty(app):
app.builder.build_all()
assert (app.outdir / '_sources' / 'index.rst').exists()
@pytest.mark.sphinx('html', testroot='html_entity') @pytest.mark.sphinx('html', testroot='html_entity')

View File

@ -251,7 +251,6 @@ def cached_etree_parse():
'contents.html': [ 'contents.html': [
(".//meta[@name='hc'][@content='hcval']", ''), (".//meta[@name='hc'][@content='hcval']", ''),
(".//meta[@name='hc_co'][@content='hcval_co']", ''), (".//meta[@name='hc_co'][@content='hcval_co']", ''),
(".//meta[@name='testopt'][@content='testoverride']", ''),
(".//dt[@class='label']/span[@class='brackets']", r'Ref1'), (".//dt[@class='label']/span[@class='brackets']", r'Ref1'),
(".//dt[@class='label']", ''), (".//dt[@class='label']", ''),
(".//li[@class='toctree-l1']/a", 'Testing various markup'), (".//li[@class='toctree-l1']/a", 'Testing various markup'),
@ -284,9 +283,6 @@ def cached_etree_parse():
(".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"), (".//a[@href='http://bugs.python.org/issue1000']", "issue 1000"),
(".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"), (".//a[@href='http://bugs.python.org/issue1042']", "explicit caption"),
], ],
'_static/statictmpl.html': [
(".//project", 'Sphinx <Tests>'),
],
'genindex.html': [ 'genindex.html': [
# index entries # index entries
(".//a/strong", "Main"), (".//a/strong", "Main"),

View File

@ -9,11 +9,25 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import os
import re import re
import subprocess
import pytest import pytest
def has_binary(binary):
try:
subprocess.check_output([binary])
except OSError as e:
if e.errno == os.errno.ENOENT:
# handle file not found error.
return False
else:
return True
return True
@pytest.mark.sphinx( @pytest.mark.sphinx(
'html', testroot='ext-math', 'html', testroot='ext-math',
confoverrides = {'extensions': ['sphinx.ext.jsmath'], 'jsmath_path': 'dummy.js'}) confoverrides = {'extensions': ['sphinx.ext.jsmath'], 'jsmath_path': 'dummy.js'})
@ -34,6 +48,8 @@ def test_jsmath(app, status, warning):
assert '<div class="math">\na + 1 &lt; b</div>' in content assert '<div class="math">\na + 1 &lt; b</div>' in content
@pytest.mark.skipif(not has_binary('dvipng'),
reason='Requires dvipng" binary')
@pytest.mark.sphinx('html', testroot='ext-math-simple', @pytest.mark.sphinx('html', testroot='ext-math-simple',
confoverrides = {'extensions': ['sphinx.ext.imgmath']}) confoverrides = {'extensions': ['sphinx.ext.imgmath']})
def test_imgmath_png(app, status, warning): def test_imgmath_png(app, status, warning):
@ -49,6 +65,8 @@ def test_imgmath_png(app, status, warning):
assert re.search(html, content, re.S) assert re.search(html, content, re.S)
@pytest.mark.skipif(not has_binary('dvisvgm'),
reason='Requires dvisvgm" binary')
@pytest.mark.sphinx('html', testroot='ext-math-simple', @pytest.mark.sphinx('html', testroot='ext-math-simple',
confoverrides={'extensions': ['sphinx.ext.imgmath'], confoverrides={'extensions': ['sphinx.ext.imgmath'],
'imgmath_image_format': 'svg'}) 'imgmath_image_format': 'svg'})

View File

@ -520,7 +520,7 @@ def test_gettext_buildr_ignores_only_directive(app):
@sphinx_intl @sphinx_intl
# use individual shared_result directory to avoid "incompatible doctree" error # use individual shared_result directory to avoid "incompatible doctree" error
@pytest.mark.test_params(shared_result='test_gettext_dont_rebuild_mo') @pytest.mark.sphinx(testroot='builder-gettext-dont-rebuild-mo')
def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo): def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo):
# --- don't rebuild by .mo mtime # --- don't rebuild by .mo mtime
def get_number_of_update_targets(app_): def get_number_of_update_targets(app_):
@ -533,7 +533,7 @@ def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo):
app0 = make_app('dummy', *args, **kwargs) app0 = make_app('dummy', *args, **kwargs)
build_mo(app0.srcdir) build_mo(app0.srcdir)
app0.build() app0.build()
assert (app0.srcdir / 'bom.mo') assert (app0.srcdir / 'xx' / 'LC_MESSAGES' / 'bom.mo').exists()
# Since it is after the build, the number of documents to be updated is 0 # Since it is after the build, the number of documents to be updated is 0
assert get_number_of_update_targets(app0) == 0 assert get_number_of_update_targets(app0) == 0
# When rewriting the timestamp of mo file, the number of documents to be # When rewriting the timestamp of mo file, the number of documents to be

View File

@ -17,6 +17,7 @@ from sphinx.theming import ThemeError
@pytest.mark.sphinx( @pytest.mark.sphinx(
testroot='theming',
confoverrides={'html_theme': 'ziptheme', confoverrides={'html_theme': 'ziptheme',
'html_theme_options.testopt': 'foo'}) 'html_theme_options.testopt': 'foo'})
def test_theme_api(app, status, warning): def test_theme_api(app, status, warning):
@ -25,10 +26,11 @@ def test_theme_api(app, status, warning):
# test Theme class API # test Theme class API
assert set(app.html_themes.keys()) == \ assert set(app.html_themes.keys()) == \
set(['basic', 'default', 'scrolls', 'agogo', 'sphinxdoc', 'haiku', set(['basic', 'default', 'scrolls', 'agogo', 'sphinxdoc', 'haiku',
'traditional', 'testtheme', 'ziptheme', 'epub', 'nature', 'traditional', 'epub', 'nature', 'pyramid', 'bizstyle', 'classic', 'nonav',
'pyramid', 'bizstyle', 'classic', 'nonav']) 'test-theme', 'ziptheme', 'staticfiles', 'parent', 'child'])
assert app.html_themes['testtheme'] == app.srcdir / 'testtheme' assert app.html_themes['test-theme'] == app.srcdir / 'test_theme' / 'test-theme'
assert app.html_themes['ziptheme'] == app.srcdir / 'ziptheme.zip' assert app.html_themes['ziptheme'] == app.srcdir / 'ziptheme.zip'
assert app.html_themes['staticfiles'] == app.srcdir / 'test_theme' / 'staticfiles'
# test Theme instance API # test Theme instance API
theme = app.builder.theme theme = app.builder.theme
@ -97,6 +99,21 @@ def test_nested_zipped_theme(app, status, warning):
app.build() # => not raises TemplateNotFound app.build() # => not raises TemplateNotFound
@pytest.mark.sphinx(testroot='theming',
confoverrides={'html_theme': 'staticfiles'})
def test_staticfiles(app, status, warning):
app.build()
assert (app.outdir / '_static' / 'staticimg.png').exists()
assert (app.outdir / '_static' / 'statictmpl.html').exists()
assert (app.outdir / '_static' / 'statictmpl.html').text() == (
'<!-- testing static templates -->\n'
'<html><project>Python</project></html>'
)
result = (app.outdir / 'index.html').text()
assert '<meta name="testopt" content="optdefault" />' in result
@pytest.mark.sphinx(testroot='theming') @pytest.mark.sphinx(testroot='theming')
def test_theme_sidebars(app, status, warning): def test_theme_sidebars(app, status, warning):
app.build() app.build()

71
tox.ini
View File

@ -1,69 +1,56 @@
[tox] [tox]
minversion=2.0 minversion = 2.0
envlist=flake8,mypy,py{27,34,35,36},pypy,du{11,12,13,14} envlist = docs,flake8,mypy,coverage,py{27,34,35,36,py},du{11,12,13,14}
[testenv] [testenv]
passenv = https_proxy http_proxy no_proxy passenv =
https_proxy http_proxy no_proxy
description =
py{27,34,35,36,py}: Run unit tests against {envname}.
du{11,12,13,14}: Run unit tests with the given version of docutils.
coverage: Run code coverage checks.
# TODO(stephenfin) Replace this with the 'extras' config option when tox 2.4 is # TODO(stephenfin) Replace this with the 'extras' config option when tox 2.4 is
# widely available, likely some time after the Ubuntu 18.04 release # widely available, likely some time after the Ubuntu 18.04 release
# #
# https://tox.readthedocs.io/en/latest/config.html#confval-extras=MULTI-LINE-LIST # https://tox.readthedocs.io/en/latest/config.html#confval-extras=MULTI-LINE-LIST
deps = deps =
.[test,websupport] .[test,websupport]
du11: docutils==0.11
du12: docutils==0.12
du13: docutils==0.13.1
du14: docutils==0.14
setenv = setenv =
SPHINX_TEST_TEMPDIR = {envdir}/testbuild SPHINX_TEST_TEMPDIR = {envdir}/testbuild
coverage: PYTEST_ADDOPTS = --cov sphinx
commands= commands=
{envpython} -Wall tests/run.py --ignore tests/py35 --cov=sphinx \ {envpython} -Wall tests/run.py --durations 25 {posargs}
--durations 25 {posargs}
sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
[testenv:du11]
deps=
docutils==0.11
{[testenv]deps}
[testenv:du12]
deps=
docutils==0.12
{[testenv]deps}
[testenv:du13]
deps=
docutils==0.13.1
{[testenv]deps}
[testenv:du14]
deps=
docutils==0.14
{[testenv]deps}
[testenv:flake8] [testenv:flake8]
deps=flake8 description =
commands=flake8 Run style checks.
commands =
flake8
[testenv:pylint] [testenv:pylint]
deps= description =
Run source code analyzer.
deps =
pylint pylint
{[testenv]deps} {[testenv]deps}
commands= commands =
pylint --rcfile utils/pylintrc sphinx pylint --rcfile utils/pylintrc sphinx
[testenv:py27]
deps=
{[testenv]deps}
[testenv:py35]
commands=
{envpython} -Wall tests/run.py --cov=sphinx --durations 25 {posargs}
sphinx-build -q -W -b html -d {envtmpdir}/doctrees doc {envtmpdir}/html
[testenv:mypy] [testenv:mypy]
basepython=python3 description =
deps= Run type checks.
deps =
mypy mypy
commands= commands=
mypy sphinx/ mypy sphinx/
[testenv:docs] [testenv:docs]
commands= description =
Build documentation.
commands =
python setup.py build_sphinx {posargs} python setup.py build_sphinx {posargs}