summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml2
-rw-r--r--.travis.yml9
-rw-r--r--AUTHORS1
-rw-r--r--CHANGES54
-rw-r--r--EXAMPLES999
-rw-r--r--doc/conf.py7
-rw-r--r--doc/develop.rst2
-rw-r--r--doc/extdev/appapi.rst26
-rw-r--r--doc/extdev/envapi.rst4
-rw-r--r--doc/extdev/index.rst25
-rw-r--r--doc/faq.rst2
-rw-r--r--doc/intl.rst2
-rw-r--r--doc/intro.rst8
-rw-r--r--doc/usage/builders/index.rst11
-rw-r--r--doc/usage/configuration.rst26
-rw-r--r--doc/usage/extensions/autodoc.rst17
-rw-r--r--doc/usage/extensions/example_google.py2
-rw-r--r--doc/usage/extensions/example_numpy.py2
-rw-r--r--doc/usage/extensions/inheritance.rst2
-rw-r--r--doc/usage/extensions/math.rst2
-rw-r--r--doc/usage/extensions/napoleon.rst4
-rw-r--r--doc/usage/installation.rst13
-rw-r--r--doc/usage/markdown.rst2
-rw-r--r--setup.py24
-rw-r--r--sphinx/__init__.py52
-rw-r--r--sphinx/addnodes.py4
-rw-r--r--sphinx/apidoc.py41
-rw-r--r--sphinx/application.py97
-rw-r--r--sphinx/builders/__init__.py26
-rw-r--r--sphinx/builders/applehelp.py12
-rw-r--r--sphinx/builders/changes.py21
-rw-r--r--sphinx/builders/devhelp.py12
-rw-r--r--sphinx/builders/gettext.py8
-rw-r--r--sphinx/builders/html.py118
-rw-r--r--sphinx/builders/htmlhelp.py17
-rw-r--r--sphinx/builders/latex/__init__.py46
-rw-r--r--sphinx/builders/latex/transforms.py25
-rw-r--r--sphinx/builders/linkcheck.py4
-rw-r--r--sphinx/builders/qthelp.py7
-rw-r--r--sphinx/builders/text.py6
-rw-r--r--sphinx/builders/xml.py6
-rw-r--r--sphinx/cmd/make_mode.py2
-rw-r--r--sphinx/cmd/quickstart.py33
-rw-r--r--sphinx/config.py62
-rw-r--r--sphinx/deprecation.py6
-rw-r--r--sphinx/directives/__init__.py2
-rw-r--r--sphinx/directives/code.py6
-rw-r--r--sphinx/directives/other.py1
-rw-r--r--sphinx/domains/__init__.py10
-rw-r--r--sphinx/domains/changeset.py5
-rw-r--r--sphinx/domains/cpp.py28
-rw-r--r--sphinx/domains/python.py13
-rw-r--r--sphinx/domains/rst.py4
-rw-r--r--sphinx/domains/std.py15
-rw-r--r--sphinx/environment/__init__.py92
-rw-r--r--sphinx/environment/adapters/asset.py2
-rw-r--r--sphinx/environment/adapters/indexentries.py8
-rw-r--r--sphinx/environment/adapters/toctree.py5
-rw-r--r--sphinx/environment/collectors/__init__.py6
-rw-r--r--sphinx/environment/collectors/asset.py5
-rw-r--r--sphinx/environment/collectors/dependencies.py5
-rw-r--r--sphinx/environment/collectors/indexentries.py6
-rw-r--r--sphinx/environment/collectors/toctree.py3
-rw-r--r--sphinx/events.py8
-rw-r--r--sphinx/ext/apidoc.py4
-rw-r--r--sphinx/ext/autodoc/__init__.py179
-rw-r--r--sphinx/ext/autodoc/directive.py4
-rw-r--r--sphinx/ext/autodoc/importer.py16
-rw-r--r--sphinx/ext/autodoc/inspector.py187
-rw-r--r--sphinx/ext/autosummary/__init__.py16
-rw-r--r--sphinx/ext/autosummary/generate.py7
-rw-r--r--sphinx/ext/coverage.py10
-rw-r--r--sphinx/ext/doctest.py67
-rw-r--r--sphinx/ext/extlinks.py3
-rw-r--r--sphinx/ext/graphviz.py7
-rw-r--r--sphinx/ext/imgmath.py3
-rw-r--r--sphinx/ext/inheritance_diagram.py4
-rw-r--r--sphinx/ext/intersphinx.py28
-rw-r--r--sphinx/ext/napoleon/__init__.py65
-rw-r--r--sphinx/ext/napoleon/docstring.py67
-rw-r--r--sphinx/ext/napoleon/iterators.py2
-rw-r--r--sphinx/ext/viewcode.py6
-rw-r--r--sphinx/extension.py6
-rw-r--r--sphinx/highlighting.py2
-rw-r--r--sphinx/io.py4
-rw-r--r--sphinx/jinja2glue.py2
-rw-r--r--sphinx/locale/__init__.py9
-rw-r--r--sphinx/parsers.py2
-rw-r--r--sphinx/pycode/__init__.py7
-rw-r--r--sphinx/pycode/parser.py17
-rw-r--r--sphinx/quickstart.py41
-rw-r--r--sphinx/registry.py13
-rw-r--r--sphinx/roles.py7
-rw-r--r--sphinx/search/__init__.py22
-rw-r--r--sphinx/search/ja.py18
-rw-r--r--sphinx/templates/latex/latex.tex_t10
-rw-r--r--sphinx/templates/latex/sphinxmessages.sty_t10
-rw-r--r--sphinx/templates/quickstart/conf.py_t2
-rw-r--r--sphinx/testing/fixtures.py2
-rw-r--r--sphinx/testing/path.py15
-rw-r--r--sphinx/testing/util.py9
-rw-r--r--sphinx/themes/agogo/layout.html2
-rw-r--r--sphinx/themes/basic/opensearch.xml2
-rw-r--r--sphinx/themes/basic/searchbox.html2
-rw-r--r--sphinx/themes/basic/static/searchtools.js17
-rw-r--r--sphinx/theming.py38
-rw-r--r--sphinx/transforms/i18n.py47
-rw-r--r--sphinx/transforms/post_transforms/__init__.py34
-rw-r--r--sphinx/transforms/references.py3
-rw-r--r--sphinx/util/__init__.py14
-rw-r--r--sphinx/util/build_phase.py5
-rw-r--r--sphinx/util/compat.py24
-rw-r--r--sphinx/util/docfields.py4
-rw-r--r--sphinx/util/docutils.py7
-rw-r--r--sphinx/util/fileutil.py11
-rw-r--r--sphinx/util/i18n.py9
-rw-r--r--sphinx/util/images.py16
-rw-r--r--sphinx/util/inspect.py365
-rw-r--r--sphinx/util/inventory.py11
-rw-r--r--sphinx/util/jsdump.py4
-rw-r--r--sphinx/util/logging.py38
-rw-r--r--sphinx/util/matching.py2
-rw-r--r--sphinx/util/nodes.py58
-rw-r--r--sphinx/util/osutil.py72
-rw-r--r--sphinx/util/parallel.py8
-rw-r--r--sphinx/util/pycompat.py129
-rw-r--r--sphinx/util/stemmer/__init__.py2
-rw-r--r--sphinx/util/stemmer/porter.py4
-rw-r--r--sphinx/util/tags.py2
-rw-r--r--sphinx/util/template.py7
-rw-r--r--sphinx/util/texescape.py12
-rw-r--r--sphinx/util/typing.py9
-rw-r--r--sphinx/versioning.py8
-rw-r--r--sphinx/websupport/__init__.py28
-rw-r--r--sphinx/websupport/errors.py12
-rw-r--r--sphinx/websupport/search/__init__.py12
-rw-r--r--sphinx/websupport/search/nullsearch.py12
-rw-r--r--sphinx/websupport/search/whooshsearch.py12
-rw-r--r--sphinx/websupport/search/xapiansearch.py12
-rw-r--r--sphinx/websupport/storage/__init__.py12
-rw-r--r--sphinx/websupport/storage/differ.py12
-rw-r--r--sphinx/websupport/storage/sqlalchemy_db.py13
-rw-r--r--sphinx/websupport/storage/sqlalchemystorage.py12
-rw-r--r--sphinx/writers/latex.py53
-rw-r--r--sphinx/writers/manpage.py20
-rw-r--r--sphinx/writers/texinfo.py4
-rw-r--r--tests/conftest.py8
-rw-r--r--tests/py3/test_util_inspect_py3.py26
-rw-r--r--tests/py35/test_autodoc_py35.py348
-rw-r--r--tests/roots/test-api-set-translator/conf.py6
-rw-r--r--tests/roots/test-autosummary/index.rst (renamed from tests/roots/test-autosummary/contents.rst)0
-rw-r--r--tests/roots/test-build-text/conf.py1
-rw-r--r--tests/roots/test-build-text/index.txt (renamed from tests/roots/test-build-text/contents.txt)0
-rw-r--r--tests/roots/test-circular/index.rst (renamed from tests/roots/test-circular/contents.rst)0
-rw-r--r--tests/roots/test-circular/sub.rst2
-rw-r--r--tests/roots/test-correct-year/index.rst (renamed from tests/roots/test-correct-year/contents.rst)0
-rw-r--r--tests/roots/test-directive-only/index.rst (renamed from tests/roots/test-directive-only/contents.rst)0
-rw-r--r--tests/roots/test-docutilsconf/index.txt (renamed from tests/roots/test-docutilsconf/contents.txt)0
-rw-r--r--tests/roots/test-ext-autodoc/index.rst (renamed from tests/roots/test-ext-autodoc/contents.rst)0
-rw-r--r--tests/roots/test-ext-autodoc/target/__init__.py2
-rw-r--r--tests/roots/test-ext-autodoc/target/coroutine.py8
-rw-r--r--tests/roots/test-ext-autosummary/index.rst (renamed from tests/roots/test-ext-autosummary/contents.rst)0
-rw-r--r--tests/roots/test-gettext-template/index.rst (renamed from tests/roots/test-gettext-template/contents.rst)0
-rw-r--r--tests/roots/test-inheritance/index.rst (renamed from tests/roots/test-inheritance/contents.rst)0
-rw-r--r--tests/roots/test-intl/_templates/contents.html (renamed from tests/roots/test-intl/_templates/index.html)0
-rw-r--r--tests/roots/test-intl/conf.py2
-rw-r--r--tests/roots/test-intl/index.po (renamed from tests/roots/test-intl/contents.po)0
-rw-r--r--tests/roots/test-intl/index.txt (renamed from tests/roots/test-intl/contents.txt)2
-rw-r--r--tests/roots/test-intl/role_xref.po8
-rw-r--r--tests/roots/test-intl/role_xref.txt4
-rw-r--r--tests/roots/test-intl/subdir/index.txt (renamed from tests/roots/test-intl/subdir/contents.txt)0
-rw-r--r--tests/roots/test-numbered-circular/index.rst (renamed from tests/roots/test-numbered-circular/contents.rst)0
-rw-r--r--tests/roots/test-numbered-circular/sub.rst2
-rw-r--r--tests/roots/test-root/autodoc_target.py2
-rw-r--r--tests/roots/test-root/conf.py10
-rw-r--r--tests/roots/test-root/index.txt (renamed from tests/roots/test-root/contents.txt)0
-rw-r--r--tests/roots/test-setup/doc/index.txt (renamed from tests/roots/test-setup/doc/contents.txt)0
-rw-r--r--tests/roots/test-templating/index.txt (renamed from tests/roots/test-templating/contents.txt)0
-rw-r--r--tests/test_autodoc.py61
-rw-r--r--tests/test_build.py15
-rw-r--r--tests/test_build_applehelp.py8
-rw-r--r--tests/test_build_epub.py2
-rw-r--r--tests/test_build_html.py15
-rw-r--r--tests/test_build_html5.py4
-rw-r--r--tests/test_build_htmlhelp.py23
-rw-r--r--tests/test_build_latex.py7
-rw-r--r--tests/test_build_texinfo.py6
-rw-r--r--tests/test_build_text.py12
-rw-r--r--tests/test_builder.py4
-rw-r--r--tests/test_config.py41
-rw-r--r--tests/test_correct_year.py2
-rw-r--r--tests/test_docutilsconf.py8
-rw-r--r--tests/test_domain_cpp.py6
-rw-r--r--tests/test_ext_autodoc.py2
-rw-r--r--tests/test_ext_autosummary.py4
-rw-r--r--tests/test_ext_doctest.py4
-rw-r--r--tests/test_ext_napoleon.py2
-rw-r--r--tests/test_ext_napoleon_docstring.py99
-rw-r--r--tests/test_intl.py32
-rw-r--r--tests/test_markup.py4
-rw-r--r--tests/test_pycode.py12
-rw-r--r--tests/test_pycode_parser.py2
-rw-r--r--tests/test_quickstart.py10
-rw-r--r--tests/test_search.py4
-rw-r--r--tests/test_setup_command.py2
-rw-r--r--tests/test_templating.py2
-rw-r--r--tests/test_util_images.py2
-rw-r--r--tests/test_util_inspect.py130
-rw-r--r--tests/test_util_inventory.py3
-rw-r--r--tests/test_util_nodes.py35
-rw-r--r--tests/test_websupport.py36
-rw-r--r--tests/typing_test_data.py7
-rw-r--r--tox.ini9
-rwxr-xr-xutils/bump_version.py2
214 files changed, 1638 insertions, 3538 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index a0c948246..9da9bc56d 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -5,8 +5,6 @@ environment:
PYTHONWARNINGS: all
matrix:
- - PYTHON: 27
- TEST_IGNORE: --ignore py35
- PYTHON: 37
- PYTHON: 37-x64
diff --git a/.travis.yml b/.travis.yml
index f156d59d7..f14bf6495 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,16 +11,9 @@ env:
matrix:
include:
- - python: 'pypy'
- env: TOXENV=pypy
- - python: '2.7'
+ - python: '3.5'
env:
- TOXENV=du13
- - PYTEST_ADDOPTS="--cov ./ --cov-append --cov-config setup.cfg"
- - python: '3.4'
- env: TOXENV=py34
- - python: '3.5'
- env: TOXENV=py35
- python: '3.6'
env:
- TOXENV=py36
diff --git a/AUTHORS b/AUTHORS
index 1cbb20137..b7636c4d2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -38,6 +38,7 @@ Other contributors, listed alphabetically, are:
* Zac Hatfield-Dodds -- doctest reporting improvements
* Doug Hellmann -- graphviz improvements
* Tim Hoffmann -- theme improvements
+* Antti Kaihola -- doctest extension (skipif option)
* Dave Kuhlman -- original LaTeX writer
* Blaise Laflamme -- pyramid theme
* Chris Lamb -- reproducibility fixes
diff --git a/CHANGES b/CHANGES
index 761ed2539..5e8d7cb3b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,55 @@
+Release 2.0.0 (in development)
+==============================
+
+Dependencies
+------------
+
+* LaTeX builder now depends on TeX Live 2015 or above
+
+Incompatible changes
+--------------------
+
+* Drop python 2.7 and 3.4 support
+* Drop docutils 0.11 support
+* The default setting for :confval:`master_doc` is changed to ``'index'`` which
+ has been longly used as default of sphinx-quickstart.
+* LaTeX: Move message resources to ``sphinxmessage.sty``
+* LaTeX: Stop using ``\captions<lang>`` macro for some labels
+
+Deprecated
+----------
+
+* The ``suffix`` argument of ``env.doc2path()`` is deprecated.
+* The string style ``base`` argument of ``env.doc2path()`` is deprecated.
+* ``sphinx.ext.doctest.doctest_encode()``
+* ``sphinx.testing.util.remove_unicode_literal()``
+* ``sphinx.util.osutil.walk()``
+* ``translatablestrings`` variable for LaTeX template
+
+For more details, see `deprecation APIs list
+<http://www.sphinx-doc.org/en/master/extdev/index.html#deprecated-apis>`_
+
+Features added
+--------------
+* #1618: The search results preview of generated HTML documentation is
+ reader-friendlier: instead of showing the snippets as raw reStructuredText
+ markup, Sphinx now renders the corresponding HTML. This means the Sphinx
+ extension `Sphinx: pretty search results`__ is no longer necessary. Note that
+ changes to the search function of your custom or 3rd-pary HTML template might
+ overwrite this improvement.
+
+__ https://github.com/sphinx-contrib/sphinx-pretty-searchresults
+
+* #4182: autodoc: Support :confval:`suppress_warnings`
+* #4018: htmlhelp: Add :confval:`htmlhelp_file_suffix` and
+ :confval:`htmlhelp_link_suffix`
+
+Bugs fixed
+----------
+
+Testing
+--------
+
Release 1.8.2 (in development)
==============================
@@ -2101,7 +2153,7 @@ Incompatible changes
parsing is attempted to distinguish valid code. To get the old behavior back,
add ``highlight_language = "python"`` to conf.py.
* `Locale Date Markup Language
- <http://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns>`_ like
+ <https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns>`_ like
``"MMMM dd, YYYY"`` is default format for `today_fmt` and `html_last_updated_fmt`.
However strftime format like ``"%B %d, %Y"`` is also supported for backward
compatibility until Sphinx-1.5. Later format will be disabled from Sphinx-1.5.
diff --git a/EXAMPLES b/EXAMPLES
index 7606bcd5b..2dd0373f2 100644
--- a/EXAMPLES
+++ b/EXAMPLES
@@ -12,714 +12,385 @@ interesting examples.
Documentation using the alabaster theme
---------------------------------------
-* `Alabaster`__
-* `Blinker`__
-* `Calibre`__
-* `Click`__ (customized)
-* `coala`__ (customized)
-* `CodePy`__
-* `Fabric`__
-* `Fityk`__
-* `Flask`__
-* `Flask-OpenID`__
-* `Invoke`__
-* `Jinja`__
-* `Lino`__ (customized)
-* `marbl`__
-* `MDAnalysis`__ (customized)
-* `MeshPy`__
-* `PyCUDA`__
-* `PyOpenCL`__
-* `PyLangAcq`__
-* `pytest`__ (customized)
-* `python-apt`__
-* `PyVisfile`__
-* `Requests`__
-* `searx`__
-* `Spyder`__ (customized)
-* `Tablib`__
-* `urllib3`__ (customized)
-* `Werkzeug`__ (customized)
-
-__ https://alabaster.readthedocs.io/
-__ https://pythonhosted.org/blinker/
-__ https://manual.calibre-ebook.com/
-__ http://click.pocoo.org/
-__ https://docs.coala.io/
-__ https://documen.tician.de/codepy/
-__ http://docs.fabfile.org/
-__ http://fityk.nieto.pl/
-__ http://flask.pocoo.org/docs/
-__ https://pythonhosted.org/Flask-OpenID/
-__ http://docs.pyinvoke.org/
-__ http://jinja.pocoo.org/docs/
-__ http://www.lino-framework.org/
-__ https://getmarbl.readthedocs.io/
-__ http://www.mdanalysis.org/docs/
-__ https://documen.tician.de/meshpy/
-__ https://documen.tician.de/pycuda/
-__ https://documen.tician.de/pyopencl/
-__ http://pylangacq.org/
-__ https://docs.pytest.org/
-__ https://apt.alioth.debian.org/python-apt-doc/
-__ https://documen.tician.de/pyvisfile/
-__ http://www.python-requests.org/
-__ https://asciimoo.github.io/searx/
-__ https://docs.spyder-ide.org/
-__ http://docs.python-tablib.org/
-__ https://urllib3.readthedocs.io/
-__ http://werkzeug.pocoo.org/docs/
+* `Alabaster <https://alabaster.readthedocs.io/>`__
+* `Blinker <https://pythonhosted.org/blinker/>`__
+* `Calibre <https://manual.calibre-ebook.com/>`__
+* `Click <http://click.pocoo.org/>`__ (customized)
+* `coala <https://docs.coala.io/>`__ (customized)
+* `CodePy <https://documen.tician.de/codepy/>`__
+* `Fabric <https://docs.fabfile.org/>`__
+* `Fityk <https://fityk.nieto.pl/>`__
+* `Flask <http://flask.pocoo.org/docs/>`__
+* `Flask-OpenID <https://pythonhosted.org/Flask-OpenID/>`__
+* `Invoke <https://docs.pyinvoke.org/>`__
+* `Jinja <http://jinja.pocoo.org/docs/>`__
+* `Lino <http://www.lino-framework.org/>`__ (customized)
+* `marbl <https://getmarbl.readthedocs.io/>`__
+* `MDAnalysis <https://www.mdanalysis.org/docs/>`__ (customized)
+* `MeshPy <https://documen.tician.de/meshpy/>`__
+* `PyCUDA <https://documen.tician.de/pycuda/>`__
+* `PyOpenCL <https://documen.tician.de/pyopencl/>`__
+* `PyLangAcq <http://pylangacq.org/>`__
+* `pytest <https://docs.pytest.org/>`__ (customized)
+* `python-apt <https://apt.alioth.debian.org/python-apt-doc/>`__
+* `PyVisfile <https://documen.tician.de/pyvisfile/>`__
+* `Requests <http://www.python-requests.org/>`__
+* `searx <https://asciimoo.github.io/searx/>`__
+* `Spyder <https://docs.spyder-ide.org/>`__ (customized)
+* `Tablib <http://docs.python-tablib.org/>`__
+* `urllib3 <https://urllib3.readthedocs.io/>`__ (customized)
+* `Werkzeug <http://werkzeug.pocoo.org/docs/>`__ (customized)
Documentation using the classic theme
-------------------------------------
-* `Advanced Generic Widgets`__ (customized)
-* `Apache CouchDB`__ (customized)
-* `APSW`__
-* `Arb`__
-* `Bazaar`__ (customized)
-* `Beautiful Soup`__
-* `Blender`__
-* `Bugzilla`__
-* `Buildbot`__
-* `CMake`__ (customized)
-* `Chaco`__ (customized)
-* `Cormoran`__
-* `DEAP`__ (customized)
-* `Director`__
-* `EZ-Draw`__ (customized)
-* `F2py`__
-* `Generic Mapping Tools (GMT)`__ (customized)
-* `Genomedata`__
-* `GetFEM++`__ (customized)
-* `Glasgow Haskell Compiler`__ (customized)
-* `Grok`__ (customized)
-* `GROMACS`__
-* `GSL Shell`__
-* `Hands-on Python Tutorial`__
-* `Kaa`__ (customized)
-* `Leo`__
-* `LEPL`__ (customized)
-* `Mayavi`__ (customized)
-* `MediaGoblin`__ (customized)
-* `mpmath`__
-* `OpenCV`__ (customized)
-* `OpenEXR`__
-* `OpenGDA`__
-* `Peach^3`__ (customized)
-* `Plone`__ (customized)
-* `PyEMD`__
-* `Pyevolve`__
-* `Pygame`__ (customized)
-* `PyMQI`__
-* `PyQt4`__ (customized)
-* `PyQt5`__ (customized)
-* `Python 2`__
-* `Python 3`__ (customized)
-* `Python Packaging Authority`__ (customized)
-* `Ring programming language`__ (customized)
-* `SageMath`__ (customized)
-* `Segway`__
-* `simuPOP`__ (customized)
-* `Sprox`__ (customized)
-* `SymPy`__
-* `TurboGears`__ (customized)
-* `tvtk`__
-* `Varnish`__ (customized, alabaster for index)
-* `Waf`__
-* `wxPython Phoenix`__ (customized)
-* `z3c`__
-* `zc.async`__ (customized)
-* `Zope`__ (customized)
-
-__ http://xoomer.virgilio.it/infinity77/AGW_Docs/
-__ http://docs.couchdb.org/
-__ https://rogerbinns.github.io/apsw/
-__ http://arblib.org/
-__ http://doc.bazaar.canonical.com/
-__ https://www.crummy.com/software/BeautifulSoup/bs4/doc/
-__ https://docs.blender.org/api/current/
-__ https://bugzilla.readthedocs.io/
-__ https://docs.buildbot.net/latest/
-__ https://cmake.org/documentation/
-__ http://docs.enthought.com/chaco/
-__ http://cormoran.nhopkg.org/docs/
-__ https://deap.readthedocs.io/
-__ https://pythonhosted.org/director/
-__ https://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html
-__ http://f2py.sourceforge.net/docs/
-__ http://gmt.soest.hawaii.edu/doc/latest/
-__ https://noble.gs.washington.edu/proj/genomedata/doc/1.3.3/
-__ http://getfem.org/
-__ https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/
-__ http://grok.zope.org/doc/current/
-__ http://manual.gromacs.org/documentation/
-__ http://www.nongnu.org/gsl-shell/
-__ http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/
-__ http://api.freevo.org/kaa-base/
-__ http://leoeditor.com/
-__ http://www.acooke.org/lepl/
-__ http://docs.enthought.com/mayavi/mayavi/
-__ https://mediagoblin.readthedocs.io/
-__ http://mpmath.org/doc/current/
-__ http://docs.opencv.org/
-__ http://excamera.com/articles/26/doc/index.html
-__ http://www.opengda.org/gdadoc/html/
-__ https://peach3.nl/doc/latest/userdoc/
-__ https://docs.plone.org/
-__ https://pyemd.readthedocs.io/
-__ http://pyevolve.sourceforge.net/
-__ https://www.pygame.org/docs/
-__ https://pythonhosted.org/pymqi/
-__ http://pyqt.sourceforge.net/Docs/PyQt4/
-__ http://pyqt.sourceforge.net/Docs/PyQt5/
-__ https://docs.python.org/2/
-__ https://docs.python.org/3/
-__ https://www.pypa.io/
-__ http://ring-lang.sourceforge.net/doc/
-__ https://doc.sagemath.org/
-__ http://noble.gs.washington.edu/proj/segway/doc/1.1.0/segway.html
-__ http://simupop.sourceforge.net/manual_release/build/userGuide.html
-__ http://sprox.org/
-__ http://docs.sympy.org/
-__ https://turbogears.readthedocs.io/
-__ http://docs.enthought.com/mayavi/tvtk/
-__ https://www.varnish-cache.org/docs/
-__ https://waf.io/apidocs/
-__ https://wxpython.org/Phoenix/docs/html/main.html
-__ http://www.ibiblio.org/paulcarduner/z3ctutorial/
-__ https://pythonhosted.org/zc.async/
-__ https://docs.zope.org/zope2/
+* `Advanced Generic Widgets <http://xoomer.virgilio.it/infinity77/AGW_Docs/>`__ (customized)
+* `Apache CouchDB <http://docs.couchdb.org/>`__ (customized)
+* `APSW <https://rogerbinns.github.io/apsw/>`__
+* `Arb <http://arblib.org/>`__
+* `Bazaar <http://doc.bazaar.canonical.com/>`__ (customized)
+* `Beautiful Soup <https://www.crummy.com/software/BeautifulSoup/bs4/doc/>`__
+* `Blender <https://docs.blender.org/api/current/>`__
+* `Bugzilla <https://bugzilla.readthedocs.io/>`__
+* `Buildbot <https://docs.buildbot.net/latest/>`__
+* `CMake <https://cmake.org/documentation/>`__ (customized)
+* `Chaco <https://docs.enthought.com/chaco/>`__ (customized)
+* `Cormoran <http://cormoran.nhopkg.org/docs/>`__
+* `DEAP <https://deap.readthedocs.io/>`__ (customized)
+* `Director <https://pythonhosted.org/director/>`__
+* `EZ-Draw <https://pageperso.lif.univ-mrs.fr/~edouard.thiel/ez-draw/doc/en/html/ez-manual.html>`__ (customized)
+* `F2py <http://f2py.sourceforge.net/docs/>`__
+* `Generic Mapping Tools (GMT) <https://gmt.soest.hawaii.edu/doc/latest/>`__ (customized)
+* `Genomedata <https://noble.gs.washington.edu/proj/genomedata/doc/1.3.3/>`__
+* `GetFEM++ <http://getfem.org/>`__ (customized)
+* `Glasgow Haskell Compiler <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/>`__ (customized)
+* `Grok <http://grok.zope.org/doc/current/>`__ (customized)
+* `GROMACS <http://manual.gromacs.org/documentation/>`__
+* `GSL Shell <https://www.nongnu.org/gsl-shell/>`__
+* `Hands-on Python Tutorial <https://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/>`__
+* `Kaa <https://api.freevo.org/kaa-base/>`__ (customized)
+* `Leo <https://leoeditor.com/>`__
+* `LEPL <http://www.acooke.org/lepl/>`__ (customized)
+* `Mayavi <https://docs.enthought.com/mayavi/mayavi/>`__ (customized)
+* `MediaGoblin <https://mediagoblin.readthedocs.io/>`__ (customized)
+* `mpmath <http://mpmath.org/doc/current/>`__
+* `OpenCV <https://docs.opencv.org/>`__ (customized)
+* `OpenEXR <http://excamera.com/articles/26/doc/index.html>`__
+* `OpenGDA <http://www.opengda.org/gdadoc/html/>`__
+* `Peach^3 <https://peach3.nl/doc/latest/userdoc/>`__ (customized)
+* `Plone <https://docs.plone.org/>`__ (customized)
+* `PyEMD <https://pyemd.readthedocs.io/>`__
+* `Pyevolve <http://pyevolve.sourceforge.net/>`__
+* `Pygame <https://www.pygame.org/docs/>`__ (customized)
+* `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 3 <https://docs.python.org/3/>`__ (customized)
+* `Python Packaging Authority <https://www.pypa.io/>`__ (customized)
+* `Ring programming language <http://ring-lang.sourceforge.net/doc/>`__ (customized)
+* `SageMath <https://doc.sagemath.org/>`__ (customized)
+* `Segway <https://noble.gs.washington.edu/proj/segway/doc/1.1.0/segway.html>`__
+* `simuPOP <http://simupop.sourceforge.net/manual_release/build/userGuide.html>`__ (customized)
+* `Sprox <http://sprox.org/>`__ (customized)
+* `SymPy <https://docs.sympy.org/>`__
+* `TurboGears <https://turbogears.readthedocs.io/>`__ (customized)
+* `tvtk <https://docs.enthought.com/mayavi/tvtk/>`__
+* `Varnish <https://www.varnish-cache.org/docs/>`__ (customized, alabaster for index)
+* `Waf <https://waf.io/apidocs/>`__
+* `wxPython Phoenix <https://wxpython.org/Phoenix/docs/html/main.html>`__ (customized
+* `z3c <https://www.ibiblio.org/paulcarduner/z3ctutorial/>`__
+* `zc.async <https://pythonhosted.org/zc.async/>`__ (customized)
+* `Zope <https://docs.zope.org/zope2/>`__ (customized)
Documentation using the sphinxdoc theme
---------------------------------------
-* `cartopy`__
-* `Jython`__
-* `Matplotlib`__
-* `MDAnalysis Tutorial`__
-* `NetworkX`__
-* `PyCantonese`__
-* `Pyre`__
-* `pySPACE`__
-* `Pysparse`__
-* `PyTango`__
-* `Python Wild Magic`__ (customized)
-* `Reteisi`__ (customized)
-* `Sqlkit`__ (customized)
-* `Turbulenz`__
-
-__ http://scitools.org.uk/cartopy/docs/latest/
-__ http://www.jython.org/docs/
-__ https://matplotlib.org/
-__ http://www.mdanalysis.org/MDAnalysisTutorial/
-__ https://networkx.github.io/
-__ http://pycantonese.org/
-__ http://docs.danse.us/pyre/sphinx/
-__ https://pyspace.github.io/pyspace/
-__ http://pysparse.sourceforge.net/
-__ http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/pytango/latest/
-__ https://vmlaker.github.io/pythonwildmagic/
-__ http://www.reteisi.org/contents.html
-__ http://sqlkit.argolinux.org/
-__ http://docs.turbulenz.com/
+* `cartopy <https://scitools.org.uk/cartopy/docs/latest/>`__
+* `Jython <http://www.jython.org/docs/>`__
+* `Matplotlib <https://matplotlib.org/>`__
+* `MDAnalysis Tutorial <https://www.mdanalysis.org/MDAnalysisTutorial/>`__
+* `NetworkX <https://networkx.github.io/>`__
+* `PyCantonese <http://pycantonese.org/>`__
+* `Pyre <http://docs.danse.us/pyre/sphinx/>`__
+* `pySPACE <https://pyspace.github.io/pyspace/>`__
+* `Pysparse <http://pysparse.sourceforge.net/>`__
+* `PyTango <https://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/pytango/latest/>`__
+* `Python Wild Magic <https://vmlaker.github.io/pythonwildmagic/>`__ (customized)
+* `Reteisi <http://www.reteisi.org/contents.html>`__ (customized)
+* `Sqlkit <http://sqlkit.argolinux.org/>`__ (customized)
+* `Turbulenz <http://docs.turbulenz.com/>`__
Documentation using the nature theme
------------------------------------
-* `Alembic`__
-* `Cython`__
-* `easybuild`__
-* `jsFiddle`__
-* `libLAS`__ (customized)
-* `Lmod`__
-* `MapServer`__ (customized)
-* `Pandas`__
-* `pyglet`__ (customized)
-* `Setuptools`__
-* `Spring Python`__
-* `StatsModels`__ (customized)
-* `Sylli`__
-
-__ http://alembic.zzzcomputing.com/
-__ http://docs.cython.org/
-__ https://easybuild.readthedocs.io/
-__ http://doc.jsfiddle.net/
-__ https://www.liblas.org/
-__ https://lmod.readthedocs.io/
-__ http://mapserver.org/
-__ https://pandas.pydata.org/pandas-docs/stable/
-__ https://pyglet.readthedocs.io/
-__ https://setuptools.readthedocs.io/
-__ https://docs.spring.io/spring-python/1.2.x/sphinx/html/
-__ http://www.statsmodels.org/
-__ http://sylli.sourceforge.net/
+* `Alembic <http://alembic.zzzcomputing.com/>`__
+* `Cython <http://docs.cython.org/>`__
+* `easybuild <https://easybuild.readthedocs.io/>`__
+* `jsFiddle <http://doc.jsfiddle.net/>`__
+* `libLAS <https://www.liblas.org/>`__ (customized)
+* `Lmod <https://lmod.readthedocs.io/>`__
+* `MapServer <https://mapserver.org/>`__ (customized)
+* `Pandas <https://pandas.pydata.org/pandas-docs/stable/>`__
+* `pyglet <https://pyglet.readthedocs.io/>`__ (customized)
+* `Setuptools <https://setuptools.readthedocs.io/>`__
+* `Spring Python <https://docs.spring.io/spring-python/1.2.x/sphinx/html/>`__
+* `StatsModels <https://www.statsmodels.org/>`__ (customized)
+* `Sylli <http://sylli.sourceforge.net/>`__
Documentation using another builtin theme
-----------------------------------------
-* `Breathe`__ (haiku)
-* `MPipe`__ (sphinx13)
-* `NLTK`__ (agogo)
-* `Programmieren mit PyGTK und Glade (German)`__ (agogo, customized)
-* `PyPubSub`__ (bizstyle)
-* `Pylons`__ (pyramid)
-* `Pyramid web framework`__ (pyramid)
-* `Sphinx`__ (sphinx13) :-)
-* `Valence`__ (haiku, customized)
-
-__ https://breathe.readthedocs.io/
-__ https://vmlaker.github.io/mpipe/
-__ http://www.nltk.org/
-__ http://www.florian-diesch.de/doc/python-und-glade/online/
-__ https://pypubsub.readthedocs.io/
-__ http://docs.pylonsproject.org/projects/pylons-webframework/
-__ https://docs.pylonsproject.org/projects/pyramid/
-__ http://www.sphinx-doc.org/
-__ http://docs.valence.desire2learn.com/
+* `Breathe <https://breathe.readthedocs.io/>`__ (haiku)
+* `MPipe <https://vmlaker.github.io/mpipe/>`__ (sphinx13)
+* `NLTK <https://www.nltk.org/>`__ (agogo)
+* `Programmieren mit PyGTK und Glade (German) <https://www.florian-diesch.de/doc/python-und-glade/online/>`__ (agogo, customized)
+* `PyPubSub <https://pypubsub.readthedocs.io/>`__ (bizstyle)
+* `Pylons <https://docs.pylonsproject.org/projects/pylons-webframework/>`__ (pyramid)
+* `Pyramid web framework <https://docs.pylonsproject.org/projects/pyramid/>`__ (pyramid)
+* `Sphinx <http://www.sphinx-doc.org/>`__ (sphinx13) :-)
+* `Valence <https://docs.valence.desire2learn.com/>`__ (haiku, customized)
Documentation using sphinx_rtd_theme
------------------------------------
-* `Annotator`__
-* `Ansible`__ (customized)
-* `Arcade`__
-* `aria2`__
-* `ASE`__
-* `Autofac`__
-* `BigchainDB`__
-* `Blocks`__
-* `bootstrap-datepicker`__
-* `Certbot`__
-* `Chainer`__ (customized)
-* `CherryPy`__
-* `CodeIgniter`__
-* `Conda`__
-* `Corda`__
-* `Dask`__
-* `Databricks`__ (customized)
-* `Dataiku DSS`__
-* `edX`__
-* `Electrum`__
-* `Elemental`__
-* `ESWP3`__
-* `Ethereum Homestead`__
-* `Fidimag`__
-* `Flake8`__
-* `GeoNode`__
-* `Godot`__
-* `Graylog`__
-* `GPAW`__ (customized)
-* `HDF5 for Python (h5py)`__
-* `Hyperledger Fabric`__
-* `Hyperledger Sawtooth`__
-* `IdentityServer`__
-* `Idris`__
-* `javasphinx`__
-* `Julia`__
-* `Jupyter Notebook`__
-* `Lasagne`__
-* `latexindent.pl`__
-* `Linguistica`__
-* `Linux kernel`__
-* `MathJax`__
-* `MDTraj`__ (customized)
-* `MICrobial Community Analysis (micca)`__
-* `MicroPython`__
-* `Minds`__ (customized)
-* `Mink`__
-* `Mockery`__
-* `mod_wsgi`__
-* `MoinMoin`__
-* `Mopidy`__
-* `MyHDL`__
-* `Nextflow`__
-* `NICOS`__ (customized)
-* `Pelican`__
-* `picamera`__
-* `Pillow`__
-* `pip`__
-* `Paver`__
-* `peewee`__
-* `Phinx`__
-* `phpMyAdmin`__
-* `PROS`__ (customized)
-* `Pweave`__
-* `PyPy`__
-* `python-sqlparse`__
-* `PyVISA`__
-* `Read The Docs`__
-* `Free your information from their silos (French)`__ (customized)
-* `Releases Sphinx extension`__
-* `Qtile`__
-* `Quex`__
-* `Satchmo`__
-* `Scapy`__
-* `SimPy`__
-* `SlamData`__
-* `Solidity`__
-* `Sonos Controller (SoCo)`__
-* `Sphinx AutoAPI`__
-* `sphinx-argparse`__
-* `Sphinx-Gallery`__ (customized)
-* `SpotBugs`__
-* `StarUML`__
-* `Sublime Text Unofficial Documentation`__
-* `SunPy`__
-* `Sylius`__
-* `Tango Controls`__ (customized)
-* `Topshelf`__
-* `Theano`__
-* `ThreatConnect`__
-* `Tuleap`__
-* `TYPO3`__ (customized)
-* `uWSGI`__
-* `Wagtail`__
-* `Web Application Attack and Audit Framework (w3af)`__
-* `Weblate`__
-* `x265`__
-* `ZeroNet`__
-
-__ http://docs.annotatorjs.org/
-__ https://docs.ansible.com/
-__ http://arcade.academy/
-__ https://aria2.github.io/manual/en/html/
-__ https://wiki.fysik.dtu.dk/ase/
-__ http://docs.autofac.org/
-__ https://docs.bigchaindb.com/
-__ https://blocks.readthedocs.io/
-__ https://bootstrap-datepicker.readthedocs.io/
-__ https://letsencrypt.readthedocs.io/
-__ https://docs.chainer.org/
-__ http://docs.cherrypy.org/
-__ https://www.codeigniter.com/user_guide/
-__ https://conda.io/docs/
-__ https://docs.corda.net/
-__ https://dask.pydata.org/
-__ https://docs.databricks.com/
-__ https://doc.dataiku.com/
-__ http://docs.edx.org/
-__ http://docs.electrum.org/
-__ http://libelemental.org/documentation/dev/
-__ https://eswp3.readthedocs.io/
-__ http://www.ethdocs.org/
-__ https://fidimag.readthedocs.io/
-__ http://flake8.pycqa.org/
-__ http://docs.geonode.org/
-__ https://godot.readthedocs.io/
-__ http://docs.graylog.org/
-__ https://wiki.fysik.dtu.dk/gpaw/
-__ http://docs.h5py.org/
-__ https://hyperledger-fabric.readthedocs.io/
-__ https://intelledger.github.io/
-__ http://docs.identityserver.io/
-__ http://docs.idris-lang.org/
-__ https://bronto-javasphinx.readthedocs.io/
-__ https://julia.readthedocs.io/
-__ https://jupyter-notebook.readthedocs.io/
-__ https://lasagne.readthedocs.io/
-__ https://latexindentpl.readthedocs.io/
-__ https://linguistica-uchicago.github.io/lxa5/
-__ https://www.kernel.org/doc/html/latest/index.html
-__ https://docs.mathjax.org/
-__ http://mdtraj.org/latest/
-__ http://micca.org/docs/latest/
-__ https://docs.micropython.org/
-__ https://www.minds.org/docs/
-__ http://mink.behat.org/
-__ http://docs.mockery.io/
-__ https://modwsgi.readthedocs.io/
-__ https://moin-20.readthedocs.io/
-__ https://docs.mopidy.com/
-__ http://docs.myhdl.org/
-__ https://www.nextflow.io/docs/latest/index.html
-__ https://forge.frm2.tum.de/nicos/doc/nicos-master/
-__ http://docs.getpelican.com/
-__ https://picamera.readthedocs.io/
-__ https://pillow.readthedocs.io/
-__ https://pip.pypa.io/
-__ https://paver.readthedocs.io/
-__ http://docs.peewee-orm.com/
-__ http://docs.phinx.org/
-__ https://docs.phpmyadmin.net/
-__ https://pros.cs.purdue.edu/v5/
-__ http://mpastell.com/pweave/
-__ http://doc.pypy.org/
-__ https://sqlparse.readthedocs.io/
-__ https://pyvisa.readthedocs.io/
-__ https://docs.readthedocs.io/
-__ http://redaction-technique.org/
-__ https://releases.readthedocs.io/
-__ http://docs.qtile.org/
-__ http://quex.sourceforge.net/doc/html/main.html
-__ http://docs.satchmoproject.com/
-__ https://scapy.readthedocs.io/
-__ http://simpy.readthedocs.io/
-__ http://docs.slamdata.com/
-__ https://solidity.readthedocs.io/
-__ http://docs.python-soco.com/
-__ https://sphinx-autoapi.readthedocs.io/
-__ https://sphinx-argparse.readthedocs.io/
-__ https://sphinx-gallery.readthedocs.io/
-__ https://spotbugs.readthedocs.io/
-__ http://docs.staruml.io/
-__ http://docs.sublimetext.info/
-__ http://docs.sunpy.org/
-__ http://docs.sylius.org/
-__ https://tango-controls.readthedocs.io/
-__ http://docs.topshelf-project.com/
-__ http://www.deeplearning.net/software/theano/
-__ https://docs.threatconnect.com/
-__ https://tuleap.net/doc/en/
-__ https://docs.typo3.org/
-__ https://uwsgi-docs.readthedocs.io/
-__ http://docs.wagtail.io/
-__ http://docs.w3af.org/
-__ https://docs.weblate.org/
-__ https://x265.readthedocs.io/
-__ https://zeronet.readthedocs.io/
+* `Annotator <http://docs.annotatorjs.org/>`__
+* `Ansible <https://docs.ansible.com/>`__ (customized)
+* `Arcade <http://arcade.academy/>`__
+* `aria2 <https://aria2.github.io/manual/en/html/>`__
+* `ASE <https://wiki.fysik.dtu.dk/ase/>`__
+* `Autofac <http://docs.autofac.org/>`__
+* `BigchainDB <https://docs.bigchaindb.com/>`__
+* `Blocks <https://blocks.readthedocs.io/>`__
+* `bootstrap-datepicker <https://bootstrap-datepicker.readthedocs.io/>`__
+* `Certbot <https://letsencrypt.readthedocs.io/>`__
+* `Chainer <https://docs.chainer.org/>`__ (customized)
+* `CherryPy <https://docs.cherrypy.org/>`__
+* `CodeIgniter <https://www.codeigniter.com/user_guide/>`__
+* `Conda <https://conda.io/docs/>`__
+* `Corda <https://docs.corda.net/>`__
+* `Dask <https://dask.pydata.org/>`__
+* `Databricks <https://docs.databricks.com/>`__ (customized)
+* `Dataiku DSS <https://doc.dataiku.com/>`__
+* `edX <https://docs.edx.org/>`__
+* `Electrum <http://docs.electrum.org/>`__
+* `Elemental <http://libelemental.org/documentation/dev/>`__
+* `ESWP3 <https://eswp3.readthedocs.io/>`__
+* `Ethereum Homestead <http://www.ethdocs.org/>`__
+* `Fidimag <https://fidimag.readthedocs.io/>`__
+* `Flake8 <http://flake8.pycqa.org/>`__
+* `GeoNode <http://docs.geonode.org/>`__
+* `Godot <https://godot.readthedocs.io/>`__
+* `Graylog <http://docs.graylog.org/>`__
+* `GPAW <https://wiki.fysik.dtu.dk/gpaw/>`__ (customized)
+* `HDF5 for Python (h5py) <http://docs.h5py.org/>`__
+* `Hyperledger Fabric <https://hyperledger-fabric.readthedocs.io/>`__
+* `Hyperledger Sawtooth <https://intelledger.github.io/>`__
+* `IdentityServer <http://docs.identityserver.io/>`__
+* `Idris <http://docs.idris-lang.org/>`__
+* `javasphinx <https://bronto-javasphinx.readthedocs.io/>`__
+* `Julia <https://julia.readthedocs.io/>`__
+* `Jupyter Notebook <https://jupyter-notebook.readthedocs.io/>`__
+* `Lasagne <https://lasagne.readthedocs.io/>`__
+* `latexindent.pl <https://latexindentpl.readthedocs.io/>`__
+* `Linguistica <https://linguistica-uchicago.github.io/lxa5/>`__
+* `Linux kernel <https://www.kernel.org/doc/html/latest/index.html>`__
+* `MathJax <https://docs.mathjax.org/>`__
+* `MDTraj <http://mdtraj.org/latest/>`__ (customized)
+* `MICrobial Community Analysis (micca) <http://micca.org/docs/latest/>`__
+* `MicroPython <https://docs.micropython.org/>`__
+* `Minds <https://www.minds.org/docs/>`__ (customized)
+* `Mink <http://mink.behat.org/>`__
+* `Mockery <http://docs.mockery.io/>`__
+* `mod_wsgi <https://modwsgi.readthedocs.io/>`__
+* `MoinMoin <https://moin-20.readthedocs.io/>`__
+* `Mopidy <https://docs.mopidy.com/>`__
+* `MyHDL <http://docs.myhdl.org/>`__
+* `Nextflow <https://www.nextflow.io/docs/latest/index.html>`__
+* `NICOS <https://forge.frm2.tum.de/nicos/doc/nicos-master/>`__ (customized)
+* `Pelican <http://docs.getpelican.com/>`__
+* `picamera <https://picamera.readthedocs.io/>`__
+* `Pillow <https://pillow.readthedocs.io/>`__
+* `pip <https://pip.pypa.io/>`__
+* `Paver <https://paver.readthedocs.io/>`__
+* `peewee <http://docs.peewee-orm.com/>`__
+* `Phinx <http://docs.phinx.org/>`__
+* `phpMyAdmin <https://docs.phpmyadmin.net/>`__
+* `PROS <https://pros.cs.purdue.edu/v5/>`__ (customized)
+* `Pweave <http://mpastell.com/pweave/>`__
+* `PyPy <http://doc.pypy.org/>`__
+* `python-sqlparse <https://sqlparse.readthedocs.io/>`__
+* `PyVISA <https://pyvisa.readthedocs.io/>`__
+* `Read The Docs <https://docs.readthedocs.io/>`__
+* `Free your information from their silos (French) <http://redaction-technique.org/>`__ (customized)
+* `Releases Sphinx extension <https://releases.readthedocs.io/>`__
+* `Qtile <http://docs.qtile.org/>`__
+* `Quex <http://quex.sourceforge.net/doc/html/main.html>`__
+* `Satchmo <http://docs.satchmoproject.com/>`__
+* `Scapy <https://scapy.readthedocs.io/>`__
+* `SimPy <https://simpy.readthedocs.io/>`__
+* `SlamData <https://newdocs.slamdata.com>`__
+* `Solidity <https://solidity.readthedocs.io/>`__
+* `Sonos Controller (SoCo) <http://docs.python-soco.com/>`__
+* `Sphinx AutoAPI <https://sphinx-autoapi.readthedocs.io/>`__
+* `sphinx-argparse <https://sphinx-argparse.readthedocs.io/>`__
+* `Sphinx-Gallery <https://sphinx-gallery.readthedocs.io/>`__ (customized)
+* `SpotBugs <https://spotbugs.readthedocs.io/>`__
+* `StarUML <https://docs.staruml.io/>`__
+* `Sublime Text Unofficial Documentation <http://docs.sublimetext.info/>`__
+* `SunPy <https://docs.sunpy.org/>`__
+* `Sylius <http://docs.sylius.org/>`__
+* `Tango Controls <https://tango-controls.readthedocs.io/>`__ (customized)
+* `Topshelf <http://docs.topshelf-project.com/>`__
+* `Theano <http://www.deeplearning.net/software/theano/>`__
+* `ThreatConnect <https://docs.threatconnect.com/>`__
+* `Tuleap <https://tuleap.net/doc/en/>`__
+* `TYPO3 <https://docs.typo3.org/>`__ (customized)
+* `uWSGI <https://uwsgi-docs.readthedocs.io/>`__
+* `Wagtail <https://docs.wagtail.io/>`__
+* `Web Application Attack and Audit Framework (w3af) <http://docs.w3af.org/>`__
+* `Weblate <https://docs.weblate.org/>`__
+* `x265 <https://x265.readthedocs.io/>`__
+* `ZeroNet <https://zeronet.readthedocs.io/>`__
Documentation using sphinx_bootstrap_theme
------------------------------------------
-* `Bootstrap Theme`__
-* `C/C++ Software Development with Eclipse`__
-* `Dataverse`__
-* `e-cidadania`__
-* `Hangfire`__
-* `Hedge`__
-* `ObsPy`__
-* `Open Dylan`__
-* `Pootle`__
-* `PyUblas`__
-* `seaborn`__
-
-__ https://ryan-roemer.github.io/sphinx-bootstrap-theme/
-__ http://eclipsebook.in/
-__ http://guides.dataverse.org/
-__ https://e-cidadania.readthedocs.io/
-__ http://docs.hangfire.io/
-__ https://documen.tician.de/hedge/
-__ https://docs.obspy.org/
-__ https://opendylan.org/documentation/
-__ http://docs.translatehouse.org/projects/pootle/
-__ https://documen.tician.de/pyublas/
-__ https://seaborn.pydata.org/
+* `Bootstrap Theme <https://ryan-roemer.github.io/sphinx-bootstrap-theme/>`__
+* `C/C++ Software Development with Eclipse <https://eclipsebook.in/>`__
+* `Dataverse <http://guides.dataverse.org/>`__
+* `e-cidadania <https://e-cidadania.readthedocs.io/>`__
+* `Hangfire <http://docs.hangfire.io/>`__
+* `Hedge <https://documen.tician.de/hedge/>`__
+* `ObsPy <https://docs.obspy.org/>`__
+* `Open Dylan <https://opendylan.org/documentation/>`__
+* `Pootle <http://docs.translatehouse.org/projects/pootle/>`__
+* `PyUblas <https://documen.tician.de/pyublas/>`__
+* `seaborn <https://seaborn.pydata.org/>`__
Documentation using a custom theme or integrated in a website
-------------------------------------------------------------
-* `Apache Cassandra`__
-* `Astropy`__
-* `Bokeh`__
-* `Boto 3`__
-* `CakePHP`__
-* `CasperJS`__
-* `Ceph`__
-* `Chef`__
-* `CKAN`__
-* `Confluent Platform`__
-* `Django`__
-* `Doctrine`__
-* `Enterprise Toolkit for Acrobat products`__
-* `Gameduino`__
-* `gensim`__
-* `GeoServer`__
-* `gevent`__
-* `GHC - Glasgow Haskell Compiler`__
-* `Guzzle`__
-* `H2O.ai`__
-* `Istihza (Turkish Python documentation project)`__
-* `Kombu`__
-* `Lasso`__
-* `Mako`__
-* `MirrorBrain`__
-* `MongoDB`__
-* `Music21`__
-* `MyHDL`__
-* `nose`__
-* `ns-3`__
-* `NumPy`__
-* `ObjectListView`__
-* `OpenERP`__
-* `OpenCV`__
-* `OpenLayers`__
-* `OpenTURNS`__
-* `Open vSwitch`__
-* `PlatformIO`__
-* `PyEphem`__
-* `Pygments`__
-* `Plone User Manual (German)`__
-* `PSI4`__
-* `PyMOTW`__
-* `python-aspectlib`__ (`sphinx_py3doc_enhanced_theme <https://pypi.org/project/sphinx_py3doc_enhanced_theme/>`__)
-* `QGIS`__
-* `qooxdoo`__
-* `Roundup`__
-* `SaltStack`__
-* `scikit-learn`__
-* `SciPy`__
-* `Scrapy`__
-* `Seaborn`__
-* `Selenium`__
-* `Self`__
-* `Substance D`__
-* `Sulu`__
-* `SQLAlchemy`__
-* `tinyTiM`__
-* `Twisted`__
-* `Ubuntu Packaging Guide`__
-* `WebFaction`__
-* `WTForms`__
-
-__ https://cassandra.apache.org/doc/
-__ http://docs.astropy.org/
-__ https://bokeh.pydata.org/
-__ https://boto3.readthedocs.io/
-__ https://book.cakephp.org/
-__ http://docs.casperjs.org/
-__ http://docs.ceph.com/docs/master/
-__ https://docs.chef.io/
-__ http://docs.ckan.org/
-__ http://docs.confluent.io/
-__ https://docs.djangoproject.com/
-__ http://docs.doctrine-project.org/
-__ https://www.adobe.com/devnet-docs/acrobatetk/
-__ http://excamera.com/sphinx/gameduino/
-__ https://radimrehurek.com/gensim/
-__ http://docs.geoserver.org/
-__ http://www.gevent.org/
-__ http://downloads.haskell.org/~ghc/master/users-guide/
-__ http://docs.guzzlephp.org/en/stable/
-__ http://docs.h2o.ai/
-__ https://belgeler.yazbel.com/python-istihza/
-__ http://docs.kombu.me/
-__ http://lassoguide.com/
-__ http://docs.makotemplates.org/
-__ http://mirrorbrain.org/docs/
-__ https://docs.mongodb.com/
-__ http://web.mit.edu/music21/doc/
-__ http://docs.myhdl.org/en/latest/
-__ https://nose.readthedocs.io/
-__ https://www.nsnam.org/documentation/
-__ https://docs.scipy.org/doc/numpy/reference/
-__ http://objectlistview.sourceforge.net/python/
-__ https://doc.odoo.com/
-__ http://docs.opencv.org/
-__ http://docs.openlayers.org/
-__ http://openturns.github.io/openturns/master/
-__ http://docs.openvswitch.org/
-__ http://docs.platformio.org/
-__ http://rhodesmill.org/pyephem/
-__ http://pygments.org/docs/
-__ https://www.hasecke.com/plone-benutzerhandbuch/4.0/
-__ http://www.psicode.org/psi4manual/master/index.html
-__ https://pymotw.com/2/
-__ https://python-aspectlib.readthedocs.io/
-__ https://qgis.org/en/docs/index.html
-__ http://www.qooxdoo.org/current/
-__ http://www.roundup-tracker.org/
-__ https://docs.saltstack.com/
-__ http://scikit-learn.org/stable/
-__ https://docs.scipy.org/doc/scipy/refrence/
-__ https://doc.scrapy.org/
-__ https://seaborn.pydata.org/
-__ http://docs.seleniumhq.org/docs/
-__ http://www.selflanguage.org/
-__ https://docs.pylonsproject.org/projects/substanced/
-__ http://docs.sulu.io/
-__ https://docs.sqlalchemy.org/
-__ http://tinytim.sourceforge.net/docs/2.0/
-__ http://twistedmatrix.com/documents/current/
-__ http://packaging.ubuntu.com/html/
-__ https://docs.webfaction.com/
-__ https://wtforms.readthedocs.io/
+* `Apache Cassandra <https://cassandra.apache.org/doc/>`__
+* `Astropy <http://docs.astropy.org/>`__
+* `Bokeh <https://bokeh.pydata.org/>`__
+* `Boto 3 <https://boto3.readthedocs.io/>`__
+* `CakePHP <https://book.cakephp.org/>`__
+* `CasperJS <http://docs.casperjs.org/>`__
+* `Ceph <http://docs.ceph.com/docs/master/>`__
+* `Chef <https://docs.chef.io/>`__
+* `CKAN <https://docs.ckan.org/>`__
+* `Confluent Platform <https://docs.confluent.io/>`__
+* `Django <https://docs.djangoproject.com/>`__
+* `Doctrine <https://www.doctrine-project.org/>`__
+* `Enterprise Toolkit for Acrobat products <https://www.adobe.com/devnet-docs/acrobatetk/>`__
+* `Gameduino <http://excamera.com/sphinx/gameduino/>`__
+* `gensim <https://radimrehurek.com/gensim/>`__
+* `GeoServer <http://docs.geoserver.org/>`__
+* `gevent <http://www.gevent.org/>`__
+* `GHC - Glasgow Haskell Compiler <https://downloads.haskell.org/~ghc/master/users-guide/>`__
+* `Guzzle <http://docs.guzzlephp.org/en/stable/>`__
+* `H2O.ai <http://docs.h2o.ai/>`__
+* `Istihza (Turkish Python documentation project) <https://belgeler.yazbel.com/python-istihza/>`__
+* `Kombu <http://docs.kombu.me/>`__
+* `Lasso <http://lassoguide.com/>`__
+* `Mako <http://docs.makotemplates.org/>`__
+* `MirrorBrain <http://mirrorbrain.org/docs/>`__
+* `MongoDB <https://docs.mongodb.com/>`__
+* `Music21 <https://web.mit.edu/music21/doc/>`__
+* `MyHDL <http://docs.myhdl.org/en/latest/>`__
+* `nose <https://nose.readthedocs.io/>`__
+* `ns-3 <https://www.nsnam.org/documentation/>`__
+* `NumPy <https://docs.scipy.org/doc/numpy/reference/>`__
+* `ObjectListView <http://objectlistview.sourceforge.net/python/>`__
+* `OpenERP <https://doc.odoo.com/>`__
+* `OpenCV <https://docs.opencv.org/>`__
+* `OpenLayers <http://docs.openlayers.org/>`__
+* `OpenTURNS <https://openturns.github.io/openturns/master/>`__
+* `Open vSwitch <http://docs.openvswitch.org/>`__
+* `PlatformIO <https://docs.platformio.org/>`__
+* `PyEphem <http://rhodesmill.org/pyephem/>`__
+* `Pygments <http://pygments.org/docs/>`__
+* `Plone User Manual (German) <https://www.hasecke.com/plone-benutzerhandbuch/4.0/>`__
+* `PSI4 <http://www.psicode.org/psi4manual/master/index.html>`__
+* `PyMOTW <https://pymotw.com/2/>`__
+* `python-aspectlib <https://python-aspectlib.readthedocs.io/>`__ (`sphinx_py3doc_enhanced_theme <https://pypi.org/project/sphinx_py3doc_enhanced_theme/>`__)
+* `QGIS <https://qgis.org/en/docs/index.html>`__
+* `qooxdoo <https://www.qooxdoo.org/current/>`__
+* `Roundup <http://www.roundup-tracker.org/>`__
+* `SaltStack <https://docs.saltstack.com/>`__
+* `scikit-learn <http://scikit-learn.org/stable/>`__
+* `SciPy <https://docs.scipy.org/doc/scipy/refrence/>`__
+* `Scrapy <https://doc.scrapy.org/>`__
+* `Seaborn <https://seaborn.pydata.org/>`__
+* `Selenium <https://docs.seleniumhq.org/docs/>`__
+* `Self <http://www.selflanguage.org/>`__
+* `Substance D <https://docs.pylonsproject.org/projects/substanced/>`__
+* `Sulu <http://docs.sulu.io/>`__
+* `SQLAlchemy <https://docs.sqlalchemy.org/>`__
+* `tinyTiM <http://tinytim.sourceforge.net/docs/2.0/>`__
+* `Twisted <https://twistedmatrix.com/documents/current/>`__
+* `Ubuntu Packaging Guide <http://packaging.ubuntu.com/html/>`__
+* `WebFaction <https://docs.webfaction.com/>`__
+* `WTForms <https://wtforms.readthedocs.io/>`__
Homepages and other non-documentation sites
-------------------------------------------
-* `Arizona State University PHY494/PHY598/CHM598 Simulation approaches to Bio-and Nanophysics`__ (classic)
-* `Benoit Boissinot`__ (classic, customized)
-* `Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab)`__ (sphinx_rtd_theme)
-* `Deep Learning Tutorials`__ (sphinxdoc)
-* `Loyola University Chicago COMP 339-439 Distributed Systems course`__ (sphinx_bootstrap_theme)
-* `Pylearn2`__ (sphinxdoc, customized)
-* `PyXLL`__ (sphinx_bootstrap_theme, customized)
-* `SciPy Cookbook`__ (sphinx_rtd_theme)
-* `The Wine Cellar Book`__ (sphinxdoc)
-* `Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials`__ (standard)
-* `UC Berkeley ME233 Advanced Control Systems II course`__ (sphinxdoc)
-
-__ https://becksteinlab.physics.asu.edu/pages/courses/2013/SimBioNano/
-__ https://bboissin.appspot.com/
-__ https://lab.miletic.net/
-__ http://www.deeplearning.net/tutorial/
-__ http://books.cs.luc.edu/distributedsystems/
-__ http://www.deeplearning.net/software/pylearn2/
-__ https://www.pyxll.com/
-__ https://scipy-cookbook.readthedocs.io/
-__ https://www.thewinecellarbook.com/doc/en/
-__ http://thomas-cokelaer.info/tutorials/
-__ https://berkeley-me233.github.io/
+* `Arizona State University PHY494/PHY598/CHM598 Simulation approaches to Bio-and Nanophysics <https://becksteinlab.physics.asu.edu/pages/courses/2013/SimBioNano/>`__ (classic)
+* `Benoit Boissinot <https://bboissin.appspot.com/>`__ (classic, customized)
+* `Computer Networks, Parallelization, and Simulation Laboratory (CNPSLab) <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 <https://books.cs.luc.edu/distributedsystems/>`__ (sphinx_bootstrap_theme)
+* `Pylearn2 <http://www.deeplearning.net/software/pylearn2/>`__ (sphinxdoc, customized)
+* `PyXLL <https://www.pyxll.com/>`__ (sphinx_bootstrap_theme, customized)
+* `SciPy Cookbook <https://scipy-cookbook.readthedocs.io/>`__ (sphinx_rtd_theme)
+* `The Wine Cellar Book <https://www.thewinecellarbook.com/doc/en/>`__ (sphinxdoc)
+* `Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials <https://thomas-cokelaer.info/tutorials/>`__ (standard)
+* `UC Berkeley ME233 Advanced Control Systems II course <https://berkeley-me233.github.io/>`__ (sphinxdoc)
Books produced using Sphinx
---------------------------
-* `"Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kieślowski"`__
-* `"Expert Python Programming"`__
-* `"Expert Python Programming" (Japanese translation)`__
-* `"The Hitchhiker's Guide to Python"`__
-* `"LassoGuide"`__
-* `"Learning Sphinx" (in Japanese)`__
-* `"Mercurial: the definitive guide (Second edition)"`__
-* `"Pioneers and Prominent Men of Utah"`__
-* `"Pomodoro Technique Illustrated" (Japanese translation)`__
-* `"Python Professional Programming" (in Japanese)`__
-* `"Redmine Primer 5th Edition (in Japanese)"`__
-* `"The repoze.bfg Web Application Framework"`__
-* `"Simple and Steady Way of Learning for Software Engineering" (in Japanese)`__
-* `"Software-Dokumentation mit Sphinx"`__
-* `"Theoretical Physics Reference"`__
-* `"The Varnish Book"`__
-
-__ https://literatur.hasecke.com/post/die-wahrheit-des-sehens-dekalog-kieslowski/
-__ https://www.packtpub.com/application-development/expert-python-programming
-__ https://www.amazon.co.jp/dp/4048686291/
-__ http://docs.python-guide.org/en/latest/
-__ http://www.lassosoft.com/Lasso-Documentation
-__ https://www.oreilly.co.jp/books/9784873116488/
-__ https://book.mercurial-scm.org/
-__ http://pioneers.rstebbing.com/
-__ https://www.amazon.co.jp/dp/4048689525/
-__ http://www.amazon.co.jp/dp/4798032948/
-__ https://www.shuwasystem.co.jp/products/7980html/4825.html
-__ https://www.amazon.com/repoze-bfg-Web-Application-Framework-Version/dp/0615345379
-__ https://www.amazon.co.jp/dp/477414259X/
-__ https://www.amazon.de/dp/1497448689/
-__ http://www.theoretical-physics.net/
-__ https://info.varnish-software.com/the-varnish-book
+* `"The Art of Community" (Japanese translation) <https://www.oreilly.co.jp/books/9784873114958/>`__
+* `"Die Wahrheit des Sehens. Der DEKALOG von Krzysztof Kieślowski" <https://literatur.hasecke.com/post/die-wahrheit-des-sehens-dekalog-kieslowski/>`__
+* `"Expert Python Programming" <https://www.packtpub.com/application-development/expert-python-programming>`__
+* `"Expert Python Programming" (Japanese translation) <https://www.amazon.co.jp/dp/4048686291/>`__
+* `"Expert Python Programming 2nd Edition" (Japanese translation) <https://www.amazon.co.jp/dp/4048930613/>`__
+* `"The Hitchhiker's Guide to Python" <https://docs.python-guide.org/>`__
+* `"LassoGuide" <http://www.lassosoft.com/Lasso-Documentation>`__
+* `"Learning Sphinx" (in Japanese) <https://www.oreilly.co.jp/books/9784873116488/>`__
+* `"Learning System Programming with Go (Japanese)" <https://www.lambdanote.com/products/go>`__
+* `"Mercurial: the definitive guide (Second edition)" <https://book.mercurial-scm.org/>`__
+* `"Mithril -- The fastest clientside MVC (Japanese)" <https://www.oreilly.co.jp/books/9784873117447/>`__
+* `"Pioneers and Prominent Men of Utah" <http://pioneers.rstebbing.com/>`__
+* `"Pomodoro Technique Illustrated" (Japanese translation) <https://www.amazon.co.jp/dp/4048689525/>`__
+* `"Python Professional Programming" (in Japanese) <http://www.amazon.co.jp/dp/4798032948/>`__
+* `"Python Professional Programming 2nd Edition" (in Japanese) <https://www.amazon.co.jp/dp/479804315X/>`__
+* `"Python Professional Programming 3rd Edition" (in Japanese) <https://www.amazon.co.jp/dp/4798053821/>`__
+* `"Real World HTTP -- Learning The Internet and Web Technology via its history and code (Japanese)" <https://www.oreilly.co.jp/books/9784873118048/>`__
+* `"Redmine Primer 5th Edition (in Japanese)" <https://www.shuwasystem.co.jp/products/7980html/4825.html>`__
+* `"The repoze.bfg Web Application Framework" <https://www.amazon.com/repoze-bfg-Web-Application-Framework-Version/dp/0615345379>`__
+* `"The Self-Taught Programmer" (Japanese translation) <https://www.amazon.co.jp/dp/4822292274/>`__
+* `"Simple and Steady Way of Learning for Software Engineering" (in Japanese) <https://www.amazon.co.jp/dp/477414259X/>`__
+* `"Software-Dokumentation mit Sphinx" <https://www.amazon.de/dp/1497448689/>`__
+* `"Theoretical Physics Reference" <https://www.theoretical-physics.net/>`__
+* `"The Varnish Book" <https://info.varnish-software.com/the-varnish-book>`__
Theses produced using Sphinx
----------------------------
* `"A Web-Based System for Comparative Analysis of OpenStreetMap Data by the Use
- of CouchDB"`__
-* `"Content Conditioning and Distribution for Dynamic Virtual Worlds"`__
-* `"The Sphinx Thesis Resource"`__
-
-__ https://www.yumpu.com/et/document/view/11722645/masterthesis-markusmayr-0542042
-__ https://www.cs.princeton.edu/research/techreps/TR-941-12
-__ https://jterrace.github.io/sphinxtr/
+ of CouchDB" <https://www.yumpu.com/et/document/view/11722645/masterthesis-markusmayr-0542042>`__
+* `"Content Conditioning and Distribution for Dynamic Virtual Worlds" <https://www.cs.princeton.edu/research/techreps/TR-941-12>`__
+* `"The Sphinx Thesis Resource" <https://jterrace.github.io/sphinxtr/>`__
Projects integrating Sphinx functionality
-----------------------------------------
-* `Read the Docs`__, a software-as-a-service documentation hosting platform, uses
- Sphinx to automatically build documentation updates that are pushed to GitHub
+* `Read the Docs <https://readthedocs.org/>`__, a software-as-a-service documentation hosting platform, uses
+ Sphinx to automatically build documentation updates that are pushed to GitHub.
-* `Spyder`__, the Scientific Python Development Environment, uses Sphinx in its
+* `Spyder <https://docs.spyder-ide.org/help.html>`__, the Scientific Python Development Environment, uses Sphinx in its
help pane to render rich documentation for functions, classes and methods
- automatically or on-demand
-
- __ https://readthedocs.org/
- __ https://docs.spyder-ide.org/help.html
+ automatically or on-demand.
diff --git a/doc/conf.py b/doc/conf.py
index 724d355d0..e06d70150 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -144,3 +144,10 @@ def setup(app):
names=['param'], can_collapse=True)
app.add_object_type('event', 'event', 'pair: %s; event', parse_event,
doc_field_types=[fdesc])
+
+ # workaround for RTD
+ from sphinx.util import logging
+ logger = logging.getLogger(__name__)
+ app.info = lambda *args, **kwargs: logger.info(*args, **kwargs)
+ app.warn = lambda *args, **kwargs: logger.warning(*args, **kwargs)
+ app.debug = lambda *args, **kwargs: logger.debug(*args, **kwargs)
diff --git a/doc/develop.rst b/doc/develop.rst
index d2a51b8e2..60ccaf79b 100644
--- a/doc/develop.rst
+++ b/doc/develop.rst
@@ -127,7 +127,7 @@ own extensions.
.. _NumPy style: https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
.. _hyphenator: https://github.com/mnater/hyphenator
.. _exceltable: https://pythonhosted.org/sphinxcontrib-exceltable/
-.. _YouTube: http://www.youtube.com/
+.. _YouTube: https://www.youtube.com/
.. _ClearQuest: https://www.ibm.com/us-en/marketplace/rational-clearquest
.. _Zope interfaces: https://zopeinterface.readthedocs.io/en/latest/README.html
.. _slideshare: https://www.slideshare.net/
diff --git a/doc/extdev/appapi.rst b/doc/extdev/appapi.rst
index ee612765c..5509d6a91 100644
--- a/doc/extdev/appapi.rst
+++ b/doc/extdev/appapi.rst
@@ -115,32 +115,6 @@ Emitting events
.. automethod:: emit_firstresult(event, \*arguments)
-Producing messages / logging
-----------------------------
-
-The application object also provides support for emitting leveled messages.
-
-.. note::
-
- There is no "error" call: in Sphinx, errors are defined as things that stop
- the build; just raise an exception (:exc:`sphinx.errors.SphinxError` or a
- custom subclass) to do that.
-
-.. deprecated:: 1.6
-
- Please use :ref:`logging-api` instead.
-
-.. automethod:: Sphinx.warn
-
-.. automethod:: Sphinx.info
-
-.. automethod:: Sphinx.verbose
-
-.. automethod:: Sphinx.debug
-
-.. automethod:: Sphinx.debug2
-
-
Sphinx runtime information
--------------------------
diff --git a/doc/extdev/envapi.rst b/doc/extdev/envapi.rst
index 442cfde15..818a50f8d 100644
--- a/doc/extdev/envapi.rst
+++ b/doc/extdev/envapi.rst
@@ -39,10 +39,6 @@ Build environment API
**Utility methods**
- .. automethod:: warn
-
- .. automethod:: warn_node
-
.. automethod:: doc2path
.. automethod:: relfn2path
diff --git a/doc/extdev/index.rst b/doc/extdev/index.rst
index bbfcd4188..b75afc40c 100644
--- a/doc/extdev/index.rst
+++ b/doc/extdev/index.rst
@@ -122,6 +122,31 @@ The following is a list of deprecated interfaces.
- (will be) Removed
- Alternatives
+ * - ``suffix`` argument of ``BuildEnvironment.doc2path()``
+ - 2.0
+ - 4.0
+ - N/A
+
+ * - string style ``base`` argument of ``BuildEnvironment.doc2path()``
+ - 2.0
+ - 4.0
+ - ``os.path.join()``
+
+ * - ``sphinx.ext.doctest.doctest_encode()``
+ - 2.0
+ - 4.0
+ - N/A
+
+ * - ``sphinx.testing.util.remove_unicode_literal()``
+ - 2.0
+ - 4.0
+ - N/A
+
+ * - ``sphinx.util.osutil.walk()``
+ - 2.0
+ - 4.0
+ - ``os.walk()``
+
* - :rst:dir:`highlightlang`
- 1.8
- 4.0
diff --git a/doc/faq.rst b/doc/faq.rst
index b2d6cc9e6..021143f40 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -205,7 +205,7 @@ The following list gives some hints for the creation of epub files:
.. _Epubcheck: https://github.com/IDPF/epubcheck
.. _Calibre: https://calibre-ebook.com/
.. _FBreader: https://fbreader.org/
-.. _Bookworm: http://www.oreilly.com/bookworm/index.html
+.. _Bookworm: https://www.oreilly.com/bookworm/index.html
.. _kindlegen: https://www.amazon.com/gp/feature.html?docId=1000765211
.. _texinfo-faq:
diff --git a/doc/intl.rst b/doc/intl.rst
index 129665dde..ab062dca1 100644
--- a/doc/intl.rst
+++ b/doc/intl.rst
@@ -326,4 +326,4 @@ There is `sphinx translation page`_ for Sphinx (master) documentation.
.. _`sphinx-intl`: https://pypi.org/project/sphinx-intl/
.. _Transifex: https://www.transifex.com/
.. _`sphinx translation page`: https://www.transifex.com/sphinx-doc/sphinx-doc/
-.. _`Transifex Client documentation`: http://docs.transifex.com/developer/client/
+.. _`Transifex Client documentation`: https://docs.transifex.com/client/introduction/
diff --git a/doc/intro.rst b/doc/intro.rst
index d44003b71..622d16b83 100644
--- a/doc/intro.rst
+++ b/doc/intro.rst
@@ -55,15 +55,13 @@ See the :ref:`pertinent section in the FAQ list <usingwith>`.
Prerequisites
-------------
-Sphinx needs at least **Python 2.7** or **Python 3.4** to run, as well as the
-docutils_ and Jinja2_ libraries. Sphinx should work with docutils version 0.10
-or some (not broken) SVN trunk snapshot. If you like to have source code
-highlighting support, you must also install the Pygments_ library.
+Sphinx needs at least **Python 3.5** to run, as well as the docutils_ and
+Jinja2_ libraries. Sphinx should work with docutils version 0.12 or some (not
+broken) SVN trunk snapshot.
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _docutils: http://docutils.sourceforge.net/
.. _Jinja2: http://jinja.pocoo.org/
-.. _Pygments: http://pygments.org/
Usage
diff --git a/doc/usage/builders/index.rst b/doc/usage/builders/index.rst
index bb107162c..e7ad13bd1 100644
--- a/doc/usage/builders/index.rst
+++ b/doc/usage/builders/index.rst
@@ -165,16 +165,17 @@ The builder's "name" must be given to the **-b** command-line option of
* ``texlive-fonts-recommended``
* ``texlive-latex-extra``
* ``latexmk`` (for ``make latexpdf`` on GNU/Linux and MacOS X)
- * ``latex-xcolor`` (old Ubuntu)
* ``texlive-luatex``, ``texlive-xetex`` (see :confval:`latex_engine`)
- The testing of Sphinx LaTeX is done on Ubuntu trusty with the above
- mentioned packages, which are from a TeXLive 2013 snapshot dated
- February 2014.
+ The testing of Sphinx LaTeX is done on Ubuntu xenial with the above mentioned
+ packages, which are from a TeXLive 2015 snapshot dated March 2016.
.. versionchanged:: 1.6
Formerly, testing had been done on Ubuntu precise (TeXLive 2009).
+ .. versionchanged:: 2.0
+ Formerly, testing had been done on Ubuntu trusty (TeXLive 2013).
+
.. note::
Since 1.6, ``make latexpdf`` uses ``latexmk`` (not on Windows). This
@@ -215,7 +216,7 @@ Note that a direct PDF builder is being provided by `rinohtype`_. The builder's
name is ``rinoh``. Refer to the `rinohtype manual`_ for details.
.. _rinohtype: https://github.com/brechtm/rinohtype
-.. _rinohtype manual: http://www.mos6581.org/rinohtype/quickstart.html#sphinx-builder
+.. _rinohtype manual: https://www.mos6581.org/rinohtype/quickstart.html#sphinx-builder
.. module:: sphinx.builders.text
.. class:: TextBuilder
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index 208cd24a2..e7be5fb44 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -149,7 +149,10 @@ General configuration
.. confval:: master_doc
The document name of the "master" document, that is, the document that
- contains the root :rst:dir:`toctree` directive. Default is ``'contents'``.
+ contains the root :rst:dir:`toctree` directive. Default is ``'index'``.
+
+ .. versionchanged:: 2.0
+ The defualt is changed to ``'index'`` from ``'contents'``.
.. confval:: exclude_patterns
@@ -1108,12 +1111,6 @@ that use Sphinx's HTMLWriter class.
If true, the reST sources are included in the HTML build as
:file:`_sources/{name}`. The default is ``True``.
- .. warning::
-
- If this config value is set to ``False``, the JavaScript search function
- will only display the titles of matching documents, and no excerpt from
- the matching contents.
-
.. confval:: html_show_sourcelink
If true (and :confval:`html_copy_source` is true as well), links to the
@@ -1251,7 +1248,7 @@ that use Sphinx's HTMLWriter class.
:'sphinx.search.ja.DefaultSplitter':
TinySegmenter algorithm. This is default splitter.
- :'sphinx.search.ja.MeCabSplitter':
+ :'sphinx.search.ja.MecabSplitter':
MeCab binding. To use this splitter, 'mecab' python binding or dynamic
link library ('libmecab.so' for linux, 'libmecab.dll' for windows) is
required.
@@ -1353,6 +1350,19 @@ Options for HTML help output
Output file base name for HTML help builder. Default is ``'pydoc'``.
+.. confval:: htmlhelp_file_suffix
+
+ This is the file name suffix for generated HTML help files. The
+ default is ``".html"``.
+
+ .. versionadded:: 2.0
+
+.. confval:: htmlhelp_link_suffix
+
+ Suffix for generated links to HTML files. The default is ``".html"``.
+
+ .. versionadded:: 2.0
+
.. _applehelp-options:
diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst
index d33378435..e604cad28 100644
--- a/doc/usage/extensions/autodoc.rst
+++ b/doc/usage/extensions/autodoc.rst
@@ -45,6 +45,10 @@ docstrings to correct reStructuredText before :mod:`autodoc` processes them.
.. _NumPy:
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+Directives
+----------
+
:mod:`autodoc` provides several directives that are versions of the usual
:rst:dir:`py:module`, :rst:dir:`py:class` and so forth. On parsing time, they
import the corresponding module and extract the docstring of the given objects,
@@ -306,6 +310,9 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
well-behaved decorating functions.
+Configuration
+-------------
+
There are also new config values that you can set:
.. confval:: autoclass_content
@@ -432,6 +439,16 @@ There are also new config values that you can set:
.. versionadded:: 1.7
+.. confval:: suppress_warnings
+ :noindex:
+
+ :mod:`autodoc` supports to suppress warning messages via
+ :confval:`suppress_warnings`. It allows following warnings types in
+ addition:
+
+ * autodoc
+ * autodoc.import_object
+
Docstring preprocessing
-----------------------
diff --git a/doc/usage/extensions/example_google.py b/doc/usage/extensions/example_google.py
index 4f6abacdf..07870297e 100644
--- a/doc/usage/extensions/example_google.py
+++ b/doc/usage/extensions/example_google.py
@@ -178,7 +178,7 @@ class ExampleError(Exception):
self.code = code
-class ExampleClass(object):
+class ExampleClass:
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
diff --git a/doc/usage/extensions/example_numpy.py b/doc/usage/extensions/example_numpy.py
index dbee080c3..479aea489 100644
--- a/doc/usage/extensions/example_numpy.py
+++ b/doc/usage/extensions/example_numpy.py
@@ -223,7 +223,7 @@ class ExampleError(Exception):
self.code = code
-class ExampleClass(object):
+class ExampleClass:
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
diff --git a/doc/usage/extensions/inheritance.rst b/doc/usage/extensions/inheritance.rst
index ef78d04fe..c66f4130f 100644
--- a/doc/usage/extensions/inheritance.rst
+++ b/doc/usage/extensions/inheritance.rst
@@ -54,7 +54,7 @@ It adds this directive:
E D F
"""
- class A(object):
+ class A:
pass
class B(A):
diff --git a/doc/usage/extensions/math.rst b/doc/usage/extensions/math.rst
index 9daa03186..9e62c1425 100644
--- a/doc/usage/extensions/math.rst
+++ b/doc/usage/extensions/math.rst
@@ -183,7 +183,7 @@ Sphinx.
The default is empty (not configured).
-.. _Using in-line configuration options: http://docs.mathjax.org/en/latest/configuration.html#using-in-line-configuration-options
+.. _Using in-line configuration options: https://docs.mathjax.org/en/latest/configuration.html#using-in-line-configuration-options
:mod:`sphinx.ext.jsmath` -- Render math via JavaScript
------------------------------------------------------
diff --git a/doc/usage/extensions/napoleon.rst b/doc/usage/extensions/napoleon.rst
index 504ef015a..dc52e6375 100644
--- a/doc/usage/extensions/napoleon.rst
+++ b/doc/usage/extensions/napoleon.rst
@@ -409,10 +409,10 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
.. attribute:: attr1
- *int*
-
Description of `attr1`
+ :type: int
+
.. confval:: napoleon_use_param
True to use a ``:param:`` role for each function parameter. False to
diff --git a/doc/usage/installation.rst b/doc/usage/installation.rst
index 5c0d7de75..7efb6735d 100644
--- a/doc/usage/installation.rst
+++ b/doc/usage/installation.rst
@@ -12,10 +12,9 @@ Installing Sphinx
Overview
--------
-Sphinx is written in `Python`__ and supports both Python 2.7 and Python 3.3+.
-We recommend the latter.
+Sphinx is written in `Python`__ and supports Python 3.5+.
-__ http://docs.python-guide.org/en/latest/
+__ https://docs.python-guide.org/
Linux
@@ -73,7 +72,7 @@ Homebrew
For more information, refer to the `package overview`__.
-__ http://formulae.brew.sh/formula/sphinx-doc
+__ https://formulae.brew.sh/formula/sphinx-doc
MacPorts
~~~~~~~~
@@ -121,9 +120,9 @@ Once Python is installed, you can install Sphinx using :command:`pip`. Refer
to the :ref:`pip installation instructions <install-pypi>` below for more
information.
-__ http://docs.python-guide.org/en/latest/
-__ http://docs.python-guide.org/en/latest/starting/install3/win/
-__ http://docs.python-guide.org/en/latest/starting/install/win/
+__ https://docs.python-guide.org/
+__ https://docs.python-guide.org/starting/install3/win/
+__ https://docs.python-guide.org/starting/install/win/
.. _install-pypi:
diff --git a/doc/usage/markdown.rst b/doc/usage/markdown.rst
index f67b94cbd..ed0cce013 100644
--- a/doc/usage/markdown.rst
+++ b/doc/usage/markdown.rst
@@ -15,7 +15,7 @@ parsing the `CommonMark`__ Markdown flavor.
__ https://daringfireball.net/projects/markdown/
__ https://recommonmark.readthedocs.io/en/latest/index.html
__ https://github.com/rtfd/CommonMark-py
-__ http://commonmark.org/
+__ https://commonmark.org/
Configuration
-------------
diff --git a/setup.py b/setup.py
index b6b3bc259..ec5d3e860 100644
--- a/setup.py
+++ b/setup.py
@@ -11,15 +11,15 @@ import sphinx
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.')
+if sys.version_info < (3, 5):
+ print('ERROR: Sphinx requires at least Python 3.5 to run.')
sys.exit(1)
install_requires = [
'six>=1.5',
'Jinja2>=2.3',
'Pygments>=2.0',
- 'docutils>=0.11',
+ 'docutils>=0.12',
'snowballstemmer>=1.1',
'babel>=1.3,!=2.0',
'alabaster>=0.7,<0.8',
@@ -27,7 +27,6 @@ install_requires = [
'requests>=2.0.0',
'setuptools',
'packaging',
- 'sphinxcontrib-websupport',
]
extras_require = {
@@ -35,9 +34,6 @@ extras_require = {
':sys_platform=="win32"': [
'colorama>=0.3.5',
],
- ':python_version<"3.5"': [
- 'typing'
- ],
'websupport': [
'sqlalchemy>=0.9',
'whoosh>=2.0',
@@ -49,11 +45,6 @@ extras_require = {
'html5lib',
'flake8>=3.5.0',
'flake8-import-order',
- ],
- 'test:python_version<"3"': [
- 'enum34',
- ],
- 'test:python_version>="3"': [
'mypy',
'typed_ast',
],
@@ -65,7 +56,7 @@ extras_require = {
cmdclass = {}
-class Tee(object):
+class Tee:
def __init__(self, stream):
self.stream = stream
self.buffer = StringIO()
@@ -195,12 +186,11 @@ setup(
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Framework :: Setuptools Plugin',
@@ -235,7 +225,7 @@ setup(
'build_sphinx = sphinx.setup_command:BuildDoc',
],
},
- python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
+ python_requires=">=3.5",
install_requires=install_requires,
extras_require=extras_require,
cmdclass=cmdclass,
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 9b1405728..cdd3b0418 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -15,12 +15,10 @@
from __future__ import absolute_import
import os
-import sys
import warnings
from os import path
from .deprecation import RemovedInNextVersionWarning
-from .deprecation import RemovedInSphinx20Warning
if False:
# For type annotation
@@ -37,8 +35,8 @@ if 'PYTHONWARNINGS' not in os.environ:
warnings.filterwarnings('ignore', "'U' mode is deprecated",
DeprecationWarning, module='docutils.io')
-__version__ = '1.8.2+'
-__released__ = '1.8.2' # used when Sphinx builds its own docs
+__version__ = '2.0.0+'
+__released__ = '2.0.0' # used when Sphinx builds its own docs
#: Version info for better programmatic use.
#:
@@ -48,7 +46,7 @@ __released__ = '1.8.2' # used when Sphinx builds its own docs
#:
#: .. versionadded:: 1.2
#: Before version 1.2, check the string ``sphinx.__version__``.
-version_info = (1, 8, 2, 'beta', 0)
+version_info = (2, 0, 0, 'beta', 0)
package_dir = path.abspath(path.dirname(__file__))
@@ -68,47 +66,3 @@ if __version__.endswith('+'):
__display_version__ += '/' + out.decode().strip()
except Exception:
pass
-
-
-def main(argv=sys.argv): # type: ignore
- # type: (List[unicode]) -> int
- from .cmd import build
- warnings.warn(
- '`sphinx.main()` has moved to `sphinx.cmd.build.main()`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- argv = argv[1:] # skip first argument to adjust arguments (refs: #4615)
- return build.main(argv)
-
-
-def build_main(argv=sys.argv):
- """Sphinx build "main" command-line entry."""
- from .cmd import build
- warnings.warn(
- '`sphinx.build_main()` has moved to `sphinx.cmd.build.build_main()`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- return build.build_main(argv[1:]) # skip first argument to adjust arguments (refs: #4615)
-
-
-def make_main(argv=sys.argv):
- """Sphinx build "make mode" entry."""
- from .cmd import build
- warnings.warn(
- '`sphinx.build_main()` has moved to `sphinx.cmd.build.make_main()`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- return build.make_main(argv[1:]) # skip first argument to adjust arguments (refs: #4615)
-
-
-if __name__ == '__main__':
- from .cmd import build
- warnings.warn(
- '`sphinx` has moved to `sphinx.build`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- build.main()
diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py
index 331fe5225..b69533751 100644
--- a/sphinx/addnodes.py
+++ b/sphinx/addnodes.py
@@ -20,7 +20,7 @@ if False:
from typing import List, Sequence # NOQA
-class translatable(object):
+class translatable:
"""Node which supports translation.
The translation goes forward with following steps:
@@ -53,7 +53,7 @@ class translatable(object):
raise NotImplementedError
-class not_smartquotable(object):
+class not_smartquotable:
"""A node which does not support smart-quotes."""
support_smartquotes = False
diff --git a/sphinx/apidoc.py b/sphinx/apidoc.py
deleted file mode 100644
index 95a1d14f7..000000000
--- a/sphinx/apidoc.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.apidoc
- ~~~~~~~~~~~~~
-
- This file has moved to :py:mod:`sphinx.ext.apidoc`.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-import sys
-import warnings
-
-from sphinx.deprecation import RemovedInSphinx20Warning
-from sphinx.ext.apidoc import main as _main
-
-if False:
- # For type annotation
- from typing import List # NOQA
- from sphinx.application import Sphinx # NOQA
-
-
-def main(argv=sys.argv):
- # type: (List[str]) -> None
- warnings.warn(
- '`sphinx.apidoc.main()` has moved to `sphinx.ext.apidoc.main()`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- _main(argv[1:]) # skip first argument to adjust arguments (refs: #4615)
-
-
-# So program can be started with "python -m sphinx.apidoc ..."
-if __name__ == "__main__":
- warnings.warn(
- '`sphinx.apidoc` has moved to `sphinx.ext.apidoc`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- main()
diff --git a/sphinx/application.py b/sphinx/application.py
index 64433915a..c595b7719 100644
--- a/sphinx/application.py
+++ b/sphinx/application.py
@@ -13,6 +13,7 @@
from __future__ import print_function
import os
+import pickle
import sys
import warnings
from collections import deque
@@ -20,8 +21,6 @@ from inspect import isclass
from os import path
from docutils.parsers.rst import Directive, directives, roles
-from six import itervalues
-from six.moves import cPickle as pickle
from six.moves import cStringIO
import sphinx
@@ -29,7 +28,7 @@ from sphinx import package_dir, locale
from sphinx.config import Config, check_unicode
from sphinx.config import CONFIG_FILENAME # NOQA # for compatibility (RemovedInSphinx30)
from sphinx.deprecation import (
- RemovedInSphinx20Warning, RemovedInSphinx30Warning, RemovedInSphinx40Warning
+ RemovedInSphinx30Warning, RemovedInSphinx40Warning
)
from sphinx.environment import BuildEnvironment
from sphinx.errors import ApplicationError, ConfigError, VersionRequirementError
@@ -118,7 +117,7 @@ ENV_PICKLE_FILENAME = 'environment.pickle'
logger = logging.getLogger(__name__)
-class Sphinx(object):
+class Sphinx:
"""The main application class and extensibility interface.
:ivar srcdir: Directory containing source.
@@ -250,11 +249,6 @@ class Sphinx(object):
self.config.init_values()
self.emit('config-inited', self.config)
- # check primary_domain if requested
- primary_domain = self.config.primary_domain
- if primary_domain and not self.registry.has_domain(primary_domain):
- logger.warning(__('primary_domain %r not found, ignored.'), primary_domain)
-
# create the builder
self.builder = self.create_builder(buildername)
# set up the build environment
@@ -369,72 +363,6 @@ class Sphinx(object):
self.emit('build-finished', None)
self.builder.cleanup()
- # ---- logging handling ----------------------------------------------------
- def warn(self, message, location=None, type=None, subtype=None):
- # type: (unicode, unicode, unicode, unicode) -> None
- """Emit a warning.
-
- If *location* is given, it should either be a tuple of (*docname*,
- *lineno*) or a string describing the location of the warning as well as
- possible.
-
- *type* and *subtype* are used to suppress warnings with
- :confval:`suppress_warnings`.
-
- .. deprecated:: 1.6
- Use :mod:`sphinx.util.logging` instead.
- """
- warnings.warn('app.warning() is now deprecated. Use sphinx.util.logging instead.',
- RemovedInSphinx20Warning)
- logger.warning(message, type=type, subtype=subtype, location=location)
-
- def info(self, message='', nonl=False):
- # type: (unicode, bool) -> None
- """Emit an informational message.
-
- If *nonl* is true, don't emit a newline at the end (which implies that
- more info output will follow soon.)
-
- .. deprecated:: 1.6
- Use :mod:`sphinx.util.logging` instead.
- """
- warnings.warn('app.info() is now deprecated. Use sphinx.util.logging instead.',
- RemovedInSphinx20Warning)
- logger.info(message, nonl=nonl)
-
- def verbose(self, message, *args, **kwargs):
- # type: (unicode, Any, Any) -> None
- """Emit a verbose informational message.
-
- .. deprecated:: 1.6
- Use :mod:`sphinx.util.logging` instead.
- """
- warnings.warn('app.verbose() is now deprecated. Use sphinx.util.logging instead.',
- RemovedInSphinx20Warning)
- logger.verbose(message, *args, **kwargs)
-
- def debug(self, message, *args, **kwargs):
- # type: (unicode, Any, Any) -> None
- """Emit a debug-level informational message.
-
- .. deprecated:: 1.6
- Use :mod:`sphinx.util.logging` instead.
- """
- warnings.warn('app.debug() is now deprecated. Use sphinx.util.logging instead.',
- RemovedInSphinx20Warning)
- logger.debug(message, *args, **kwargs)
-
- def debug2(self, message, *args, **kwargs):
- # type: (unicode, Any, Any) -> None
- """Emit a lowlevel debug-level informational message.
-
- .. deprecated:: 1.6
- Use :mod:`sphinx.util.logging` instead.
- """
- warnings.warn('app.debug2() is now deprecated. Use debug() instead.',
- RemovedInSphinx20Warning)
- logger.debug(message, *args, **kwargs)
-
# ---- general extensibility interface -------------------------------------
def setup_extension(self, extname):
@@ -913,21 +841,6 @@ class Sphinx(object):
ref_nodeclass, objname, doc_field_types,
override=override)
- def add_description_unit(self, directivename, rolename, indextemplate='',
- parse_node=None, ref_nodeclass=None, objname='',
- doc_field_types=[]):
- # type: (unicode, unicode, unicode, Callable, nodes.Node, unicode, List) -> None
- """Deprecated alias for :meth:`add_object_type`.
-
- .. deprecated:: 1.6
- Use :meth:`add_object_type` instead.
- """
- warnings.warn('app.add_description_unit() is now deprecated. '
- 'Use app.add_object_type() instead.',
- RemovedInSphinx20Warning)
- self.add_object_type(directivename, rolename, indextemplate, parse_node,
- ref_nodeclass, objname, doc_field_types)
-
def add_crossref_type(self, directivename, rolename, indextemplate='',
ref_nodeclass=None, objname='', override=False):
# type: (unicode, unicode, unicode, nodes.Node, unicode, bool) -> None
@@ -1282,7 +1195,7 @@ class Sphinx(object):
else:
raise ValueError('parallel type %s is not supported' % typ)
- for ext in itervalues(self.extensions):
+ for ext in self.extensions.values():
allowed = getattr(ext, attrname, None)
if allowed is None:
logger.warning(message, ext.name)
@@ -1294,7 +1207,7 @@ class Sphinx(object):
return True
-class TemplateBridge(object):
+class TemplateBridge:
"""
This class defines the interface for a "template bridge", that is, a class
that renders templates given a template name and a context.
diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py
index 9c7537631..077ab6abe 100644
--- a/sphinx/builders/__init__.py
+++ b/sphinx/builders/__init__.py
@@ -9,14 +9,12 @@
:license: BSD, see LICENSE for details.
"""
+import pickle
import time
-import warnings
from os import path
from docutils import nodes
-from six.moves import cPickle as pickle
-from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment import CONFIG_OK, CONFIG_CHANGED_REASON
from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.errors import SphinxError
@@ -54,7 +52,7 @@ if False:
logger = logging.getLogger(__name__)
-class Builder(object):
+class Builder:
"""
Builds target formats from the reST sources.
"""
@@ -97,8 +95,6 @@ class Builder(object):
self.app = app # type: Sphinx
self.env = None # type: BuildEnvironment
- self.warn = app.warn # type: Callable
- self.info = app.info # type: Callable
self.config = app.config # type: Config
self.tags = app.tags # type: Tags
self.tags.add(self.format)
@@ -138,22 +134,6 @@ class Builder(object):
"""
return self.app.registry.create_translator(self, *args)
- @property
- def translator_class(self):
- # type: () -> Callable[[Any], nodes.NodeVisitor]
- """Return a class of translator.
-
- .. deprecated:: 1.6
- """
- translator_class = self.app.registry.get_translator_class(self)
- if translator_class is None and self.default_translator_class is None:
- warnings.warn('builder.translator_class() is now deprecated. '
- 'Please use builder.create_translator() and '
- 'builder.default_translator_class instead.',
- RemovedInSphinx20Warning)
- return None
- return self.create_translator
-
# helper methods
def init(self):
# type: () -> None
@@ -556,7 +536,7 @@ class Builder(object):
doctree.settings.env = None
doctree.settings.record_dependencies = None
- doctree_filename = self.env.doc2path(docname, self.env.doctreedir, '.doctree')
+ doctree_filename = path.join(self.doctreedir, docname + '.doctree')
ensuredir(path.dirname(doctree_filename))
with open(doctree_filename, 'wb') as f:
pickle.dump(doctree, f, pickle.HIGHEST_PROTOCOL)
diff --git a/sphinx/builders/applehelp.py b/sphinx/builders/applehelp.py
index 79d57210c..b29ce3d95 100644
--- a/sphinx/builders/applehelp.py
+++ b/sphinx/builders/applehelp.py
@@ -10,7 +10,6 @@
"""
from __future__ import print_function
-import codecs
import pipes
import plistlib
import shlex
@@ -36,13 +35,6 @@ if False:
logger = logging.getLogger(__name__)
-# Use plistlib.dump in 3.4 and above
-try:
- write_plist = plistlib.dump # type: ignore
-except AttributeError:
- write_plist = plistlib.writePlist
-
-
# False access page (used because helpd expects strict XHTML)
access_page_template = '''\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\
@@ -174,7 +166,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
logger.info(bold(__('writing Info.plist... ')), nonl=True)
with open(path.join(contents_dir, 'Info.plist'), 'wb') as f:
- write_plist(info_plist, f)
+ plistlib.dump(info_plist, f) # type: ignore
logger.info(__('done'))
# Copy the icon, if one is supplied
@@ -193,7 +185,7 @@ class AppleHelpBuilder(StandaloneHTMLBuilder):
# Build the access page
logger.info(bold(__('building access page...')), nonl=True)
- with codecs.open(path.join(language_dir, '_access.html'), 'w') as f: # type: ignore
+ with open(path.join(language_dir, '_access.html'), 'w') as f:
f.write(access_page_template % {
'toc': htmlescape(toc, quote=True),
'title': htmlescape(self.config.applehelp_title)
diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py
index 3f9bffa0d..888a011da 100644
--- a/sphinx/builders/changes.py
+++ b/sphinx/builders/changes.py
@@ -9,12 +9,9 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
from os import path
from typing import cast
-from six import iteritems
-
from sphinx import package_dir
from sphinx.builders import Builder
from sphinx.domains.changeset import ChangeSetDomain
@@ -109,15 +106,17 @@ class ChangesBuilder(Builder):
'version': version,
'docstitle': self.config.html_title,
'shorttitle': self.config.html_short_title,
- 'libchanges': sorted(iteritems(libchanges)),
+ 'libchanges': sorted(libchanges.items()),
'apichanges': sorted(apichanges),
- 'otherchanges': sorted(iteritems(otherchanges)),
+ 'otherchanges': sorted(otherchanges.items()),
'show_copyright': self.config.html_show_copyright,
'show_sphinx': self.config.html_show_sphinx,
}
- with codecs.open(path.join(self.outdir, 'index.html'), 'w', 'utf8') as f: # type: ignore # NOQA
+ with open(path.join(self.outdir, 'index.html'), 'w', # type: ignore
+ encoding='utf8') as f:
f.write(self.templates.render('changes/frameset.html', ctx))
- with codecs.open(path.join(self.outdir, 'changes.html'), 'w', 'utf8') as f: # type: ignore # NOQA
+ with open(path.join(self.outdir, 'changes.html'), 'w', # type: ignore
+ encoding='utf8') as f:
f.write(self.templates.render('changes/versionchanges.html', ctx))
hltext = ['.. versionadded:: %s' % version,
@@ -135,8 +134,8 @@ class ChangesBuilder(Builder):
logger.info(bold(__('copying source files...')))
for docname in self.env.all_docs:
- with codecs.open(self.env.doc2path(docname), 'r', # type: ignore
- self.env.config.source_encoding) as f:
+ with open(self.env.doc2path(docname), 'r', # type: ignore
+ encoding=self.env.config.source_encoding) as f:
try:
lines = f.readlines()
except UnicodeDecodeError:
@@ -144,7 +143,7 @@ class ChangesBuilder(Builder):
continue
targetfn = path.join(self.outdir, 'rst', os_path(docname)) + '.html'
ensuredir(path.dirname(targetfn))
- with codecs.open(targetfn, 'w', 'utf-8') as f: # type: ignore
+ with open(targetfn, 'w', encoding='utf-8') as f: # type: ignore
text = ''.join(hl(i + 1, line) for (i, line) in enumerate(lines))
ctx = {
'filename': self.env.doc2path(docname, None),
@@ -152,7 +151,7 @@ class ChangesBuilder(Builder):
}
f.write(self.templates.render('changes/rstsource.html', ctx))
themectx = dict(('theme_' + key, val) for (key, val) in
- iteritems(self.theme.get_options({})))
+ self.theme.get_options({}).items())
copy_asset_file(path.join(package_dir, 'themes', 'default', 'static', 'default.css_t'),
self.outdir, context=themectx, renderer=self.templates)
copy_asset_file(path.join(package_dir, 'themes', 'basic', 'static', 'basic.css'),
diff --git a/sphinx/builders/devhelp.py b/sphinx/builders/devhelp.py
index fc2c0b1c9..f81154984 100644
--- a/sphinx/builders/devhelp.py
+++ b/sphinx/builders/devhelp.py
@@ -15,6 +15,7 @@ from __future__ import absolute_import
import gzip
import re
from os import path
+from typing import Any
from docutils import nodes
@@ -23,6 +24,7 @@ from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.environment.adapters.indexentries import IndexEntries
from sphinx.locale import __
from sphinx.util import logging
+from sphinx.util.nodes import NodeMatcher
from sphinx.util.osutil import make_filename
try:
@@ -32,7 +34,7 @@ except ImportError:
if False:
# For type annotation
- from typing import Any, Dict, List # NOQA
+ from typing import Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
@@ -100,12 +102,8 @@ class DevhelpBuilder(StandaloneHTMLBuilder):
parent.attrib['link'] = node['refuri']
parent.attrib['name'] = node.astext()
- def istoctree(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, addnodes.compact_paragraph) and \
- 'toctree' in node
-
- for node in tocdoc.traverse(istoctree):
+ matcher = NodeMatcher(addnodes.compact_paragraph, toctree=Any)
+ for node in tocdoc.traverse(matcher):
write_toc(node, chapters)
# Index
diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py
index 9981012a0..fbec9aae2 100644
--- a/sphinx/builders/gettext.py
+++ b/sphinx/builders/gettext.py
@@ -18,7 +18,7 @@ from os import path, walk, getenv
from time import time
from uuid import uuid4
-from six import iteritems, StringIO
+from six import StringIO
from sphinx.builders import Builder
from sphinx.domains.python import pairindextypes
@@ -63,7 +63,7 @@ msgstr ""
"""[1:]
-class Catalog(object):
+class Catalog:
"""Catalog of translatable messages."""
def __init__(self):
@@ -85,7 +85,7 @@ class Catalog(object):
self.metadata[msg].append((origin.source, origin.line, origin.uid))
-class MsgOrigin(object):
+class MsgOrigin:
"""
Origin holder for Catalog message origin.
"""
@@ -272,7 +272,7 @@ class MessageCatalogBuilder(I18nBuilder):
ctime = datetime.fromtimestamp(
timestamp, ltz).strftime('%Y-%m-%d %H:%M%z'),
)
- for textdomain, catalog in status_iterator(iteritems(self.catalogs), # type: ignore
+ for textdomain, catalog in status_iterator(self.catalogs.items(), # type: ignore
__("writing message catalogs... "),
"darkgreen", len(self.catalogs),
self.app.verbosity,
diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py
index e8558d054..9689b34ff 100644
--- a/sphinx/builders/html.py
+++ b/sphinx/builders/html.py
@@ -9,7 +9,7 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
+import pickle
import posixpath
import re
import sys
@@ -25,14 +25,13 @@ from docutils.frontend import OptionParser
from docutils.io import DocTreeInput, StringOutput
from docutils.readers.doctree import Reader as DoctreeReader
from docutils.utils import relative_path
-from six import iteritems, text_type, string_types
-from six.moves import cPickle as pickle
+from six import text_type, string_types
from sphinx import package_dir, __display_version__
from sphinx.application import ENV_PICKLE_FILENAME
from sphinx.builders import Builder
from sphinx.config import string_classes
-from sphinx.deprecation import RemovedInSphinx20Warning, RemovedInSphinx30Warning
+from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.environment.adapters.indexentries import IndexEntries
from sphinx.environment.adapters.toctree import TocTree
@@ -92,53 +91,6 @@ def get_stable_hash(obj):
return md5(text_type(obj).encode('utf8')).hexdigest()
-class CSSContainer(list):
- """The container for stylesheets.
-
- To support the extensions which access the container directly, this wraps
- the entry with Stylesheet class.
- """
- def append(self, obj):
- # type: (Union[unicode, Stylesheet]) -> None
- if isinstance(obj, Stylesheet):
- super(CSSContainer, self).append(obj)
- else:
- super(CSSContainer, self).append(Stylesheet(obj))
-
- def insert(self, index, obj):
- # type: (int, Union[unicode, Stylesheet]) -> None
- warnings.warn('builder.css_files is deprecated. '
- 'Please use app.add_stylesheet() instead.',
- RemovedInSphinx20Warning)
- if isinstance(obj, Stylesheet):
- super(CSSContainer, self).insert(index, obj)
- else:
- super(CSSContainer, self).insert(index, Stylesheet(obj))
-
- def extend(self, other): # type: ignore
- # type: (List[Union[unicode, Stylesheet]]) -> None
- warnings.warn('builder.css_files is deprecated. '
- 'Please use app.add_stylesheet() instead.',
- RemovedInSphinx20Warning)
- for item in other:
- self.append(item)
-
- def __iadd__(self, other): # type: ignore
- # type: (List[Union[unicode, Stylesheet]]) -> CSSContainer
- warnings.warn('builder.css_files is deprecated. '
- 'Please use app.add_stylesheet() instead.',
- RemovedInSphinx20Warning)
- for item in other:
- self.append(item)
- return self
-
- def __add__(self, other):
- # type: (List[Union[unicode, Stylesheet]]) -> CSSContainer
- ret = CSSContainer(self)
- ret += other
- return ret
-
-
class Stylesheet(text_type):
"""A metadata of stylesheet.
@@ -216,7 +168,7 @@ class JavaScript(text_type):
return self
-class BuildInfo(object):
+class BuildInfo:
"""buildinfo file manipulator.
HTMLBuilder and its family are storing their own envdata to ``.buildinfo``.
@@ -256,10 +208,6 @@ class BuildInfo(object):
return (self.config_hash == other.config_hash and
self.tags_hash == other.tags_hash)
- def __ne__(self, other): # type: ignore
- # type: (BuildInfo) -> bool
- return not (self == other) # for py27
-
def dump(self, f):
# type: (IO) -> None
f.write('# Sphinx build info version 1\n'
@@ -311,7 +259,7 @@ class StandaloneHTMLBuilder(Builder):
super(StandaloneHTMLBuilder, self).__init__(app)
# CSS files
- self.css_files = CSSContainer() # type: List[Dict[unicode, unicode]]
+ self.css_files = [] # type: List[Dict[unicode, unicode]]
# JS files
self.script_files = JSContainer() # type: List[JavaScript]
@@ -330,20 +278,23 @@ class StandaloneHTMLBuilder(Builder):
self.init_highlighter()
self.init_css_files()
self.init_js_files()
- if self.config.html_file_suffix is not None:
- self.out_suffix = self.config.html_file_suffix
- if self.config.html_link_suffix is not None:
- self.link_suffix = self.config.html_link_suffix
+ html_file_suffix = self.get_builder_config('file_suffix', 'html')
+ if html_file_suffix is not None:
+ self.out_suffix = html_file_suffix
+
+ html_link_suffix = self.get_builder_config('link_suffix', 'html')
+ if html_link_suffix is not None:
+ self.link_suffix = html_link_suffix
else:
self.link_suffix = self.out_suffix
self.use_index = self.get_builder_config('use_index', 'html')
if self.config.html_experimental_html5_writer and not html5_ready:
- self.app.warn(('html_experimental_html5_writer is set, but current version '
- 'is old. Docutils\' version should be 0.13 or newer, but %s.') %
- docutils.__version__)
+ logger.warning(__('html_experimental_html5_writer is set, but current version '
+ 'is old. Docutils\' version should be 0.13 or newer, but %s.'),
+ docutils.__version__)
def create_build_info(self):
# type: () -> BuildInfo
@@ -633,7 +584,7 @@ class StandaloneHTMLBuilder(Builder):
if self.theme:
self.globalcontext.update(
('theme_' + key, val) for (key, val) in
- iteritems(self.theme.get_options(self.theme_options)))
+ self.theme.get_options(self.theme_options).items())
self.globalcontext.update(self.config.html_context)
def get_doc_context(self, docname, body, metatags):
@@ -1003,9 +954,9 @@ class StandaloneHTMLBuilder(Builder):
try:
searchindexfn = path.join(self.outdir, self.searchindex_filename)
if self.indexer_dumps_unicode:
- f = codecs.open(searchindexfn, 'r', encoding='utf-8') # type: ignore
+ f = open(searchindexfn, 'r', encoding='utf-8') # type: ignore
else:
- f = open(searchindexfn, 'rb') # type: ignore
+ f = open(searchindexfn, 'rb')
with f:
self.indexer.load(f, self.indexer_format)
except (IOError, OSError, ValueError):
@@ -1067,7 +1018,7 @@ class StandaloneHTMLBuilder(Builder):
# user sidebar settings
html_sidebars = self.get_builder_config('sidebars', 'html')
- for pattern, patsidebars in iteritems(html_sidebars):
+ for pattern, patsidebars in html_sidebars.items():
if patmatch(pagename, pattern):
if matched:
if has_wildcard(pattern):
@@ -1085,14 +1036,6 @@ class StandaloneHTMLBuilder(Builder):
if sidebars is None:
# keep defaults
pass
- elif isinstance(sidebars, string_types):
- # 0.x compatible mode: insert custom sidebar before searchbox
- customsidebar = sidebars
- sidebars = None
- warnings.warn('Now html_sidebars only allows list of sidebar '
- 'templates as a value. Support for a string value '
- 'will be removed at Sphinx-2.0.',
- RemovedInSphinx20Warning)
ctx['sidebars'] = sidebars
ctx['customsidebar'] = customsidebar
@@ -1162,7 +1105,7 @@ class StandaloneHTMLBuilder(Builder):
warnings.warn('The template function warn() was deprecated. '
'Use warning() instead.',
RemovedInSphinx30Warning)
- self.warn(*args, **kwargs)
+ logger.warning(*args, **kwargs)
return '' # return empty string
ctx['warn'] = warn
@@ -1192,7 +1135,8 @@ class StandaloneHTMLBuilder(Builder):
# outfilename's path is in general different from self.outdir
ensuredir(path.dirname(outfilename))
try:
- with codecs.open(outfilename, 'w', ctx['encoding'], 'xmlcharrefreplace') as f: # type: ignore # NOQA
+ with open(outfilename, 'w', # type: ignore
+ encoding=ctx['encoding'], errors='xmlcharrefreplace') as f:
f.write(output)
except (IOError, OSError) as err:
logger.warning(__("error writing file %s: %s"), outfilename, err)
@@ -1229,9 +1173,9 @@ class StandaloneHTMLBuilder(Builder):
# first write to a temporary file, so that if dumping fails,
# the existing index won't be overwritten
if self.indexer_dumps_unicode:
- f = codecs.open(searchindexfn + '.tmp', 'w', encoding='utf-8') # type: ignore
+ f = open(searchindexfn + '.tmp', 'w', encoding='utf-8') # type: ignore
else:
- f = open(searchindexfn + '.tmp', 'wb') # type: ignore
+ f = open(searchindexfn + '.tmp', 'wb')
with f:
self.indexer.dump(f, self.indexer_format)
movefile(searchindexfn + '.tmp', searchindexfn)
@@ -1346,8 +1290,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
# There are related codes in inline_all_toctres() and
# HTMLTranslter#add_secnumber().
new_secnumbers = {} # type: Dict[unicode, Tuple[int, ...]]
- for docname, secnums in iteritems(self.env.toc_secnumbers):
- for id, secnum in iteritems(secnums):
+ for docname, secnums in self.env.toc_secnumbers.items():
+ for id, secnum in secnums.items():
alias = "%s/%s" % (docname, id)
new_secnumbers[alias] = secnum
@@ -1366,11 +1310,11 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
# HTMLTranslter#add_fignumber().
new_fignumbers = {} # type: Dict[unicode, Dict[unicode, Tuple[int, ...]]]
# {u'foo': {'figure': {'id2': (2,), 'id1': (1,)}}, u'bar': {'figure': {'id1': (3,)}}}
- for docname, fignumlist in iteritems(self.env.toc_fignumbers):
- for figtype, fignums in iteritems(fignumlist):
+ for docname, fignumlist in self.env.toc_fignumbers.items():
+ for figtype, fignums in fignumlist.items():
alias = "%s/%s" % (docname, figtype)
new_fignumbers.setdefault(alias, {})
- for id, fignum in iteritems(fignums):
+ for id, fignum in fignums.items():
new_fignumbers[alias][id] = fignum
return {self.config.master_doc: new_fignumbers}
@@ -1488,9 +1432,9 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
def dump_context(self, context, filename):
# type: (Dict, unicode) -> None
if self.implementation_dumps_unicode:
- f = codecs.open(filename, 'w', encoding='utf-8') # type: ignore
+ f = open(filename, 'w', encoding='utf-8') # type: ignore
else:
- f = open(filename, 'wb') # type: ignore
+ f = open(filename, 'wb')
with f:
self.implementation.dump(context, f, *self.additional_dump_args)
diff --git a/sphinx/builders/htmlhelp.py b/sphinx/builders/htmlhelp.py
index 49d48361e..252e5050d 100644
--- a/sphinx/builders/htmlhelp.py
+++ b/sphinx/builders/htmlhelp.py
@@ -11,7 +11,6 @@
"""
from __future__ import print_function
-import codecs
import os
from os import path
@@ -19,6 +18,7 @@ from docutils import nodes
from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder
+from sphinx.config import string_classes
from sphinx.environment.adapters.indexentries import IndexEntries
from sphinx.locale import __
from sphinx.util import logging
@@ -133,8 +133,9 @@ that the their then there these they this to
was will with
""".split()
-# The following list includes only languages supported by Sphinx.
-# See http://msdn.microsoft.com/en-us/library/ms930130.aspx for more.
+# The following list includes only languages supported by Sphinx. See
+# https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms930130(v=msdn.10)
+# for more.
chm_locales = {
# lang: LCID, encoding
'ca': (0x403, 'cp1252'),
@@ -195,10 +196,10 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
def init(self):
# type: () -> None
- StandaloneHTMLBuilder.init(self)
- # the output files for HTML help must be .html only
+ # the output files for HTML help is .html by default
self.out_suffix = '.html'
self.link_suffix = '.html'
+ StandaloneHTMLBuilder.init(self)
# determine the correct locale setting
locale = chm_locales.get(self.config.language)
if locale is not None:
@@ -207,8 +208,8 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
def open_file(self, outdir, basename, mode='w'):
# type: (unicode, unicode, unicode) -> IO
# open a file with the correct encoding for the selected language
- return codecs.open(path.join(outdir, basename), mode, # type: ignore
- self.encoding, 'xmlcharrefreplace')
+ return open(path.join(outdir, basename), mode, # type: ignore
+ encoding=self.encoding, errors='xmlcharrefreplace')
def update_page_context(self, pagename, templatename, ctx, event_arg):
# type: (unicode, unicode, Dict, unicode) -> None
@@ -341,6 +342,8 @@ def setup(app):
app.add_builder(HTMLHelpBuilder)
app.add_config_value('htmlhelp_basename', lambda self: make_filename(self.project), None)
+ app.add_config_value('htmlhelp_file_suffix', None, 'html', string_classes)
+ app.add_config_value('htmlhelp_link_suffix', None, 'html', string_classes)
return {
'version': 'builtin',
diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py
index bbbcce0dc..c4335885f 100644
--- a/sphinx/builders/latex/__init__.py
+++ b/sphinx/builders/latex/__init__.py
@@ -34,7 +34,10 @@ from sphinx.util.docutils import SphinxFileOutput, new_document
from sphinx.util.fileutil import copy_asset_file
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, make_filename
-from sphinx.writers.latex import DEFAULT_SETTINGS, LaTeXWriter, LaTeXTranslator
+from sphinx.util.template import LaTeXRenderer
+from sphinx.writers.latex import (
+ ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, LaTeXWriter, LaTeXTranslator
+)
if False:
# For type annotation
@@ -126,11 +129,14 @@ class LaTeXBuilder(Builder):
def init(self):
# type: () -> None
+ self.context = {} # type: Dict[unicode, Any]
self.docnames = [] # type: Iterable[unicode]
self.document_data = [] # type: List[Tuple[unicode, unicode, unicode, unicode, unicode, bool]] # NOQA
self.usepackages = self.app.registry.latex_packages
texescape.init()
+ self.init_context()
+
def get_outdated_docs(self):
# type: () -> Union[unicode, List[unicode]]
return 'all documents' # for now
@@ -167,6 +173,31 @@ class LaTeXBuilder(Builder):
docname = docname[:-5]
self.titles.append((docname, entry[2]))
+ def init_context(self):
+ # type: () -> None
+ self.context = DEFAULT_SETTINGS.copy()
+
+ # Add special settings for latex_engine
+ self.context.update(ADDITIONAL_SETTINGS.get(self.config.latex_engine, {}))
+
+ # for xelatex+French, don't use polyglossia by default
+ if self.config.latex_engine == 'xelatex':
+ if self.config.language:
+ if self.config.language[:2] == 'fr':
+ self.context['polyglossia'] = ''
+ self.context['babel'] = r'\usepackage{babel}'
+
+ # Apply user settings to context
+ self.context.update(self.config.latex_elements)
+ self.context['release'] = self.config.release
+ self.context['use_xindy'] = self.config.latex_use_xindy
+
+ # for compatibilities
+ self.context['indexname'] = _('Index')
+ if self.config.release:
+ # Show the release label only if release value exists
+ self.context['releasename'] = _('Release')
+
def write_stylesheet(self):
# type: () -> None
highlighter = highlighting.PygmentsBridge('latex', self.config.pygments_style)
@@ -210,6 +241,8 @@ class LaTeXBuilder(Builder):
doctree['tocdepth'] = tocdepth
self.apply_transforms(doctree)
self.post_process_images(doctree)
+ self.update_doc_context(title, author)
+
logger.info(__("writing... "), nonl=1)
doctree.settings = docsettings
doctree.settings.author = author
@@ -231,6 +264,11 @@ class LaTeXBuilder(Builder):
return contentsname
+ def update_doc_context(self, title, author):
+ # type: (unicode, unicode) -> None
+ self.context['title'] = title
+ self.context['author'] = author
+
def assemble_doctree(self, indexfile, toctree_only, appendices):
# type: (unicode, bool, List[unicode]) -> nodes.Node
from docutils import nodes # NOQA
@@ -290,6 +328,7 @@ class LaTeXBuilder(Builder):
def finish(self):
# type: () -> None
self.copy_image_files()
+ self.write_message_catalog()
# copy TeX support files from texinputs
# configure usage of xindy (impacts Makefile and latexmkrc)
@@ -353,6 +392,11 @@ class LaTeXBuilder(Builder):
logger.warning(__('cannot copy image file %r: %s'),
path.join(self.srcdir, src), err)
+ def write_message_catalog(self):
+ # type: () -> None
+ filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t')
+ copy_asset_file(filename, self.outdir, context={}, renderer=LaTeXRenderer())
+
def validate_config_values(app, config):
# type: (Sphinx, Config) -> None
diff --git a/sphinx/builders/latex/transforms.py b/sphinx/builders/latex/transforms.py
index 160c8c324..afc580f9d 100644
--- a/sphinx/builders/latex/transforms.py
+++ b/sphinx/builders/latex/transforms.py
@@ -16,6 +16,7 @@ from sphinx.builders.latex.nodes import (
captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography
)
from sphinx.transforms import SphinxTransform
+from sphinx.util.nodes import NodeMatcher
if False:
# For type annotation
@@ -30,7 +31,7 @@ class FootnoteDocnameUpdater(SphinxTransform):
TARGET_NODES = (nodes.footnote, nodes.footnote_reference)
def apply(self):
- for node in self.document.traverse(lambda n: isinstance(n, self.TARGET_NODES)):
+ for node in self.document.traverse(NodeMatcher(*self.TARGET_NODES)):
node['docname'] = self.env.docname
@@ -536,14 +537,14 @@ class CitationReferenceTransform(SphinxTransform):
if self.app.builder.name != 'latex':
return
+ matcher = NodeMatcher(addnodes.pending_xref, refdomain='std', reftype='citation')
citations = self.env.get_domain('std').data['citations']
- for node in self.document.traverse(addnodes.pending_xref):
- if node['refdomain'] == 'std' and node['reftype'] == 'citation':
- docname, labelid, _ = citations.get(node['reftarget'], ('', '', 0))
- if docname:
- citation_ref = nodes.citation_reference('', *node.children,
- docname=docname, refname=labelid)
- node.replace_self(citation_ref)
+ for node in self.document.traverse(matcher):
+ docname, labelid, _ = citations.get(node['reftarget'], ('', '', 0))
+ if docname:
+ citation_ref = nodes.citation_reference('', *node.children,
+ docname=docname, refname=labelid)
+ node.replace_self(citation_ref)
class MathReferenceTransform(SphinxTransform):
@@ -577,10 +578,10 @@ class LiteralBlockTransform(SphinxTransform):
if self.app.builder.name != 'latex':
return
- for node in self.document.traverse(nodes.container):
- if node.get('literal_block') is True:
- newnode = captioned_literal_block('', *node.children, **node.attributes)
- node.replace_self(newnode)
+ matcher = NodeMatcher(nodes.container, literal_block=True)
+ for node in self.document.traverse(matcher):
+ newnode = captioned_literal_block('', *node.children, **node.attributes)
+ node.replace_self(newnode)
class DocumentTargetTransform(SphinxTransform):
diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py
index c3fd1e88a..2189411ee 100644
--- a/sphinx/builders/linkcheck.py
+++ b/sphinx/builders/linkcheck.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
import re
import socket
import threading
@@ -308,7 +307,8 @@ class CheckExternalLinksBuilder(Builder):
def write_entry(self, what, docname, line, uri):
# type: (unicode, unicode, int, unicode) -> None
- with codecs.open(path.join(self.outdir, 'output.txt'), 'a', 'utf-8') as output: # type: ignore # NOQA
+ with open(path.join(self.outdir, 'output.txt'), 'a', # type: ignore
+ encoding='utf-8') as output:
output.write("%s:%s: [%s] %s\n" % (self.env.doc2path(docname, None),
line, what, uri))
diff --git a/sphinx/builders/qthelp.py b/sphinx/builders/qthelp.py
index a90fd1e44..74d0d7c98 100644
--- a/sphinx/builders/qthelp.py
+++ b/sphinx/builders/qthelp.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
import os
import posixpath
import re
@@ -145,7 +144,8 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
nspace = nspace.lower()
# write the project file
- with codecs.open(path.join(outdir, outname + '.qhp'), 'w', 'utf-8') as f: # type: ignore # NOQA
+ with open(path.join(outdir, outname + '.qhp'), 'w', # type: ignore
+ encoding='utf-8') as f:
body = render_file('project.qhp', outname=outname,
title=self.config.html_title, version=self.config.version,
project=self.config.project, namespace=nspace,
@@ -159,7 +159,8 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
startpage = 'qthelp://' + posixpath.join(nspace, 'doc', 'index.html')
logger.info(__('writing collection project file...'))
- with codecs.open(path.join(outdir, outname + '.qhcp'), 'w', 'utf-8') as f: # type: ignore # NOQA
+ with open(path.join(outdir, outname + '.qhcp'), 'w', # type: ignore
+ encoding='utf-8') as f:
body = render_file('project.qhcp', outname=outname,
title=self.config.html_short_title,
homepage=homepage, startpage=startpage)
diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py
index 81209d165..a43332971 100644
--- a/sphinx/builders/text.py
+++ b/sphinx/builders/text.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
from os import path
from docutils.io import StringOutput
@@ -51,8 +50,7 @@ class TextBuilder(Builder):
if docname not in self.env.all_docs:
yield docname
continue
- targetname = self.env.doc2path(docname, self.outdir,
- self.out_suffix)
+ targetname = path.join(self.outdir, docname + self.out_suffix)
try:
targetmtime = path.getmtime(targetname)
except Exception:
@@ -82,7 +80,7 @@ class TextBuilder(Builder):
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
ensuredir(path.dirname(outfilename))
try:
- with codecs.open(outfilename, 'w', 'utf-8') as f: # type: ignore
+ with open(outfilename, 'w', encoding='utf-8') as f: # type: ignore
f.write(self.writer.output)
except (IOError, OSError) as err:
logger.warning(__("error writing file %s: %s"), outfilename, err)
diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py
index 6198532c9..03aefe006 100644
--- a/sphinx/builders/xml.py
+++ b/sphinx/builders/xml.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
from os import path
from docutils import nodes
@@ -54,8 +53,7 @@ class XMLBuilder(Builder):
if docname not in self.env.all_docs:
yield docname
continue
- targetname = self.env.doc2path(docname, self.outdir,
- self.out_suffix)
+ targetname = path.join(self.outdir, docname + self.out_suffix)
try:
targetmtime = path.getmtime(targetname)
except Exception:
@@ -95,7 +93,7 @@ class XMLBuilder(Builder):
outfilename = path.join(self.outdir, os_path(docname) + self.out_suffix)
ensuredir(path.dirname(outfilename))
try:
- with codecs.open(outfilename, 'w', 'utf-8') as f: # type: ignore
+ with open(outfilename, 'w', encoding='utf-8') as f: # type: ignore
f.write(self.writer.output)
except (IOError, OSError) as err:
logger.warning(__("error writing file %s: %s"), outfilename, err)
diff --git a/sphinx/cmd/make_mode.py b/sphinx/cmd/make_mode.py
index cf8673623..447b2ed01 100644
--- a/sphinx/cmd/make_mode.py
+++ b/sphinx/cmd/make_mode.py
@@ -59,7 +59,7 @@ BUILDERS = [
]
-class Make(object):
+class Make:
def __init__(self, srcdir, builddir, opts):
# type: (unicode, unicode, List[unicode]) -> None
diff --git a/sphinx/cmd/quickstart.py b/sphinx/cmd/quickstart.py
index e7a669557..d919af720 100644
--- a/sphinx/cmd/quickstart.py
+++ b/sphinx/cmd/quickstart.py
@@ -17,8 +17,8 @@ import os
import re
import sys
import time
+import warnings
from collections import OrderedDict
-from io import open
from os import path
# try to import readline, unix specific enhancement
@@ -34,12 +34,12 @@ except ImportError:
USE_LIBEDIT = False
from docutils.utils import column_width
-from six import PY2, PY3, text_type, binary_type
-from six.moves import input
+from six import text_type, binary_type
from six.moves.urllib.parse import quote as urlquote
import sphinx.locale
from sphinx import __display_version__, package_dir
+from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.locale import __
from sphinx.util import texescape
from sphinx.util.console import ( # type: ignore
@@ -185,20 +185,6 @@ def do_prompt(text, default=None, validator=nonempty):
prompt = PROMPT_PREFIX + '%s [%s]: ' % (text, default) # type: unicode
else:
prompt = PROMPT_PREFIX + text + ': '
- if PY2:
- # for Python 2.x, try to get a Unicode string out of it
- if prompt.encode('ascii', 'replace').decode('ascii', 'replace') \
- != prompt:
- if TERM_ENCODING:
- prompt = prompt.encode(TERM_ENCODING)
- else:
- print(turquoise(__('* Note: non-ASCII default value provided '
- 'and terminal encoding unknown -- assuming '
- 'UTF-8 or Latin-1.')))
- try:
- prompt = prompt.encode('utf-8')
- except UnicodeEncodeError:
- prompt = prompt.encode('latin1')
if USE_LIBEDIT:
# Note: libedit has a problem for combination of ``input()`` and escape
# sequence (see #5335). To avoid the problem, all prompts are not colored
@@ -222,10 +208,9 @@ def do_prompt(text, default=None, validator=nonempty):
def convert_python_source(source, rex=re.compile(r"[uU]('.*?')")):
# type: (unicode, Pattern) -> unicode
# remove Unicode literal prefixes
- if PY3:
- return rex.sub('\\1', source)
- else:
- return source
+ warnings.warn('convert_python_source() is deprecated.',
+ RemovedInSphinx40Warning)
+ return rex.sub('\\1', source)
class QuickstartRenderer(SphinxRenderer):
@@ -399,7 +384,7 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
if 'mastertocmaxdepth' not in d:
d['mastertocmaxdepth'] = 2
- d['PY3'] = PY3
+ d['PY3'] = True
d['project_fn'] = make_filename(d['project'])
d['project_url'] = urlquote(d['project'].encode('idna'))
d['project_manpage'] = d['project_fn'].lower()
@@ -445,7 +430,7 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
if overwrite or not path.isfile(fpath):
if 'quiet' not in d:
print(__('Creating file %s.') % fpath)
- with open(fpath, 'wt', encoding='utf-8', newline=newline) as f:
+ with open(fpath, 'wt', encoding='utf-8', newline=newline) as f: # type: ignore
f.write(content)
else:
if 'quiet' not in d:
@@ -455,7 +440,7 @@ def generate(d, overwrite=True, silent=False, templatedir=None):
if not conf_path or not path.isfile(conf_path):
conf_path = os.path.join(package_dir, 'templates', 'quickstart', 'conf.py_t')
with open(conf_path) as f:
- conf_text = convert_python_source(f.read())
+ conf_text = f.read()
write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d))
diff --git a/sphinx/config.py b/sphinx/config.py
index d4e1ab055..c3a81291f 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -17,9 +17,7 @@ from collections import OrderedDict
from os import path, getenv
from typing import Any, NamedTuple, Union
-from six import (
- PY2, PY3, iteritems, string_types, binary_type, text_type, integer_types, class_types
-)
+from six import string_types, binary_type, text_type, integer_types
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.errors import ConfigError, ExtensionError
@@ -38,15 +36,12 @@ if False:
logger = logging.getLogger(__name__)
CONFIG_FILENAME = 'conf.py'
-UNSERIALIZABLE_TYPES = class_types + (types.ModuleType, types.FunctionType)
+UNSERIALIZABLE_TYPES = (type, types.ModuleType, types.FunctionType)
copyright_year_re = re.compile(r'^((\d{4}-)?)(\d{4})(?=[ ,])')
-if PY3:
- unicode = str # special alias for static typing...
-
ConfigValue = NamedTuple('ConfigValue', [('name', str),
('value', Any),
- ('rebuild', Union[bool, unicode])])
+ ('rebuild', Union[bool, text_type])])
def is_serializable(obj):
@@ -55,7 +50,7 @@ def is_serializable(obj):
if isinstance(obj, UNSERIALIZABLE_TYPES):
return False
elif isinstance(obj, dict):
- for key, value in iteritems(obj):
+ for key, value in obj.items():
if not is_serializable(key) or not is_serializable(value):
return False
elif isinstance(obj, (list, tuple, set)):
@@ -64,7 +59,7 @@ def is_serializable(obj):
return True
-class ENUM(object):
+class ENUM:
"""represents the config value should be a one of candidates.
Example:
@@ -83,11 +78,9 @@ class ENUM(object):
string_classes = [text_type] # type: List
-if PY2:
- string_classes.append(binary_type) # => [str, unicode]
-class Config(object):
+class Config:
"""Configuration file abstraction.
The config object makes the values of all config values available as
@@ -119,7 +112,7 @@ class Config(object):
locale_dirs = (['locales'], 'env', []),
figure_language_filename = (u'{root}.{language}{ext}', 'env', [str]),
- master_doc = ('contents', 'env', []),
+ master_doc = ('index', 'env', []),
source_suffix = ({'.rst': 'restructuredtext'}, 'env', Any),
source_encoding = ('utf-8-sig', 'env', []),
source_parsers = ({}, 'env', []),
@@ -261,7 +254,7 @@ class Config(object):
def init_values(self):
# type: () -> None
config = self._raw_config
- for valname, value in iteritems(self.overrides):
+ for valname, value in self.overrides.items():
try:
if '.' in valname:
realvalname, key = valname.split('.', 1)
@@ -310,7 +303,7 @@ class Config(object):
def __iter__(self):
# type: () -> Generator[ConfigValue, None, None]
- for name, value in iteritems(self.values):
+ for name, value in self.values.items():
yield ConfigValue(name, getattr(self, name), value[1]) # type: ignore
def add(self, name, default, rebuild, types):
@@ -331,7 +324,7 @@ class Config(object):
"""Obtains serializable data for pickling."""
# remove potentially pickling-problematic values from config
__dict__ = {}
- for key, value in iteritems(self.__dict__):
+ for key, value in self.__dict__.items():
if key.startswith('_') or not is_serializable(value):
pass
else:
@@ -339,7 +332,7 @@ class Config(object):
# create a picklable copy of values list
__dict__['values'] = {}
- for key, value in iteritems(self.values): # type: ignore
+ for key, value in self.values.items(): # type: ignore
real_value = getattr(self, key)
if not is_serializable(real_value):
# omit unserializable value
@@ -367,9 +360,8 @@ def eval_config_file(filename, tags):
try:
execfile_(filename, namespace)
except SyntaxError as err:
- msg = __("There is a syntax error in your configuration file: %s")
- if PY3:
- msg += __("\nDid you change the syntax from 2.x to 3.x?")
+ msg = __("There is a syntax error in your configuration file: %s\n"
+ "Did you change the syntax from 2.x to 3.x?")
raise ConfigError(msg % err)
except SystemExit:
msg = __("The configuration file (or one of the modules it imports) "
@@ -403,8 +395,8 @@ def convert_source_suffix(app, config):
# if dict, convert it to OrderedDict
config.source_suffix = OrderedDict(config.source_suffix) # type: ignore
else:
- logger.warning(__("The config value `source_suffix' expected to "
- "a string, list of strings or dictionary. "
+ logger.warning(__("The config value `source_suffix' expects "
+ "a string, list of strings, or dictionary. "
"But `%r' is given." % source_suffix))
@@ -471,11 +463,18 @@ def check_confval_types(app, config):
continue # at least we share a non-trivial base class
if annotations:
- msg = __("The config value `{name}' has type `{current.__name__}', "
- "expected to {permitted}.")
+ msg = __("The config value `{name}' has type `{current.__name__}'; "
+ "expected {permitted}.")
+ wrapped_annotations = ["`{}'".format(c.__name__) for c in annotations]
+ if len(wrapped_annotations) > 2:
+ permitted = "{}, or {}".format(
+ ", ".join(wrapped_annotations[:-1]),
+ wrapped_annotations[-1])
+ else:
+ permitted = " or ".join(wrapped_annotations)
logger.warning(msg.format(name=confval.name,
current=type(confval.value),
- permitted=str([c.__name__ for c in annotations])))
+ permitted=permitted))
else:
msg = __("The config value `{name}' has type `{current.__name__}', "
"defaults to `{default.__name__}'.")
@@ -491,19 +490,28 @@ def check_unicode(config):
"""
nonascii_re = re.compile(br'[\x80-\xff]')
- for name, value in iteritems(config._raw_config):
+ for name, value in config._raw_config.items():
if isinstance(value, binary_type) and nonascii_re.search(value):
logger.warning(__('the config value %r is set to a string with non-ASCII '
'characters; this can lead to Unicode errors occurring. '
'Please use Unicode strings, e.g. %r.'), name, u'Content')
+def check_primary_domain(app, config):
+ # type: (Sphinx, Config) -> None
+ primary_domain = config.primary_domain
+ if primary_domain and not app.registry.has_domain(primary_domain):
+ logger.warning(__('primary_domain %r not found, ignored.'), primary_domain)
+ config.primary_domain = None # type: ignore
+
+
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.connect('config-inited', convert_source_suffix)
app.connect('config-inited', init_numfig_format)
app.connect('config-inited', correct_copyright_year)
app.connect('config-inited', check_confval_types)
+ app.connect('config-inited', check_primary_domain)
return {
'version': 'builtin',
diff --git a/sphinx/deprecation.py b/sphinx/deprecation.py
index f95e8dbff..ea43a71f4 100644
--- a/sphinx/deprecation.py
+++ b/sphinx/deprecation.py
@@ -17,10 +17,6 @@ if False:
from typing import Any, Dict, Type # NOQA
-class RemovedInSphinx20Warning(DeprecationWarning):
- pass
-
-
class RemovedInSphinx30Warning(PendingDeprecationWarning):
pass
@@ -29,7 +25,7 @@ class RemovedInSphinx40Warning(PendingDeprecationWarning):
pass
-RemovedInNextVersionWarning = RemovedInSphinx20Warning
+RemovedInNextVersionWarning = RemovedInSphinx30Warning
class DeprecatedDict(dict):
diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py
index 1177a258e..1898a1c0c 100644
--- a/sphinx/directives/__init__.py
+++ b/sphinx/directives/__init__.py
@@ -233,7 +233,7 @@ class DefaultDomain(SphinxDirective):
domain_name = self.arguments[0].lower()
# if domain_name not in env.domains:
# # try searching by label
- # for domain in itervalues(env.domains):
+ # for domain in env.domains.values():
# if domain.label.lower() == domain_name:
# domain_name = domain.name
# break
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index a98ab5883..e14a451d9 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -7,7 +7,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
import sys
import warnings
from difflib import unified_diff
@@ -177,7 +176,7 @@ class CodeBlock(SphinxDirective):
return [literal]
-class LiteralIncludeReader(object):
+class LiteralIncludeReader:
INVALID_OPTIONS_PAIR = [
('lineno-match', 'lineno-start'),
('lineno-match', 'append'),
@@ -213,7 +212,8 @@ class LiteralIncludeReader(object):
def read_file(self, filename, location=None):
# type: (unicode, Any) -> List[unicode]
try:
- with codecs.open(filename, 'r', self.encoding, errors='strict') as f: # type: ignore # NOQA
+ with open(filename, 'r', # type: ignore
+ encoding=self.encoding, errors='strict') as f:
text = f.read() # type: unicode
if 'tab-width' in self.options:
text = text.expandtabs(self.options['tab-width'])
diff --git a/sphinx/directives/other.py b/sphinx/directives/other.py
index 3776536b8..ab3cfc37c 100644
--- a/sphinx/directives/other.py
+++ b/sphinx/directives/other.py
@@ -14,7 +14,6 @@ from docutils.parsers.rst import directives
from docutils.parsers.rst.directives.admonitions import BaseAdmonition
from docutils.parsers.rst.directives.misc import Class
from docutils.parsers.rst.directives.misc import Include as BaseInclude
-from six.moves import range
from sphinx import addnodes
from sphinx.domains.changeset import VersionChange # NOQA # for compatibility
diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py
index 41db13cb6..4824f4fb0 100644
--- a/sphinx/domains/__init__.py
+++ b/sphinx/domains/__init__.py
@@ -12,8 +12,6 @@
import copy
-from six import iteritems
-
from sphinx.errors import SphinxError
from sphinx.locale import _
@@ -28,7 +26,7 @@ if False:
from sphinx.util.typing import RoleFunction # NOQA
-class ObjType(object):
+class ObjType:
"""
An ObjType is the description for a type of object that a domain can
document. In the object_types attribute of Domain subclasses, object type
@@ -55,7 +53,7 @@ class ObjType(object):
self.attrs.update(attrs)
-class Index(object):
+class Index:
"""
An Index is the description for a domain-specific index. To add an index to
a domain, subclass Index, overriding the three name attributes:
@@ -113,7 +111,7 @@ class Index(object):
raise NotImplementedError
-class Domain(object):
+class Domain:
"""
A Domain is meant to be a group of "object" description directives for
objects of a similar nature, and corresponding roles to create references to
@@ -183,7 +181,7 @@ 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)
- for name, obj in iteritems(self.object_types):
+ for name, obj in self.object_types.items():
for rolename in obj.roles:
self._role2type.setdefault(rolename, []).append(name)
self._type2role[name] = obj.roles[0] if obj.roles else ''
diff --git a/sphinx/domains/changeset.py b/sphinx/domains/changeset.py
index ed878b1d3..669d8c5b7 100644
--- a/sphinx/domains/changeset.py
+++ b/sphinx/domains/changeset.py
@@ -12,7 +12,6 @@
from typing import NamedTuple
from docutils import nodes
-from six import iteritems
from sphinx import addnodes
from sphinx import locale
@@ -112,7 +111,7 @@ class ChangeSetDomain(Domain):
def clear_doc(self, docname):
# type: (unicode) -> None
- for version, changes in iteritems(self.data['changes']):
+ for version, changes in self.data['changes'].items():
for changeset in changes[:]:
if changeset.docname == docname:
changes.remove(changeset)
@@ -120,7 +119,7 @@ class ChangeSetDomain(Domain):
def merge_domaindata(self, docnames, otherdata):
# type: (List[unicode], Dict) -> None
# XXX duplicates?
- for version, otherchanges in iteritems(otherdata['changes']):
+ for version, otherchanges in otherdata['changes'].items():
changes = self.data['changes'].setdefault(version, [])
for changeset in otherchanges:
if changeset.docname in docnames:
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 9c8b3a3c6..df3dfb578 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -14,7 +14,7 @@ from copy import deepcopy
from docutils import nodes, utils
from docutils.parsers.rst import directives
-from six import iteritems, text_type
+from six import text_type
from sphinx import addnodes
from sphinx.directives import ObjectDescription
@@ -72,7 +72,7 @@ logger = logging.getLogger(__name__)
Grammar
----------------------------------------------------------------------------
- See http://www.nongnu.org/hcb/ for the grammar,
+ See https://www.nongnu.org/hcb/ for the grammar,
and https://github.com/cplusplus/draft/blob/master/source/grammar.tex,
and https://github.com/cplusplus/concepts-ts
for the newest grammar.
@@ -336,7 +336,7 @@ _fold_operator_re = re.compile(r'''(?x)
| !=
| [<>=/*%+|&^~-]=?
''')
-# see http://en.cppreference.com/w/cpp/keyword
+# see https://en.cppreference.com/w/cpp/keyword
_keywords = [
'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor',
'bool', 'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class',
@@ -604,17 +604,13 @@ class ASTBase(UnicodeMixin):
if type(self) is not type(other):
return False
try:
- for key, value in iteritems(self.__dict__):
+ for key, value in self.__dict__.items():
if value != getattr(other, key):
return False
except AttributeError:
return False
return True
- def __ne__(self, other):
- # type: (Any) -> bool
- return not self.__eq__(other)
-
__hash__ = None # type: Callable[[], int]
def clone(self):
@@ -3592,7 +3588,7 @@ class ASTNamespace(ASTBase):
self.templatePrefix = templatePrefix
-class SymbolLookupResult(object):
+class SymbolLookupResult:
def __init__(self, symbols, parentSymbol, identOrOp, templateParams, templateArgs):
# type: (Iterator[Symbol], Symbol, Union[ASTIdentifier, ASTOperator], Any, ASTTemplateArgs) -> None # NOQA
self.symbols = symbols
@@ -3602,7 +3598,7 @@ class SymbolLookupResult(object):
self.templateArgs = templateArgs
-class Symbol(object):
+class Symbol:
debug_lookup = False
def _assert_invariants(self):
@@ -4299,9 +4295,9 @@ class Symbol(object):
return ''.join(res)
-class DefinitionParser(object):
+class DefinitionParser:
# those without signedness and size modifiers
- # see http://en.cppreference.com/w/cpp/language/types
+ # see https://en.cppreference.com/w/cpp/language/types
_simple_fundemental_types = (
'void', 'bool', 'char', 'wchar_t', 'char16_t', 'char32_t', 'int',
'float', 'double', 'auto'
@@ -4584,7 +4580,7 @@ class DefinitionParser(object):
return ASTCharLiteral(prefix, data)
except UnicodeDecodeError as e:
self.fail("Can not handle character literal. Internal error was: %s" % e)
- except UnsupportedMultiCharacterCharLiteral as e:
+ except UnsupportedMultiCharacterCharLiteral:
self.fail("Can not handle character literal"
" resulting in multiple decoded characters.")
@@ -6591,7 +6587,7 @@ class CPPXRefRole(XRefRole):
return title, target
-class CPPExprRole(object):
+class CPPExprRole:
def __init__(self, asCode):
if asCode:
# render the expression as inline code
@@ -6603,7 +6599,7 @@ class CPPExprRole(object):
self.node_type = nodes.inline
def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]):
- class Warner(object):
+ class Warner:
def warn(self, msg):
inliner.reporter.warning(msg, line=lineno)
text = utils.unescape(text).replace('\n', ' ')
@@ -6722,7 +6718,7 @@ class CPPDomain(Domain):
target, node, contnode, emitWarnings=True):
# type: (BuildEnvironment, unicode, Builder, unicode, unicode, nodes.Node, nodes.Node, bool) -> nodes.Node # NOQA
- class Warner(object):
+ class Warner:
def warn(self, msg):
if emitWarnings:
logger.warning(msg, location=node)
diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py
index 427c86aa9..77083cc3c 100644
--- a/sphinx/domains/python.py
+++ b/sphinx/domains/python.py
@@ -13,7 +13,6 @@ import re
from docutils import nodes
from docutils.parsers.rst import directives
-from six import iteritems
from sphinx import addnodes, locale
from sphinx.deprecation import DeprecatedDict, RemovedInSphinx30Warning
@@ -114,7 +113,7 @@ def _pseudo_parse_arglist(signode, arglist):
# This override allows our inline type specifiers to behave like :class: link
# when it comes to handling "." and "~" prefixes.
-class PyXrefMixin(object):
+class PyXrefMixin:
def make_xref(self,
rolename, # type: unicode
domain, # type: unicode
@@ -536,7 +535,7 @@ class PyClassmember(PyObject):
return ''
-class PyDecoratorMixin(object):
+class PyDecoratorMixin:
"""
Mixin for decorator directives.
"""
@@ -677,7 +676,7 @@ class PythonModuleIndex(Index):
ignores = self.domain.env.config['modindex_common_prefix'] # type: ignore
ignores = sorted(ignores, key=len, reverse=True)
# list of all modules, sorted by module name
- modules = sorted(iteritems(self.domain.data['modules']),
+ modules = sorted(self.domain.data['modules'].items(),
key=lambda x: x[0].lower())
# sort out collapsable modules
prev_modname = ''
@@ -727,7 +726,7 @@ class PythonModuleIndex(Index):
collapse = len(modules) - num_toplevels < num_toplevels
# sort by first letter
- sorted_content = sorted(iteritems(content))
+ sorted_content = sorted(content.items())
return sorted_content, collapse
@@ -923,9 +922,9 @@ class PythonDomain(Domain):
def get_objects(self):
# type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
- for modname, info in iteritems(self.data['modules']):
+ for modname, info in self.data['modules'].items():
yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
- for refname, (docname, type) in iteritems(self.data['objects']):
+ for refname, (docname, type) in self.data['objects'].items():
if type != 'module': # modules are already handled
yield (refname, refname, type, docname, refname, 1)
diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py
index 1a5c3ba0c..026d2a59d 100644
--- a/sphinx/domains/rst.py
+++ b/sphinx/domains/rst.py
@@ -11,8 +11,6 @@
import re
-from six import iteritems
-
from sphinx import addnodes
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
@@ -172,7 +170,7 @@ class ReSTDomain(Domain):
def get_objects(self):
# type: () -> Iterator[Tuple[unicode, unicode, unicode, unicode, unicode, int]]
- for (typ, name), docname in iteritems(self.data['objects']):
+ for (typ, name), docname in self.data['objects'].items():
yield name, name, typ, docname, typ + '-' + name, 1
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 37bac2acc..2bbc92f88 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -17,7 +17,6 @@ from copy import copy
from docutils import nodes
from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
-from six import iteritems
from sphinx import addnodes
from sphinx.deprecation import RemovedInSphinx30Warning
@@ -529,7 +528,7 @@ class StandardDomain(Domain):
# set up enumerable nodes
self.enumerable_nodes = copy(self.enumerable_nodes) # create a copy for this instance
- for node, settings in iteritems(env.app.registry.enumerable_nodes):
+ for node, settings in env.app.registry.enumerable_nodes.items():
self.enumerable_nodes[node] = settings
def clear_doc(self, docname):
@@ -607,7 +606,7 @@ class StandardDomain(Domain):
def note_labels(self, env, docname, document):
# type: (BuildEnvironment, unicode, nodes.Node) -> None
labels, anonlabels = self.data['labels'], self.data['anonlabels']
- for name, explicit in iteritems(document.nametypes):
+ for name, explicit in document.nametypes.items():
if not explicit:
continue
labelid = document.nameids[name]
@@ -647,7 +646,7 @@ class StandardDomain(Domain):
def check_consistency(self):
# type: () -> None
- for name, (docname, labelid, lineno) in iteritems(self.data['citations']):
+ for name, (docname, labelid, lineno) in self.data['citations'].items():
if name not in self.data['citation_refs']:
logger.warning(__('Citation [%s] is not referenced.'), name,
type='ref', subtype='citation',
@@ -887,20 +886,20 @@ class StandardDomain(Domain):
# handle the special 'doc' reference here
for doc in self.env.all_docs:
yield (doc, clean_astext(self.env.titles[doc]), 'doc', doc, '', -1)
- for (prog, option), info in iteritems(self.data['progoptions']):
+ for (prog, option), info in self.data['progoptions'].items():
if prog:
fullname = ".".join([prog, option])
yield (fullname, fullname, 'cmdoption', info[0], info[1], 1)
else:
yield (option, option, 'cmdoption', info[0], info[1], 1)
- for (type, name), info in iteritems(self.data['objects']):
+ for (type, name), info in self.data['objects'].items():
yield (name, name, type, info[0], info[1],
self.object_types[type].attrs['searchprio'])
- for name, info in iteritems(self.data['labels']):
+ for name, info in self.data['labels'].items():
yield (name, info[2], 'label', info[0], info[1], -1)
# add anonymous-only labels as well
non_anon_labels = set(self.data['labels'])
- for name, info in iteritems(self.data['anonlabels']):
+ for name, info in self.data['anonlabels'].items():
if name not in non_anon_labels:
yield (name, name, 'label', info[0], info[1], -1)
diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py
index 4a79db3db..000c8a417 100644
--- a/sphinx/environment/__init__.py
+++ b/sphinx/environment/__init__.py
@@ -10,20 +10,16 @@
"""
import os
-import re
+import pickle
import sys
import warnings
from collections import defaultdict
from copy import copy
+from io import BytesIO
from os import path
-from docutils.utils import get_source_line
-from six import BytesIO, next
-from six.moves import cPickle as pickle
-
from sphinx import addnodes
-from sphinx.deprecation import RemovedInSphinx20Warning, RemovedInSphinx30Warning
-from sphinx.environment.adapters.indexentries import IndexEntries
+from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning
from sphinx.environment.adapters.toctree import TocTree
from sphinx.errors import SphinxError, BuildEnvironmentError, DocumentError, ExtensionError
from sphinx.locale import __
@@ -65,9 +61,7 @@ default_settings = {
# This is increased every time an environment attribute is added
# or changed to properly invalidate pickle files.
-#
-# NOTE: increase base version by 2 to have distinct numbers for Py2 and 3
-ENV_VERSION = 54 + (sys.version_info[0] - 2)
+ENV_VERSION = 56
# config status
CONFIG_OK = 1
@@ -94,7 +88,7 @@ class NoUri(Exception):
pass
-class BuildEnvironment(object):
+class BuildEnvironment:
"""
The environment in which the ReST files are translated.
Stores an inventory of cross-file targets and provides doctree
@@ -125,9 +119,6 @@ class BuildEnvironment(object):
self.settings = default_settings.copy()
self.settings['env'] = self
- # the function to write warning messages with
- self._warnfunc = None # type: Callable
-
# All "docnames" here are /-separated and relative and exclude
# the source suffix.
@@ -273,11 +264,6 @@ class BuildEnvironment(object):
# Allow to disable by 3rd party extension (workaround)
self.settings.setdefault('smart_quotes', True)
- def set_warnfunc(self, func):
- # type: (Callable) -> None
- warnings.warn('env.set_warnfunc() is now deprecated. Use sphinx.util.logging instead.',
- RemovedInSphinx20Warning)
-
def set_versioning_method(self, method, compare):
# type: (unicode, bool) -> None
"""This sets the doctree versioning method for this environment.
@@ -297,21 +283,6 @@ class BuildEnvironment(object):
self.versioning_condition = condition
self.versioning_compare = compare
- def warn(self, docname, msg, lineno=None, **kwargs):
- # type: (unicode, unicode, int, Any) -> None
- """Emit a warning.
-
- This differs from using ``app.warn()`` in that the warning may not
- be emitted instantly, but collected for emitting all warnings after
- the update of the environment.
- """
- self.app.warn(msg, location=(docname, lineno), **kwargs) # type: ignore
-
- def warn_node(self, msg, node, **kwargs):
- # type: (unicode, nodes.Node, Any) -> None
- """Like :meth:`warn`, but with source information taken from *node*."""
- self._warnfunc(msg, '%s:%s' % get_source_line(node), **kwargs)
-
def clear_doc(self, docname):
# type: (unicode) -> None
"""Remove all traces of a source file in the inventory."""
@@ -367,6 +338,13 @@ class BuildEnvironment(object):
If *base* is a path string, return absolute path under that.
If *suffix* is not None, add it instead of config.source_suffix.
"""
+ if suffix:
+ warnings.warn('The suffix argument for doc2path() is deprecated.',
+ RemovedInSphinx40Warning)
+ if base not in (True, None):
+ warnings.warn('The string style base argument for doc2path() is deprecated.',
+ RemovedInSphinx40Warning)
+
docname = docname.replace(SEP, path.sep)
if suffix is None:
# Use first candidate if there is not a file for any suffix
@@ -466,8 +444,8 @@ class BuildEnvironment(object):
added.add(docname)
continue
# if the doctree file is not there, rebuild
- if not path.isfile(self.doc2path(docname, self.doctreedir,
- '.doctree')):
+ filename = path.join(self.doctreedir, docname + '.doctree')
+ if not path.isfile(filename):
changed.add(docname)
continue
# check the "reread always" list
@@ -565,32 +543,6 @@ class BuildEnvironment(object):
"""
self.reread_always.add(self.docname)
- def note_toctree(self, docname, toctreenode):
- # type: (unicode, addnodes.toctree) -> None
- """Note a TOC tree directive in a document and gather information about
- file relations from it.
- """
- warnings.warn('env.note_toctree() is deprecated. '
- 'Use sphinx.environment.adapters.toctree.TocTree instead.',
- RemovedInSphinx20Warning)
- TocTree(self).note(docname, toctreenode)
-
- def get_toc_for(self, docname, builder):
- # type: (unicode, Builder) -> Dict[unicode, nodes.Node]
- """Return a TOC nodetree -- for use on the same page only!"""
- warnings.warn('env.get_toc_for() is deprecated. '
- 'Use sphinx.environment.adapters.toctre.TocTree instead.',
- RemovedInSphinx20Warning)
- return TocTree(self).get_toc_for(docname, builder)
-
- def get_toctree_for(self, docname, builder, collapse, **kwds):
- # type: (unicode, Builder, bool, Any) -> addnodes.toctree
- """Return the global TOC nodetree."""
- warnings.warn('env.get_toctree_for() is deprecated. '
- 'Use sphinx.environment.adapters.toctre.TocTree instead.',
- RemovedInSphinx20Warning)
- return TocTree(self).get_toctree_for(docname, builder, collapse, **kwds)
-
def get_domain(self, domainname):
# type: (unicode) -> Domain
"""Return the domain instance with the specified name.
@@ -607,8 +559,8 @@ class BuildEnvironment(object):
def get_doctree(self, docname):
# type: (unicode) -> nodes.Node
"""Read the doctree for a file from the pickle and return it."""
- doctree_filename = self.doc2path(docname, self.doctreedir, '.doctree')
- with open(doctree_filename, 'rb') as f:
+ filename = path.join(self.doctreedir, docname + '.doctree')
+ with open(filename, 'rb') as f:
doctree = pickle.load(f)
doctree.settings.env = self
doctree.reporter = LoggingReporter(self.doc2path(docname))
@@ -678,16 +630,6 @@ class BuildEnvironment(object):
# allow custom references to be resolved
self.app.emit('doctree-resolved', doctree, docname)
- def create_index(self, builder, group_entries=True,
- _fixre=re.compile(r'(.*) ([(][^()]*[)])')):
- # type: (Builder, bool, Pattern) -> List[Tuple[unicode, List[Tuple[unicode, List[unicode]]]]] # NOQA
- warnings.warn('env.create_index() is deprecated. '
- 'Use sphinx.environment.adapters.indexentreis.IndexEntries instead.',
- RemovedInSphinx20Warning)
- return IndexEntries(self).create_index(builder,
- group_entries=group_entries,
- _fixre=_fixre)
-
def collect_relations(self):
# type: () -> Dict[unicode, List[unicode]]
traversed = set()
@@ -804,7 +746,7 @@ class BuildEnvironment(object):
@classmethod
def loads(cls, string, app=None):
- # type: (unicode, Sphinx) -> BuildEnvironment
+ # type: (bytes, Sphinx) -> BuildEnvironment
warnings.warn('BuildEnvironment.loads() is deprecated. '
'Please use pickle.loads() instead.',
RemovedInSphinx30Warning)
diff --git a/sphinx/environment/adapters/asset.py b/sphinx/environment/adapters/asset.py
index 91f2cf8eb..fa1141f65 100644
--- a/sphinx/environment/adapters/asset.py
+++ b/sphinx/environment/adapters/asset.py
@@ -14,7 +14,7 @@ if False:
from sphinx.environment import BuildEnvironment # NOQA
-class ImageAdapter(object):
+class ImageAdapter:
def __init__(self, env):
# type: (BuildEnvironment) -> None
self.env = env
diff --git a/sphinx/environment/adapters/indexentries.py b/sphinx/environment/adapters/indexentries.py
index 7c31fc3d5..d39fb057d 100644
--- a/sphinx/environment/adapters/indexentries.py
+++ b/sphinx/environment/adapters/indexentries.py
@@ -13,7 +13,7 @@ import re
import unicodedata
from itertools import groupby
-from six import text_type, iteritems
+from six import text_type
from sphinx.locale import _, __
from sphinx.util import split_into, logging
@@ -27,7 +27,7 @@ if False:
logger = logging.getLogger(__name__)
-class IndexEntries(object):
+class IndexEntries:
def __init__(self, env):
# type: (BuildEnvironment) -> None
self.env = env
@@ -60,7 +60,7 @@ class IndexEntries(object):
# maintain links in sorted/deterministic order
bisect.insort(entry[0], (main, uri))
- for fn, entries in iteritems(self.env.indexentries):
+ for fn, entries in self.env.indexentries.items():
# new entry types must be listed in directives/other.py!
for type, value, tid, main, index_key in entries:
try:
@@ -146,7 +146,7 @@ class IndexEntries(object):
# type: (Tuple[unicode, List]) -> unicode
# hack: mutating the subitems dicts to a list in the keyfunc
k, v = item
- v[1] = sorted((si, se) for (si, (se, void, void)) in iteritems(v[1]))
+ v[1] = sorted((si, se) for (si, (se, void, void)) in v[1].items())
if v[2] is None:
# now calculate the key
if k.startswith(u'\N{RIGHT-TO-LEFT MARK}'):
diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py
index 565396ec4..c309fb27c 100644
--- a/sphinx/environment/adapters/toctree.py
+++ b/sphinx/environment/adapters/toctree.py
@@ -10,7 +10,6 @@
"""
from docutils import nodes
-from six import iteritems
from sphinx import addnodes
from sphinx.locale import __
@@ -27,7 +26,7 @@ if False:
logger = logging.getLogger(__name__)
-class TocTree(object):
+class TocTree:
def __init__(self, env):
# type: (BuildEnvironment) -> None
self.env = env
@@ -261,7 +260,7 @@ class TocTree(object):
def get_toctree_ancestors(self, docname):
# type: (unicode) -> List[unicode]
parent = {}
- for p, children in iteritems(self.env.toctree_includes):
+ for p, children in self.env.toctree_includes.items():
for child in children:
parent[child] = p
ancestors = [] # type: List[unicode]
diff --git a/sphinx/environment/collectors/__init__.py b/sphinx/environment/collectors/__init__.py
index 9d9f5347c..30e1e9480 100644
--- a/sphinx/environment/collectors/__init__.py
+++ b/sphinx/environment/collectors/__init__.py
@@ -9,8 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-from six import itervalues
-
if False:
# For type annotation
from typing import Dict, List, Set # NOQA
@@ -19,7 +17,7 @@ if False:
from sphinx.environment import BuildEnvironment # NOQA
-class EnvironmentCollector(object):
+class EnvironmentCollector:
"""An EnvironmentCollector is a specific data collector from each document.
It gathers data and stores :py:class:`BuildEnvironment
@@ -44,7 +42,7 @@ class EnvironmentCollector(object):
def disable(self, app):
# type: (Sphinx) -> None
assert self.listener_ids is not None
- for listener_id in itervalues(self.listener_ids):
+ for listener_id in self.listener_ids.values():
app.disconnect(listener_id)
self.listener_ids = None
diff --git a/sphinx/environment/collectors/asset.py b/sphinx/environment/collectors/asset.py
index 725431dfa..d41931ed3 100644
--- a/sphinx/environment/collectors/asset.py
+++ b/sphinx/environment/collectors/asset.py
@@ -15,7 +15,6 @@ from os import path
from docutils import nodes
from docutils.utils import relative_path
-from six import iteritems, itervalues
from sphinx import addnodes
from sphinx.environment.collectors import EnvironmentCollector
@@ -87,7 +86,7 @@ class ImageCollector(EnvironmentCollector):
# map image paths to unique image names (so that they can be put
# into a single directory)
- for imgpath in itervalues(candidates):
+ for imgpath in candidates.values():
app.env.dependencies[docname].add(imgpath)
if not os.access(path.join(app.srcdir, imgpath), os.R_OK):
logger.warning(__('image file not readable: %s') % imgpath,
@@ -108,7 +107,7 @@ class ImageCollector(EnvironmentCollector):
except (OSError, IOError) as err:
logger.warning(__('image file %s not readable: %s') % (filename, err),
location=node, type='image', subtype='not_readable')
- for key, files in iteritems(globbed):
+ for key, files in globbed.items():
candidates[key] = sorted(files, key=len)[0] # select by similarity
diff --git a/sphinx/environment/collectors/dependencies.py b/sphinx/environment/collectors/dependencies.py
index de0b7c080..761a51e38 100644
--- a/sphinx/environment/collectors/dependencies.py
+++ b/sphinx/environment/collectors/dependencies.py
@@ -9,12 +9,13 @@
:license: BSD, see LICENSE for details.
"""
+import os
from os import path
from docutils.utils import relative_path
from sphinx.environment.collectors import EnvironmentCollector
-from sphinx.util.osutil import getcwd, fs_encoding
+from sphinx.util.osutil import fs_encoding
if False:
# For type annotation
@@ -40,7 +41,7 @@ class DependenciesCollector(EnvironmentCollector):
def process_doc(self, app, doctree):
# type: (Sphinx, nodes.Node) -> None
"""Process docutils-generated dependency info."""
- cwd = getcwd()
+ cwd = os.getcwd()
frompath = path.join(path.normpath(app.srcdir), 'dummy')
deps = doctree.settings.record_dependencies
if not deps:
diff --git a/sphinx/environment/collectors/indexentries.py b/sphinx/environment/collectors/indexentries.py
index a9ba897d0..2a5abcc8e 100644
--- a/sphinx/environment/collectors/indexentries.py
+++ b/sphinx/environment/collectors/indexentries.py
@@ -50,11 +50,7 @@ class IndexEntriesCollector(EnvironmentCollector):
node.parent.remove(node)
else:
for entry in node['entries']:
- if len(entry) == 5:
- # Since 1.4: new index structure including index_key (5th column)
- entries.append(entry)
- else:
- entries.append(entry + (None,))
+ entries.append(entry)
def setup(app):
diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py
index fe67bbcba..462997164 100644
--- a/sphinx/environment/collectors/toctree.py
+++ b/sphinx/environment/collectors/toctree.py
@@ -10,7 +10,6 @@
"""
from docutils import nodes
-from six import iteritems
from sphinx import addnodes
from sphinx.environment.adapters.toctree import TocTree
@@ -295,7 +294,7 @@ class TocTreeCollector(EnvironmentCollector):
if env.config.numfig:
_walk_doc(env.config.master_doc, tuple()) # type: ignore
- for docname, fignums in iteritems(env.toc_fignumbers):
+ for docname, fignums in env.toc_fignumbers.items():
if fignums != old_fignumbers.get(docname):
rewrite_needed.append(docname)
diff --git a/sphinx/events.py b/sphinx/events.py
index fb62d1776..0b76d6c9e 100644
--- a/sphinx/events.py
+++ b/sphinx/events.py
@@ -14,8 +14,6 @@ from __future__ import print_function
from collections import OrderedDict, defaultdict
-from six import itervalues
-
from sphinx.errors import ExtensionError
from sphinx.locale import __
@@ -45,7 +43,7 @@ core_events = {
} # type: Dict[unicode, unicode]
-class EventManager(object):
+class EventManager:
def __init__(self):
# type: () -> None
self.events = core_events.copy()
@@ -70,13 +68,13 @@ class EventManager(object):
def disconnect(self, listener_id):
# type: (int) -> None
- for event in itervalues(self.listeners):
+ for event in self.listeners.values():
event.pop(listener_id, None)
def emit(self, name, *args):
# type: (unicode, Any) -> List
results = []
- for callback in itervalues(self.listeners[name]):
+ for callback in self.listeners[name].values():
results.append(callback(*args))
return results
diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py
index a154f6449..31cdb5855 100644
--- a/sphinx/ext/apidoc.py
+++ b/sphinx/ext/apidoc.py
@@ -32,7 +32,7 @@ from sphinx import __display_version__, package_dir
from sphinx.cmd.quickstart import EXTENSIONS
from sphinx.locale import __
from sphinx.util import rst
-from sphinx.util.osutil import FileAvoidWrite, ensuredir, walk
+from sphinx.util.osutil import FileAvoidWrite, ensuredir
if False:
# For type annotation
@@ -235,7 +235,7 @@ def recurse_tree(rootpath, excludes, opts):
root_package = None
toplevels = []
- for root, subs, files in walk(rootpath, followlinks=followlinks):
+ for root, subs, files in os.walk(rootpath, followlinks=followlinks):
# document only Python module files (that aren't excluded)
py_files = sorted(f for f in files
if path.splitext(f)[1] in PY_SUFFIXES and
diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index 6823505ee..8411e1ac4 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -18,14 +18,12 @@ import warnings
from typing import Any
from docutils.statemachine import ViewList
-from six import iteritems, itervalues, text_type, class_types, string_types
+from six import text_type, string_types
import sphinx
-from sphinx.deprecation import RemovedInSphinx20Warning, RemovedInSphinx30Warning
-from sphinx.errors import ExtensionError
+from sphinx.deprecation import RemovedInSphinx30Warning
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.locale import _, __
from sphinx.pycode import ModuleAnalyzer, PycodeError
from sphinx.util import logging
@@ -124,58 +122,6 @@ def merge_special_members_option(options):
options['members'] = options['special-members']
-class AutodocReporter(object):
- """
- A reporter replacement that assigns the correct source name
- and line number to a system message, as recorded in a ViewList.
- """
- 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
-
- def __getattr__(self, name):
- # type: (unicode) -> Any
- return getattr(self.reporter, name)
-
- def system_message(self, level, message, *children, **kwargs):
- # type: (int, unicode, Any, Any) -> nodes.system_message
- if 'line' in kwargs and 'source' not in kwargs:
- try:
- source, line = self.viewlist.items[kwargs['line']]
- except IndexError:
- pass
- else:
- kwargs['source'] = source
- kwargs['line'] = line
- return self.reporter.system_message(level, message,
- *children, **kwargs)
-
- def debug(self, *args, **kwargs):
- # type: (Any, Any) -> nodes.system_message
- if self.reporter.debug_flag:
- return self.system_message(0, *args, **kwargs)
-
- def info(self, *args, **kwargs):
- # type: (Any, Any) -> nodes.system_message
- return self.system_message(1, *args, **kwargs)
-
- def warning(self, *args, **kwargs):
- # type: (Any, Any) -> nodes.system_message
- return self.system_message(2, *args, **kwargs)
-
- def error(self, *args, **kwargs):
- # type: (Any, Any) -> nodes.system_message
- return self.system_message(3, *args, **kwargs)
-
- def severe(self, *args, **kwargs):
- # type: (Any, Any) -> nodes.system_message
- return self.system_message(4, *args, **kwargs)
-
-
# Some useful event listener factories for autodoc-process-docstring.
def cut_lines(pre, post=0, what=None):
@@ -255,7 +201,7 @@ class Options(dict):
return None
-class Documenter(object):
+class Documenter:
"""
A Documenter knows how to autodocument a single object type. When
registered with the AutoDirective, it will be used to document objects
@@ -356,7 +302,8 @@ class Documenter(object):
explicit_modname, path, base, args, retann = \
py_ext_sig_re.match(self.name).groups()
except AttributeError:
- logger.warning(__('invalid signature for auto%s (%r)') % (self.objtype, self.name))
+ logger.warning(__('invalid signature for auto%s (%r)') % (self.objtype, self.name),
+ type='autodoc')
return False
# support explicit module and class name separation via ::
@@ -393,7 +340,7 @@ class Documenter(object):
self.module, self.parent, self.object_name, self.object = ret
return True
except ImportError as exc:
- logger.warning(exc.args[0])
+ logger.warning(exc.args[0], type='autodoc', subtype='import_object')
self.env.note_reread()
return False
@@ -456,7 +403,7 @@ class Documenter(object):
args = self.format_args()
except Exception as err:
logger.warning(__('error while formatting arguments for %s: %s') %
- (self.fullname, err))
+ (self.fullname, err), type='autodoc')
args = None
retann = self.retann
@@ -578,12 +525,12 @@ class Documenter(object):
selected.append((name, members[name].value))
else:
logger.warning(__('missing attribute %s in object %s') %
- (name, self.fullname))
+ (name, self.fullname), type='autodoc')
return False, sorted(selected)
elif self.options.inherited_members:
- return False, sorted((m.name, m.value) for m in itervalues(members))
+ return False, sorted((m.name, m.value) for m in members.values())
else:
- return False, sorted((m.name, m.value) for m in itervalues(members)
+ return False, sorted((m.name, m.value) for m in members.values()
if m.directly_defined)
def filter_members(self, members, want_all):
@@ -667,7 +614,7 @@ class Documenter(object):
except Exception as exc:
logger.warning(__('autodoc: failed to determine %r to be documented.'
'the following exception was raised:\n%s'),
- member, exc)
+ member, exc, type='autodoc')
keep = False
if keep:
@@ -705,7 +652,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(self.documenters)
+ classes = [cls for cls in self.documenters.values()
if cls.can_document_member(member, mname, isattr, self)]
if not classes:
# don't know how to document this member
@@ -760,7 +707,7 @@ class Documenter(object):
__('don\'t know which module to import for autodocumenting '
'%r (try placing a "module" or "currentmodule" directive '
'in the document, or giving an explicit module name)') %
- self.name)
+ self.name, type='autodoc')
return
# now, import the module and get object to document
@@ -851,7 +798,8 @@ class ModuleDocumenter(Documenter):
def resolve_name(self, modname, parents, path, base):
# type: (str, Any, str, Any) -> Tuple[str, List[unicode]]
if modname is not None:
- logger.warning(__('"::" in automodule name doesn\'t make sense'))
+ logger.warning(__('"::" in automodule name doesn\'t make sense'),
+ type='autodoc')
return (path or '') + base, []
def parse_name(self):
@@ -859,7 +807,8 @@ class ModuleDocumenter(Documenter):
ret = Documenter.parse_name(self)
if self.args or self.retann:
logger.warning(__('signature arguments or return annotation '
- 'given for automodule %s') % self.fullname)
+ 'given for automodule %s') % self.fullname,
+ type='autodoc')
return ret
def add_directive_header(self, sig):
@@ -894,7 +843,9 @@ class ModuleDocumenter(Documenter):
logger.warning(
__('__all__ should be a list of strings, not %r '
'(in module %s) -- ignoring __all__') %
- (memberlist, self.fullname))
+ (memberlist, self.fullname),
+ type='autodoc'
+ )
# fall back to all members
return True, safe_getmembers(self.object)
else:
@@ -907,7 +858,9 @@ class ModuleDocumenter(Documenter):
logger.warning(
__('missing attribute mentioned in :members: or __all__: '
'module %s, attribute %s') %
- (safe_getattr(self.object, '__name__', '???'), mname))
+ (safe_getattr(self.object, '__name__', '???'), mname),
+ type='autodoc'
+ )
return False, ret
@@ -965,7 +918,7 @@ class ClassLevelDocumenter(Documenter):
return modname, parents + [base]
-class DocstringSignatureMixin(object):
+class DocstringSignatureMixin:
"""
Mixin for FunctionDocumenter and MethodDocumenter to provide the
feature of reading the signature from the docstring.
@@ -1108,7 +1061,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
# type: (Any, unicode, bool, Any) -> bool
- return isinstance(member, class_types)
+ return isinstance(member, type)
def import_object(self):
# type: () -> Any
@@ -1260,8 +1213,7 @@ class ExceptionDocumenter(ClassDocumenter):
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
# type: (Any, unicode, bool, Any) -> bool
- return isinstance(member, class_types) and \
- issubclass(member, BaseException) # type: ignore
+ return isinstance(member, type) and issubclass(member, BaseException)
class DataDocumenter(ModuleLevelDocumenter):
@@ -1392,7 +1344,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
# exported anywhere by Python
return isdatadesc or (not isinstance(parent, ModuleDocumenter) and
not inspect.isroutine(member) and
- not isinstance(member, class_types))
+ not isinstance(member, type))
def document_members(self, all_members=False):
# type: (bool) -> None
@@ -1475,87 +1427,16 @@ class InstanceAttributeDocumenter(AttributeDocumenter):
AttributeDocumenter.add_content(self, more_content, no_docstring=True)
-class DeprecatedDict(dict):
- def __init__(self, message):
- # type: (str) -> None
- self.message = message
- super(DeprecatedDict, self).__init__()
-
- def __setitem__(self, key, value):
- # type: (unicode, Any) -> None
- warnings.warn(self.message, RemovedInSphinx20Warning)
- super(DeprecatedDict, self).__setitem__(key, value)
-
- def setdefault(self, key, default=None):
- # type: (unicode, Any) -> None
- warnings.warn(self.message, RemovedInSphinx20Warning)
- super(DeprecatedDict, self).setdefault(key, default)
-
- def update(self, other=None): # type: ignore
- # type: (Dict) -> 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 (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 = DeprecatedDict(
- 'AutoDirective._special_attrgetters has been deprecated. '
- 'Please use app.add_autodoc_attrgetter() instead.'
- ) # type: Dict[Type, Callable]
-
-
-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)
- # actually, it should be possible to override Documenters
- # if cls.objtype in AutoDirective._registry:
- # raise ExtensionError('autodoc documenter for %r is already '
- # 'registered' % cls.objtype)
- 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
+ return app.registry.documenters
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):
+ for typ, func in app.registry.autodoc_attrgettrs.items():
if isinstance(obj, typ):
return func(obj, name, *defargs)
@@ -1582,7 +1463,7 @@ def merge_autodoc_default_flags(app, config):
else:
logger.warning(
__("Ignoring invalid option in autodoc_default_flags: %r"),
- option
+ option, type='autodoc'
)
diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py
index 3a3434fc8..e831cab64 100644
--- a/sphinx/ext/autodoc/directive.py
+++ b/sphinx/ext/autodoc/directive.py
@@ -34,7 +34,7 @@ AUTODOC_DEFAULT_OPTIONS = ['members', 'undoc-members', 'inherited-members',
'ignore-module-all', 'exclude-members']
-class DummyOptionSpec(object):
+class DummyOptionSpec:
"""An option_spec allows any options."""
def __getitem__(self, key):
@@ -42,7 +42,7 @@ class DummyOptionSpec(object):
return lambda x: x
-class DocumenterBridge(object):
+class DocumenterBridge:
"""A parameters container for Documenters."""
def __init__(self, env, reporter, options, lineno):
diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py
index a2280e82b..45bab042b 100644
--- a/sphinx/ext/autodoc/importer.py
+++ b/sphinx/ext/autodoc/importer.py
@@ -16,8 +16,6 @@ import warnings
from collections import namedtuple
from types import FunctionType, MethodType, ModuleType
-from six import PY2, iteritems
-
from sphinx.util import logging
from sphinx.util.inspect import isenumclass, safe_getattr
@@ -28,7 +26,7 @@ if False:
logger = logging.getLogger(__name__)
-class _MockObject(object):
+class _MockObject:
"""Used by autodoc_mock_imports."""
def __new__(cls, *args, **kwargs):
@@ -93,7 +91,7 @@ class _MockModule(ModuleType):
return o
-class _MockImporter(object):
+class _MockImporter:
def __init__(self, names):
# type: (List[str]) -> None
self.names = names
@@ -219,8 +217,6 @@ def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warning
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)
@@ -234,12 +230,6 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
# 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 = {} # type: Dict[str, Attribute]
# enum members
@@ -249,7 +239,7 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
members[name] = Attribute(name, True, value)
superclass = subject.__mro__[1]
- for name, value in iteritems(obj_dict):
+ for name, value in obj_dict.items():
if name not in superclass.__dict__:
members[name] = Attribute(name, True, value)
diff --git a/sphinx/ext/autodoc/inspector.py b/sphinx/ext/autodoc/inspector.py
deleted file mode 100644
index be42237c6..000000000
--- a/sphinx/ext/autodoc/inspector.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.ext.autodoc.inspector
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Inspect utilities for autodoc
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-import typing
-import warnings
-
-from six import StringIO, string_types
-
-from sphinx.deprecation import RemovedInSphinx20Warning
-from sphinx.util.inspect import object_description
-
-if False:
- # For type annotation
- from typing import Any, Callable, Dict, Tuple # NOQA
-
-
-def format_annotation(annotation):
- # type: (Any) -> str
- """Return formatted representation of a type annotation.
-
- Show qualified names for types and additional details for types from
- the ``typing`` module.
-
- 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
- return annotation.__name__
- if annotation == Ellipsis:
- return '...'
- if not isinstance(annotation, type):
- return repr(annotation)
-
- qualified_name = (annotation.__module__ + '.' + annotation.__qualname__ # type: ignore
- if annotation else repr(annotation))
-
- if annotation.__module__ == 'builtins':
- return annotation.__qualname__ # type: ignore
- else:
- if hasattr(typing, 'GenericMeta') and \
- isinstance(annotation, typing.GenericMeta):
- # In Python 3.5.2+, all arguments are stored in __args__,
- # whereas __parameters__ only contains generic parameters.
- #
- # Prior to Python 3.5.2, __args__ is not available, and all
- # arguments are in __parameters__.
- params = None
- if hasattr(annotation, '__args__'):
- if annotation.__args__ is None or len(annotation.__args__) <= 2: # type: ignore # NOQA
- params = annotation.__args__ # type: ignore
- else: # typing.Callable
- args = ', '.join(format_annotation(a) for a in annotation.__args__[:-1]) # type: ignore # NOQA
- result = format_annotation(annotation.__args__[-1]) # type: ignore
- return '%s[[%s], %s]' % (qualified_name, args, result)
- elif hasattr(annotation, '__parameters__'):
- params = annotation.__parameters__ # type: ignore
- if params is not None:
- param_str = ', '.join(format_annotation(p) for p in params)
- return '%s[%s]' % (qualified_name, param_str)
- elif (hasattr(typing, 'UnionMeta') and
- isinstance(annotation, typing.UnionMeta) and # type: ignore
- hasattr(annotation, '__union_params__')):
- params = annotation.__union_params__
- if params is not None:
- param_str = ', '.join(format_annotation(p) for p in params)
- return '%s[%s]' % (qualified_name, param_str)
- elif (hasattr(typing, 'CallableMeta') and
- isinstance(annotation, typing.CallableMeta) and # type: ignore
- getattr(annotation, '__args__', None) is not None and
- hasattr(annotation, '__result__')):
- # Skipped in the case of plain typing.Callable
- args = annotation.__args__
- if args is None:
- return qualified_name
- elif args is Ellipsis:
- args_str = '...'
- else:
- formatted_args = (format_annotation(a) for a in args)
- args_str = '[%s]' % ', '.join(formatted_args)
- return '%s[%s, %s]' % (qualified_name,
- args_str,
- format_annotation(annotation.__result__))
- elif (hasattr(typing, 'TupleMeta') and
- isinstance(annotation, typing.TupleMeta) and # type: ignore
- hasattr(annotation, '__tuple_params__') and
- hasattr(annotation, '__tuple_use_ellipsis__')):
- params = annotation.__tuple_params__
- if params is not None:
- param_strings = [format_annotation(p) for p in params]
- if annotation.__tuple_use_ellipsis__:
- param_strings.append('...')
- return '%s[%s]' % (qualified_name,
- ', '.join(param_strings))
- return qualified_name
-
-
-def formatargspec(function, args, varargs=None, varkw=None, defaults=None,
- kwonlyargs=(), kwonlydefaults={}, annotations={}):
- # type: (Callable, Tuple[str, ...], str, str, Any, Tuple, Dict, Dict[str, Any]) -> str
- """Return a string representation of an ``inspect.FullArgSpec`` tuple.
-
- An enhanced version of ``inspect.formatargspec()`` that handles typing
- annotations better.
- """
- warnings.warn('formatargspec() is now deprecated. '
- 'Please use sphinx.util.inspect.Signature instead.',
- RemovedInSphinx20Warning)
-
- def format_arg_with_annotation(name):
- # type: (str) -> str
- if name in annotations:
- return '%s: %s' % (name, format_annotation(get_annotation(name)))
- return name
-
- def get_annotation(name):
- # type: (str) -> str
- value = annotations[name]
- if isinstance(value, string_types):
- return introspected_hints.get(name, value)
- else:
- return value
-
- try:
- introspected_hints = (typing.get_type_hints(function) # type: ignore
- if typing and hasattr(function, '__code__') else {})
- except Exception:
- introspected_hints = {}
-
- fd = StringIO()
- fd.write('(')
-
- formatted = []
- defaults_start = len(args) - len(defaults) if defaults else len(args)
-
- for i, arg in enumerate(args):
- arg_fd = StringIO()
- if isinstance(arg, list):
- # support tupled arguments list (only for py2): def foo((x, y))
- arg_fd.write('(')
- arg_fd.write(format_arg_with_annotation(arg[0]))
- for param in arg[1:]:
- arg_fd.write(', ')
- arg_fd.write(format_arg_with_annotation(param))
- arg_fd.write(')')
- else:
- arg_fd.write(format_arg_with_annotation(arg))
- if defaults and i >= defaults_start:
- arg_fd.write(' = ' if arg in annotations else '=')
- arg_fd.write(object_description(defaults[i - defaults_start])) # type: ignore
- formatted.append(arg_fd.getvalue())
-
- if varargs:
- formatted.append('*' + format_arg_with_annotation(varargs))
-
- if kwonlyargs:
- if not varargs:
- formatted.append('*')
-
- for kwarg in kwonlyargs:
- arg_fd = StringIO()
- arg_fd.write(format_arg_with_annotation(kwarg))
- if kwonlydefaults and kwarg in kwonlydefaults:
- arg_fd.write(' = ' if kwarg in annotations else '=')
- arg_fd.write(object_description(kwonlydefaults[kwarg])) # type: ignore
- formatted.append(arg_fd.getvalue())
-
- if varkw:
- formatted.append('**' + format_arg_with_annotation(varkw))
-
- fd.write(', '.join(formatted))
- fd.write(')')
-
- if 'return' in annotations:
- fd.write(' -> ')
- fd.write(format_annotation(get_annotation('return')))
-
- return fd.getvalue()
diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py
index c450733ab..10adfc9ce 100644
--- a/sphinx/ext/autosummary/__init__.py
+++ b/sphinx/ext/autosummary/__init__.py
@@ -58,7 +58,6 @@ import os
import posixpath
import re
import sys
-import warnings
from types import ModuleType
from docutils import nodes
@@ -70,7 +69,6 @@ from six import text_type
import sphinx
from sphinx import addnodes
-from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment.adapters.toctree import TocTree
from sphinx.ext.autodoc import get_documenters
from sphinx.ext.autodoc.directive import DocumenterBridge, Options
@@ -176,8 +174,8 @@ class FakeDirective(DocumenterBridge):
super(FakeDirective, self).__init__({}, None, Options(), 0) # type: ignore
-def get_documenter(*args):
- # type: (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.
@@ -186,16 +184,6 @@ def get_documenter(*args):
belongs to.
"""
from sphinx.ext.autodoc import DataDocumenter, ModuleDocumenter
- if len(args) == 3:
- # new style arguments: (app, obj, parent)
- app, obj, parent = args
- else:
- # old style arguments: (obj, parent)
- app = _app
- obj, parent = args
- warnings.warn('the interface of get_documenter() has been changed. '
- 'Please give application object as first argument.',
- RemovedInSphinx20Warning)
if inspect.ismodule(obj):
# ModuleDocumenter.can_document_member always returns False
diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py
index cb27a664d..20a06aeb4 100644
--- a/sphinx/ext/autosummary/generate.py
+++ b/sphinx/ext/autosummary/generate.py
@@ -20,7 +20,6 @@
from __future__ import print_function
import argparse
-import codecs
import locale
import os
import pydoc
@@ -51,7 +50,7 @@ if False:
from sphinx.ext.autodoc import Documenter # NOQA
-class DummyApplication(object):
+class DummyApplication:
"""Dummy Application class for sphinx-autogen command."""
def __init__(self):
@@ -249,8 +248,8 @@ def find_autosummary_in_files(filenames):
"""
documented = [] # type: List[Tuple[unicode, unicode, unicode]]
for filename in filenames:
- with codecs.open(filename, 'r', encoding='utf-8', # type: ignore
- errors='ignore') as f:
+ with open(filename, 'r', encoding='utf-8', # type: ignore
+ errors='ignore') as f:
lines = f.read().splitlines()
documented.extend(find_autosummary_in_lines(lines, filename=filename))
return documented
diff --git a/sphinx/ext/coverage.py b/sphinx/ext/coverage.py
index d6d865665..76b721adf 100644
--- a/sphinx/ext/coverage.py
+++ b/sphinx/ext/coverage.py
@@ -12,12 +12,10 @@
import glob
import inspect
+import pickle
import re
from os import path
-from six import iteritems
-from six.moves import cPickle as pickle
-
import sphinx
from sphinx.builders import Builder
from sphinx.locale import __
@@ -73,7 +71,7 @@ class CoverageBuilder(Builder):
logger.warning(__('invalid regex %r in coverage_c_regexes'), exp)
self.c_ignorexps = {} # type: Dict[unicode, List[Pattern]]
- for (name, exps) in iteritems(self.config.coverage_ignore_c_items):
+ for (name, exps) in self.config.coverage_ignore_c_items.items():
self.c_ignorexps[name] = compile_regex_list('coverage_ignore_c_items',
exps)
self.mod_ignorexps = compile_regex_list('coverage_ignore_modules',
@@ -127,7 +125,7 @@ class CoverageBuilder(Builder):
write_header(op, 'Undocumented C API elements', '=')
op.write('\n')
- for filename, undoc in iteritems(self.c_undoc):
+ for filename, undoc in self.c_undoc.items():
write_header(op, filename)
for typ, name in sorted(undoc):
op.write(' * %-50s [%9s]\n' % (name, typ))
@@ -247,7 +245,7 @@ class CoverageBuilder(Builder):
if undoc['classes']:
op.write('Classes:\n')
for name, methods in sorted(
- iteritems(undoc['classes'])):
+ undoc['classes'].items()):
if not methods:
op.write(' * %s\n' % name)
else:
diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py
index c35b3d284..b2244d032 100644
--- a/sphinx/ext/doctest.py
+++ b/sphinx/ext/doctest.py
@@ -11,27 +11,28 @@
"""
from __future__ import absolute_import
-import codecs
import doctest
import re
import sys
import time
+import warnings
from os import path
from docutils import nodes
from docutils.parsers.rst import directives
from packaging.specifiers import SpecifierSet, InvalidSpecifier
from packaging.version import Version
-from six import itervalues, StringIO, binary_type, text_type, PY2
+from six import StringIO, binary_type
import sphinx
from sphinx.builders import Builder
+from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.locale import __
from sphinx.util import force_decode, logging
from sphinx.util.console import bold # type: ignore
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import set_source_info
-from sphinx.util.osutil import fs_encoding, relpath
+from sphinx.util.osutil import relpath
if False:
# For type annotation
@@ -43,18 +44,12 @@ logger = logging.getLogger(__name__)
blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
-if PY2:
- def doctest_encode(text, encoding):
- # type: (str, unicode) -> unicode
- if isinstance(text, text_type):
- text = text.encode(encoding)
- if text.startswith(codecs.BOM_UTF8):
- text = text[len(codecs.BOM_UTF8):]
- return text
-else:
- def doctest_encode(text, encoding):
- # type: (unicode, unicode) -> unicode
- return text
+
+def doctest_encode(text, encoding):
+ # type: (unicode, unicode) -> unicode
+ warnings.warn('doctest_encode() is deprecated.',
+ RemovedInSphinx40Warning)
+ return text
def is_allowed_version(spec, version):
@@ -203,7 +198,7 @@ parser = doctest.DocTestParser()
# helper classes
-class TestGroup(object):
+class TestGroup:
def __init__(self, name):
# type: (unicode) -> None
self.name = name
@@ -236,7 +231,7 @@ class TestGroup(object):
self.name, self.setup, self.cleanup, self.tests)
-class TestCode(object):
+class TestCode:
def __init__(self, code, type, filename, lineno, options=None):
# type: (unicode, unicode, Optional[str], int, Optional[Dict]) -> None
self.code = code
@@ -318,8 +313,8 @@ class DocTestBuilder(Builder):
date = time.strftime('%Y-%m-%d %H:%M:%S')
self.outfile = None # type: IO
- self.outfile = codecs.open(path.join(self.outdir, 'output.txt'), # type: ignore
- 'w', encoding='utf-8')
+ self.outfile = open(path.join(self.outdir, 'output.txt'), # type: ignore
+ 'w', encoding='utf-8')
self.outfile.write(('Results of doctest builder run on %s\n'
'==================================%s\n') %
(date, '=' * len(date)))
@@ -382,7 +377,7 @@ Doctest summary
self.test_doc(docname, doctree)
def get_filename_for_node(self, node, docname):
- # type: (nodes.Node, unicode) -> str
+ # type: (nodes.Node, unicode) -> unicode
"""Try to get the file which actually contains the doctest, not the
filename of the document it's included in."""
try:
@@ -390,8 +385,6 @@ Doctest summary
.rsplit(':docstring of ', maxsplit=1)[0]
except Exception:
filename = self.env.doc2path(docname, base=None)
- if PY2:
- return filename.encode(fs_encoding)
return filename
@staticmethod
@@ -444,7 +437,7 @@ Doctest summary
logger.warning(__('no code/output in %s block at %s:%s'),
node.get('testnodetype', 'doctest'),
filename, line_number)
- code = TestCode(source, type=node.get('testnodetype', 'doctest'),
+ code = TestCode(source, type=node.get('testnodetype', 'doctest'), # type: ignore
filename=filename, lineno=line_number,
options=node.get('options'))
node_groups = node.get('groups', ['default'])
@@ -456,24 +449,24 @@ Doctest summary
groups[groupname] = TestGroup(groupname)
groups[groupname].add_code(code)
for code in add_to_all_groups:
- for group in itervalues(groups):
+ for group in groups.values():
group.add_code(code)
if self.config.doctest_global_setup:
code = TestCode(self.config.doctest_global_setup,
'testsetup', filename=None, lineno=0)
- for group in itervalues(groups):
+ for group in groups.values():
group.add_code(code, prepend=True)
if self.config.doctest_global_cleanup:
code = TestCode(self.config.doctest_global_cleanup,
'testcleanup', filename=None, lineno=0)
- for group in itervalues(groups):
+ for group in groups.values():
group.add_code(code)
if not groups:
return
self._out('\nDocument: %s\n----------%s\n' %
(docname, '-' * len(docname)))
- for group in itervalues(groups):
+ for group in groups.values():
self.test_group(group)
# Separately count results from setup code
res_f, res_t = self.setup_runner.summarize(self._out, verbose=False)
@@ -501,9 +494,9 @@ Doctest summary
# type: (Any, List[TestCode], Any) -> bool
examples = []
for testcode in testcodes:
- examples.append(doctest.Example( # type: ignore
- doctest_encode(testcode.code, self.env.config.source_encoding), '', # type: ignore # NOQA
- lineno=testcode.lineno))
+ example = doctest.Example(testcode.code, '', # type: ignore
+ lineno=testcode.lineno)
+ examples.append(example)
if not examples:
return True
# simulate a doctest with the code
@@ -528,9 +521,8 @@ Doctest summary
if len(code) == 1:
# ordinary doctests (code/output interleaved)
try:
- test = parser.get_doctest( # type: ignore
- doctest_encode(code[0].code, self.env.config.source_encoding), {}, # type: ignore # NOQA
- group.name, code[0].filename, code[0].lineno)
+ test = parser.get_doctest(code[0].code, {}, group.name, # type: ignore
+ code[0].filename, code[0].lineno)
except Exception:
logger.warning(__('ignoring invalid doctest code: %r'), code[0].code,
location=(code[0].filename, code[0].lineno))
@@ -555,11 +547,10 @@ Doctest summary
exc_msg = m.group('msg')
else:
exc_msg = None
- example = doctest.Example( # type: ignore
- doctest_encode(code[0].code, self.env.config.source_encoding), output, # type: ignore # NOQA
- exc_msg=exc_msg,
- lineno=code[0].lineno,
- options=options)
+ example = doctest.Example(code[0].code, output, # type: ignore
+ exc_msg=exc_msg,
+ lineno=code[0].lineno,
+ options=options)
test = doctest.DocTest([example], {}, group.name, # type: ignore
code[0].filename, code[0].lineno, None)
self.type = 'exec' # multiple statements again
diff --git a/sphinx/ext/extlinks.py b/sphinx/ext/extlinks.py
index 29bfe928f..106748dbb 100644
--- a/sphinx/ext/extlinks.py
+++ b/sphinx/ext/extlinks.py
@@ -25,7 +25,6 @@
"""
from docutils import nodes, utils
-from six import iteritems
import sphinx
from sphinx.util.nodes import split_explicit_title
@@ -64,7 +63,7 @@ def make_link_role(base_url, prefix):
def setup_link_roles(app):
# type: (Sphinx) -> None
- for name, (base_url, prefix) in iteritems(app.config.extlinks):
+ for name, (base_url, prefix) in app.config.extlinks.items():
app.add_role(name, make_link_role(base_url, prefix))
diff --git a/sphinx/ext/graphviz.py b/sphinx/ext/graphviz.py
index 5ed39cfcf..57d63f120 100644
--- a/sphinx/ext/graphviz.py
+++ b/sphinx/ext/graphviz.py
@@ -10,7 +10,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
import posixpath
import re
from hashlib import sha1
@@ -44,7 +43,7 @@ class GraphvizError(SphinxError):
category = 'Graphviz error'
-class ClickableMapDefinition(object):
+class ClickableMapDefinition:
"""A manipulator for clickable map file of graphviz."""
maptag_re = re.compile('<map id="(.*?)"')
href_re = re.compile('href=".*?"')
@@ -142,7 +141,7 @@ class Graphviz(SphinxDirective):
rel_filename, filename = self.env.relfn2path(argument)
self.env.note_dependency(rel_filename)
try:
- with codecs.open(filename, 'r', 'utf-8') as fp: # type: ignore
+ with open(filename, 'r', encoding='utf-8') as fp: # type: ignore
dotcode = fp.read()
except (IOError, OSError):
return [document.reporter.warning(
@@ -309,7 +308,7 @@ def render_dot_html(self, node, code, options, prefix='graphviz',
self.body.append('<p class="warning">%s</p>' % alt)
self.body.append('</object></div>\n')
else:
- with codecs.open(outfn + '.map', 'r', encoding='utf-8') as mapfile: # type: ignore
+ with open(outfn + '.map', 'r', encoding='utf-8') as mapfile: # type: ignore
imgmap = ClickableMapDefinition(outfn + '.map', mapfile.read(), dot=code)
if imgmap.clickable:
# has a map
diff --git a/sphinx/ext/imgmath.py b/sphinx/ext/imgmath.py
index 18f04a095..cbd38b84c 100644
--- a/sphinx/ext/imgmath.py
+++ b/sphinx/ext/imgmath.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
import posixpath
import re
import shutil
@@ -123,7 +122,7 @@ def compile_math(latex, builder):
"""Compile LaTeX macros for math to DVI."""
tempdir = ensure_tempdir(builder)
filename = path.join(tempdir, 'math.tex')
- with codecs.open(filename, 'w', 'utf-8') as f: # type: ignore
+ with open(filename, 'w', encoding='utf-8') as f: # type: ignore
f.write(latex)
# build latex command; old versions of latex don't have the
diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py
index 750fcd4f7..3815f6ba1 100644
--- a/sphinx/ext/inheritance_diagram.py
+++ b/sphinx/ext/inheritance_diagram.py
@@ -36,6 +36,7 @@ r"""
:license: BSD, see LICENSE for details.
"""
+import builtins
import inspect
import re
import sys
@@ -44,7 +45,6 @@ from hashlib import md5
from docutils import nodes
from docutils.parsers.rst import directives
from six import text_type
-from six.moves import builtins
import sphinx
from sphinx.ext.graphviz import render_dot_html, render_dot_latex, \
@@ -129,7 +129,7 @@ class InheritanceException(Exception):
pass
-class InheritanceGraph(object):
+class InheritanceGraph:
"""
Given a list of classes, determines the set of classes that they inherit
from all the way to the root "object", and then is able to generate a
diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py
index e3f8dc275..482ed1957 100644
--- a/sphinx/ext/intersphinx.py
+++ b/sphinx/ext/intersphinx.py
@@ -30,17 +30,15 @@ import functools
import posixpath
import sys
import time
-import warnings
from os import path
from docutils import nodes
from docutils.utils import relative_path
-from six import PY3, iteritems, string_types
+from six import string_types, text_type
from six.moves.urllib.parse import urlsplit, urlunsplit
import sphinx
from sphinx.builders.html import INVENTORY_FILENAME
-from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.locale import _, __
from sphinx.util import requests, logging
from sphinx.util.inventory import InventoryFile
@@ -52,15 +50,12 @@ if False:
from sphinx.config import Config # NOQA
from sphinx.environment import BuildEnvironment # NOQA
- if PY3:
- unicode = str
-
- Inventory = Dict[unicode, Dict[unicode, Tuple[unicode, unicode, unicode, unicode]]]
+ Inventory = Dict[text_type, Dict[text_type, Tuple[text_type, text_type, text_type, text_type]]] # NOQA
logger = logging.getLogger(__name__)
-class InventoryAdapter(object):
+class InventoryAdapter:
"""Inventory adapter for environment"""
def __init__(self, env):
@@ -214,7 +209,7 @@ def load_mappings(app):
cache_time = now - app.config.intersphinx_cache_limit * 86400
inventories = InventoryAdapter(app.builder.env)
update = False
- for key, value in iteritems(app.config.intersphinx_mapping):
+ for key, value in app.config.intersphinx_mapping.items():
name = None # type: unicode
uri = None # type: unicode
inv = None # type: Union[unicode, Tuple[unicode, ...]]
@@ -286,7 +281,7 @@ def load_mappings(app):
for name, _x, invdata in named_vals + unnamed_vals:
if name:
inventories.named_inventory[name] = invdata
- for type, objects in iteritems(invdata):
+ for type, objects in invdata.items():
inventories.main_inventory.setdefault(type, {}).update(objects)
@@ -380,15 +375,6 @@ def setup(app):
}
-def debug(argv):
- # type: (List[unicode]) -> None
- """Debug functionality to print out an inventory"""
- warnings.warn('sphinx.ext.intersphinx.debug() is deprecated. '
- 'Please use inspect_main() instead',
- RemovedInSphinx20Warning)
- inspect_main(argv[1:])
-
-
def inspect_main(argv):
# type: (List[unicode]) -> None
"""Debug functionality to print out an inventory"""
@@ -398,11 +384,11 @@ def inspect_main(argv):
file=sys.stderr)
sys.exit(1)
- class MockConfig(object):
+ class MockConfig:
intersphinx_timeout = None # type: int
tls_verify = False
- class MockApp(object):
+ class MockApp:
srcdir = ''
config = MockConfig()
diff --git a/sphinx/ext/napoleon/__init__.py b/sphinx/ext/napoleon/__init__.py
index b968f5948..00b78e859 100644
--- a/sphinx/ext/napoleon/__init__.py
+++ b/sphinx/ext/napoleon/__init__.py
@@ -9,11 +9,7 @@
:license: BSD, see LICENSE for details.
"""
-import sys
-
-from six import PY2, iteritems
-
-import sphinx
+from sphinx import __display_version__ as __version__
from sphinx.application import Sphinx
from sphinx.ext.napoleon.docstring import GoogleDocstring, NumpyDocstring
@@ -22,7 +18,7 @@ if False:
from typing import Any, Dict, List # NOQA
-class Config(object):
+class Config:
"""Sphinx napoleon extension settings in `conf.py`.
Listed below are all the settings used by napoleon and their default
@@ -176,10 +172,10 @@ class Config(object):
.. attribute:: attr1
- *int*
-
Description of `attr1`
+ :type: int
+
napoleon_use_param : :obj:`bool` (Defaults to True)
True to use a ``:param:`` role for each function parameter. False to
use a single ``:parameters:`` role for all the parameters.
@@ -274,9 +270,9 @@ class Config(object):
def __init__(self, **settings):
# type: (Any) -> None
- for name, (default, rebuild) in iteritems(self._config_values):
+ for name, (default, rebuild) in self._config_values.items():
setattr(self, name, default)
- for name, value in iteritems(settings):
+ for name, value in settings.items():
setattr(self, name, value)
@@ -304,7 +300,8 @@ def setup(app):
"""
if not isinstance(app, Sphinx):
- return # probably called by tests
+ # probably called by tests
+ return {'version': __version__, 'parallel_read_safe': True}
_patch_python_domain()
@@ -312,9 +309,9 @@ def setup(app):
app.connect('autodoc-process-docstring', _process_docstring)
app.connect('autodoc-skip-member', _skip_member)
- for name, (default, rebuild) in iteritems(Config._config_values):
+ for name, (default, rebuild) in Config._config_values.items():
app.add_config_value(name, default, rebuild)
- return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
+ return {'version': __version__, 'parallel_read_safe': True}
def _patch_python_domain():
@@ -435,34 +432,26 @@ def _skip_member(app, what, name, obj, skip, options):
if name != '__weakref__' and has_doc and is_member:
cls_is_owner = False
if what == 'class' or what == 'exception':
- if PY2:
- cls = getattr(obj, 'im_class', getattr(obj, '__objclass__',
- None))
- cls_is_owner = (cls and hasattr(cls, name) and
- name in cls.__dict__)
- elif sys.version_info >= (3, 3):
- qualname = getattr(obj, '__qualname__', '')
- cls_path, _, _ = qualname.rpartition('.')
- if cls_path:
- try:
- if '.' in cls_path:
- import importlib
- import functools
-
- mod = importlib.import_module(obj.__module__)
- mod_path = cls_path.split('.')
- cls = functools.reduce(getattr, mod_path, mod)
- else:
- cls = obj.__globals__[cls_path]
- except Exception:
- cls_is_owner = False
+ qualname = getattr(obj, '__qualname__', '')
+ cls_path, _, _ = qualname.rpartition('.')
+ if cls_path:
+ try:
+ if '.' in cls_path:
+ import importlib
+ import functools
+
+ mod = importlib.import_module(obj.__module__)
+ mod_path = cls_path.split('.')
+ cls = functools.reduce(getattr, mod_path, mod)
else:
- cls_is_owner = (cls and hasattr(cls, name) and
- name in cls.__dict__)
- else:
+ cls = obj.__globals__[cls_path]
+ except Exception:
cls_is_owner = False
+ else:
+ cls_is_owner = (cls and hasattr(cls, name) and # type: ignore
+ name in cls.__dict__)
else:
- cls_is_owner = True
+ cls_is_owner = False
if what == 'module' or cls_is_owner:
is_init = (name == '__init__')
diff --git a/sphinx/ext/napoleon/docstring.py b/sphinx/ext/napoleon/docstring.py
index 2e5380472..f8a1327aa 100644
--- a/sphinx/ext/napoleon/docstring.py
+++ b/sphinx/ext/napoleon/docstring.py
@@ -11,13 +11,12 @@
:license: BSD, see LICENSE for details.
"""
-import collections
import inspect
import re
+from collections.abc import Callable
from functools import partial
from six import string_types, u
-from six.moves import range
from sphinx.ext.napoleon.iterators import modify_iter
from sphinx.locale import _
@@ -25,7 +24,7 @@ from sphinx.util.pycompat import UnicodeMixin
if False:
# For type annotation
- from typing import Any, Callable, Dict, List, Tuple, Union # NOQA
+ from typing import Any, Dict, List, Tuple, Type, Union # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config as SphinxConfig # NOQA
@@ -105,6 +104,10 @@ class GoogleDocstring(UnicodeMixin):
<BLANKLINE>
"""
+
+ _name_rgx = re.compile(r"^\s*(:(?P<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|"
+ r" (?P<name2>[a-zA-Z0-9_.-]+))\s*", re.X)
+
def __init__(self, docstring, config=None, app=None, what='', name='',
obj=None, options=None):
# type: (Union[unicode, List[unicode]], SphinxConfig, Sphinx, unicode, unicode, Any, Any) -> None # NOQA
@@ -120,7 +123,7 @@ class GoogleDocstring(UnicodeMixin):
what = 'class'
elif inspect.ismodule(obj):
what = 'module'
- elif isinstance(obj, collections.Callable): # type: ignore
+ elif isinstance(obj, Callable):
what = 'function'
else:
what = 'object'
@@ -264,8 +267,9 @@ class GoogleDocstring(UnicodeMixin):
# type: () -> Tuple[unicode, List[unicode]]
line = next(self._line_iter)
_type, colon, _desc = self._partition_field_on_colon(line)
- if not colon:
+ if not colon or not _desc:
_type, _desc = _desc, _type
+ _desc += colon
_descs = [_desc] + self._dedent(self._consume_to_end())
_descs = self.__class__(_descs, self._config).lines()
return _type, _descs
@@ -604,6 +608,7 @@ class GoogleDocstring(UnicodeMixin):
lines = []
for _name, _type, _desc in self._consume_fields():
if self._config.napoleon_use_ivar:
+ _name = self._qualify_name(_name, self._obj)
field = ':ivar %s: ' % _name # type: unicode
lines.extend(self._format_block(field, _desc))
if _type:
@@ -697,39 +702,16 @@ class GoogleDocstring(UnicodeMixin):
def _parse_raises_section(self, section):
# type: (unicode) -> List[unicode]
fields = self._consume_fields(parse_type=False, prefer_type=True)
- field_type = ':raises:'
- padding = ' ' * len(field_type)
- multi = len(fields) > 1
lines = [] # type: List[unicode]
for _name, _type, _desc in fields:
+ m = self._name_rgx.match(_type).groupdict() # type: ignore
+ if m['role']:
+ _type = m['name']
+ _type = ' ' + _type if _type else ''
_desc = self._strip_empty(_desc)
- has_desc = any(_desc)
- separator = has_desc and ' -- ' or ''
- if _type:
- has_refs = '`' in _type or ':' in _type
- has_space = any(c in ' \t\n\v\f ' for c in _type)
-
- if not has_refs and not has_space:
- _type = ':exc:`%s`%s' % (_type, separator)
- elif has_desc and has_space:
- _type = '*%s*%s' % (_type, separator)
- else:
- _type = '%s%s' % (_type, separator)
-
- if has_desc:
- field = [_type + _desc[0]] + _desc[1:]
- else:
- field = [_type]
- else:
- field = _desc
- if multi:
- if lines:
- lines.extend(self._format_block(padding + ' * ', field))
- else:
- lines.extend(self._format_block(field_type + ' * ', field))
- else:
- lines.extend(self._format_block(field_type + ' ', field))
- if lines and lines[-1]:
+ _descs = ' ' + '\n '.join(_desc) if any(_desc) else ''
+ lines.append(':raises%s:%s' % (_type, _descs))
+ if lines:
lines.append('')
return lines
@@ -803,6 +785,18 @@ class GoogleDocstring(UnicodeMixin):
colon,
"".join(after_colon).strip())
+ def _qualify_name(self, attr_name, klass):
+ # type: (unicode, Type) -> unicode
+ if klass and '.' not in attr_name:
+ if attr_name.startswith('~'):
+ attr_name = attr_name[1:]
+ try:
+ q = klass.__qualname__
+ except AttributeError:
+ q = klass.__name__
+ return '~%s.%s' % (q, attr_name)
+ return attr_name
+
def _strip_empty(self, lines):
# type: (List[unicode]) -> List[unicode]
if lines:
@@ -976,9 +970,6 @@ class NumpyDocstring(GoogleDocstring):
return True
return False
- _name_rgx = re.compile(r"^\s*(:(?P<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|"
- r" (?P<name2>[a-zA-Z0-9_.-]+))\s*", re.X)
-
def _parse_see_also_section(self, section):
# type: (unicode) -> List[unicode]
lines = self._consume_to_next_section()
diff --git a/sphinx/ext/napoleon/iterators.py b/sphinx/ext/napoleon/iterators.py
index 8926c865c..0ad8038f3 100644
--- a/sphinx/ext/napoleon/iterators.py
+++ b/sphinx/ext/napoleon/iterators.py
@@ -18,7 +18,7 @@ if False:
from typing import Any, Iterable # NOQA
-class peek_iter(object):
+class peek_iter:
"""An iterator object that supports peeking ahead.
Parameters
diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py
index ca944a636..38c34733b 100644
--- a/sphinx/ext/viewcode.py
+++ b/sphinx/ext/viewcode.py
@@ -13,7 +13,7 @@ import traceback
import warnings
from docutils import nodes
-from six import iteritems, text_type
+from six import text_type
import sphinx
from sphinx import addnodes
@@ -163,7 +163,7 @@ def collect_pages(app):
# len(env._viewcode_modules), nonl=1)
for modname, entry in status_iterator(
- sorted(iteritems(env._viewcode_modules)), # type: ignore
+ sorted(env._viewcode_modules.items()), # type: ignore
'highlighting module code... ', "blue",
len(env._viewcode_modules), # type: ignore
app.verbosity, lambda x: x[0]):
@@ -188,7 +188,7 @@ def collect_pages(app):
# the collected tags (HACK: this only works if the tag boundaries are
# properly nested!)
maxindex = len(lines) - 1
- for name, docname in iteritems(used):
+ for name, docname in used.items():
type, start, end = tags[name]
backlink = urito(pagename, docname) + '#' + refname + '.' + name
lines[start] = (
diff --git a/sphinx/extension.py b/sphinx/extension.py
index 732ea327c..4282d5f07 100644
--- a/sphinx/extension.py
+++ b/sphinx/extension.py
@@ -9,8 +9,6 @@
:license: BSD, see LICENSE for details.
"""
-from six import iteritems
-
from sphinx.errors import VersionRequirementError
from sphinx.locale import __
from sphinx.util import logging
@@ -24,7 +22,7 @@ if False:
logger = logging.getLogger(__name__)
-class Extension(object):
+class Extension:
def __init__(self, name, module, **kwargs):
# type: (unicode, Any, Any) -> None
self.name = name
@@ -49,7 +47,7 @@ def verify_needs_extensions(app, config):
if config.needs_extensions is None:
return
- for extname, reqversion in iteritems(config.needs_extensions):
+ for extname, reqversion in config.needs_extensions.items():
extension = app.extensions.get(extname)
if extension is None:
logger.warning(__('The %s extension is required by needs_extensions settings, '
diff --git a/sphinx/highlighting.py b/sphinx/highlighting.py
index 21e3420ba..e61a891a0 100644
--- a/sphinx/highlighting.py
+++ b/sphinx/highlighting.py
@@ -62,7 +62,7 @@ _LATEX_ADD_STYLES = r'''
'''
-class PygmentsBridge(object):
+class PygmentsBridge:
# Set these attributes if you want to have different Pygments formatters
# than the default ones.
html_formatter = HtmlFormatter
diff --git a/sphinx/io.py b/sphinx/io.py
index ad76c2afb..f18a1e95f 100644
--- a/sphinx/io.py
+++ b/sphinx/io.py
@@ -18,7 +18,7 @@ from docutils.parsers.rst import Parser as RSTParser
from docutils.readers import standalone
from docutils.statemachine import StringList, string2lines
from docutils.writers import UnfilteredWriter
-from six import text_type, iteritems
+from six import text_type
from typing import Any, Union # NOQA
from sphinx.deprecation import RemovedInSphinx30Warning
@@ -282,7 +282,7 @@ class FiletypeNotFoundError(Exception):
def get_filetype(source_suffix, filename):
# type: (Dict[unicode, unicode], unicode) -> unicode
- for suffix, filetype in iteritems(source_suffix):
+ for suffix, filetype in source_suffix.items():
if filename.endswith(suffix):
# If default filetype (None), considered as restructuredtext.
return filetype or 'restructuredtext'
diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py
index f19454c27..c3ed86e09 100644
--- a/sphinx/jinja2glue.py
+++ b/sphinx/jinja2glue.py
@@ -98,7 +98,7 @@ def accesskey(context, key):
return ''
-class idgen(object):
+class idgen:
def __init__(self):
# type: () -> None
self.id = 0
diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py
index 7f69d1dca..a09447cb1 100644
--- a/sphinx/locale/__init__.py
+++ b/sphinx/locale/__init__.py
@@ -25,7 +25,7 @@ if False:
from typing import Any, Callable, Dict, Iterator, List, Tuple # NOQA
-class _TranslationProxy(UserString, object):
+class _TranslationProxy(UserString):
"""
Class for proxy strings from gettext translations. This is a helper for the
lazy_* functions from this module.
@@ -36,7 +36,6 @@ class _TranslationProxy(UserString, object):
This inherits from UserString because some docutils versions use UserString
for their Text nodes, which then checks its argument for being either a
basestring or UserString, otherwise calls str() -- not unicode() -- on it.
- This also inherits from object to make the __new__ method work.
"""
__slots__ = ('_func', '_args')
@@ -65,7 +64,7 @@ class _TranslationProxy(UserString, object):
# for the encoding result
def encode(self, encoding=None, errors=None): # type: ignore
- # type: (unicode, unicode) -> str
+ # type: (unicode, unicode) -> bytes
if encoding:
if errors:
return self.data.encode(encoding, errors)
@@ -139,10 +138,6 @@ class _TranslationProxy(UserString, object):
# type: (Any) -> bool
return self.data == other
- def __ne__(self, other):
- # type: (Any) -> bool
- return self.data != other
-
def __gt__(self, other):
# type: (unicode) -> bool
return self.data > other
diff --git a/sphinx/parsers.py b/sphinx/parsers.py
index 5f15c4103..9b1fef702 100644
--- a/sphinx/parsers.py
+++ b/sphinx/parsers.py
@@ -55,8 +55,6 @@ class Parser(docutils.parsers.Parser):
self.app = app
self.config = app.config
self.env = app.env
- self.warn = app.warn
- self.info = app.info
class RSTParser(docutils.parsers.rst.Parser):
diff --git a/sphinx/pycode/__init__.py b/sphinx/pycode/__init__.py
index 8561169b5..3bd49a305 100644
--- a/sphinx/pycode/__init__.py
+++ b/sphinx/pycode/__init__.py
@@ -11,9 +11,10 @@
from __future__ import print_function
import re
+from io import BytesIO
from zipfile import ZipFile
-from six import iteritems, BytesIO, StringIO
+from six import StringIO
from sphinx.errors import PycodeError
from sphinx.pycode.parser import Parser
@@ -24,7 +25,7 @@ if False:
from typing import Any, Dict, IO, List, Tuple # NOQA
-class ModuleAnalyzer(object):
+class ModuleAnalyzer:
# cache for analyzer objects -- caches both by module and file name
cache = {} # type: Dict[Tuple[unicode, unicode], Any]
@@ -111,7 +112,7 @@ class ModuleAnalyzer(object):
parser.parse()
self.attr_docs = {}
- for (scope, comment) in iteritems(parser.comments):
+ for (scope, comment) in parser.comments.items():
if comment:
self.attr_docs[scope] = comment.splitlines() + ['']
else:
diff --git a/sphinx/pycode/parser.py b/sphinx/pycode/parser.py
index 9d464a253..e1aa1f504 100644
--- a/sphinx/pycode/parser.py
+++ b/sphinx/pycode/parser.py
@@ -17,7 +17,7 @@ import tokenize
from token import NAME, NEWLINE, INDENT, DEDENT, NUMBER, OP, STRING
from tokenize import COMMENT, NL
-from six import PY2, text_type
+from six import text_type
if False:
# For type annotation
@@ -59,10 +59,7 @@ def get_lvar_names(node, self=None):
# => TypeError
"""
if self:
- if PY2:
- self_id = self.id # type: ignore
- else:
- self_id = self.arg
+ self_id = self.arg # type: ignore
node_name = node.__class__.__name__
if node_name in ('Index', 'Num', 'Slice', 'Str', 'Subscript'):
@@ -107,7 +104,7 @@ def dedent_docstring(s):
return docstring.lstrip("\r\n").rstrip("\r\n")
-class Token(object):
+class Token:
"""Better token wrapper for tokenize module."""
def __init__(self, kind, value, start, end, source):
@@ -131,10 +128,6 @@ class Token(object):
else:
raise ValueError('Unknown value: %r' % other)
- def __ne__(self, other):
- # type: (Any) -> bool
- return not (self == other)
-
def match(self, *conditions):
# type: (Any) -> bool
return any(self == candidate for candidate in conditions)
@@ -145,7 +138,7 @@ class Token(object):
self.value.strip())
-class TokenProcessor(object):
+class TokenProcessor:
def __init__(self, buffers):
# type: (List[unicode]) -> None
lines = iter(buffers)
@@ -464,7 +457,7 @@ class DefinitionFinder(TokenProcessor):
self.context.pop()
-class Parser(object):
+class Parser:
"""Python source code parser to pick up variable comments.
This is a better wrapper for ``VariableCommentPicker``.
diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py
deleted file mode 100644
index 8cad0640b..000000000
--- a/sphinx/quickstart.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.quickstart
- ~~~~~~~~~~~~~~~~~
-
- This file has moved to :py:mod:`sphinx.cmd.quickstart`.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-import warnings
-
-from sphinx.cmd.quickstart import main as _main
-from sphinx.deprecation import RemovedInSphinx20Warning
-
-if False:
- # For type annotation
- from typing import Any # NOQA
-
-
-def main(*args, **kwargs):
- # type: (Any, Any) -> None
- warnings.warn(
- '`sphinx.quickstart.main()` has moved to `sphinx.cmd.quickstart.'
- 'main()`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- args = args[1:] # skip first argument to adjust arguments (refs: #4615)
- _main(*args, **kwargs)
-
-
-# So program can be started with "python -m sphinx.quickstart ..."
-if __name__ == "__main__":
- warnings.warn(
- '`sphinx.quickstart` has moved to `sphinx.cmd.quickstart`.',
- RemovedInSphinx20Warning,
- stacklevel=2,
- )
- main()
diff --git a/sphinx/registry.py b/sphinx/registry.py
index fc9dce316..763a3ce54 100644
--- a/sphinx/registry.py
+++ b/sphinx/registry.py
@@ -17,7 +17,6 @@ from types import MethodType
from docutils.parsers.rst import Directive
from pkg_resources import iter_entry_points
-from six import iteritems, itervalues
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.domains import ObjType
@@ -54,7 +53,7 @@ EXTENSION_BLACKLIST = {
} # type: Dict[unicode, unicode]
-class SphinxComponentRegistry(object):
+class SphinxComponentRegistry:
def __init__(self):
# type: () -> None
#: special attrgetter for autodoc; class object -> attrgetter
@@ -170,14 +169,14 @@ class SphinxComponentRegistry(object):
def create_domains(self, env):
# type: (BuildEnvironment) -> Iterator[Domain]
- for DomainClass in itervalues(self.domains):
+ for DomainClass in self.domains.values():
domain = DomainClass(env)
# transplant components added by extensions
domain.directives.update(self.domain_directives.get(domain.name, {}))
domain.roles.update(self.domain_roles.get(domain.name, {}))
domain.indices.extend(self.domain_indices.get(domain.name, []))
- for name, objtype in iteritems(self.domain_object_types.get(domain.name, {})):
+ for name, objtype in self.domain_object_types.get(domain.name, {}).items():
domain.add_object_type(name, objtype)
yield domain
@@ -365,7 +364,7 @@ class SphinxComponentRegistry(object):
def add_translation_handlers(self, node, **kwargs):
# type: (nodes.Node, Any) -> None
logger.debug('[app] adding translation_handlers: %r, %r', node, kwargs)
- for builder_name, handlers in iteritems(kwargs):
+ for builder_name, handlers in kwargs.items():
translation_handlers = self.translation_handlers.setdefault(builder_name, {})
try:
visit, depart = handlers # unpack once for assertion
@@ -391,7 +390,7 @@ class SphinxComponentRegistry(object):
# retry with builder.format
handlers = self.translation_handlers.get(builder.format, {})
- for name, (visit, depart) in iteritems(handlers):
+ for name, (visit, depart) in handlers.items():
setattr(translator, 'visit_' + name, MethodType(visit, translator))
if depart:
setattr(translator, 'depart_' + name, MethodType(depart, translator))
@@ -512,7 +511,7 @@ class SphinxComponentRegistry(object):
def merge_source_suffix(app, config):
# type: (Sphinx, Config) -> None
"""Merge source_suffix which specified by user and added by extensions."""
- for suffix, filetype in iteritems(app.registry.source_suffix):
+ for suffix, filetype in app.registry.source_suffix.items():
if suffix not in app.config.source_suffix:
app.config.source_suffix[suffix] = filetype
elif app.config.source_suffix[suffix] is None:
diff --git a/sphinx/roles.py b/sphinx/roles.py
index b2a540122..fb01a876b 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -12,7 +12,6 @@
import re
from docutils import nodes, utils
-from six import iteritems
from sphinx import addnodes
from sphinx.errors import SphinxError
@@ -45,7 +44,7 @@ generic_docroles = {
# -- generic cross-reference role ----------------------------------------------
-class XRefRole(object):
+class XRefRole:
"""
A generic cross-referencing role. To create a callable that can be used as
a role function, create an instance of this class.
@@ -403,12 +402,12 @@ def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
from docutils.parsers.rst import roles
- for rolename, nodeclass in iteritems(generic_docroles):
+ for rolename, nodeclass in generic_docroles.items():
generic = roles.GenericRole(rolename, nodeclass)
role = roles.CustomRole(rolename, generic, {'classes': [rolename]})
roles.register_local_role(rolename, role)
- for rolename, func in iteritems(specific_docroles):
+ for rolename, func in specific_docroles.items():
roles.register_local_role(rolename, func)
return {
diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py
index 3da6c4ba5..4ae96fb57 100644
--- a/sphinx/search/__init__.py
+++ b/sphinx/search/__init__.py
@@ -8,11 +8,11 @@
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import pickle
import re
from os import path
-from six import iteritems, itervalues, text_type, string_types
-from six.moves import cPickle as pickle
+from six import text_type, string_types
from docutils.nodes import raw, comment, title, Text, NodeVisitor, SkipNode
@@ -28,7 +28,7 @@ if False:
from sphinx.environment import BuildEnvironment # NOQA
-class SearchLanguage(object):
+class SearchLanguage:
"""
This class is the base class for search natural language preprocessors. If
you want to add support for a new language, you should override the methods
@@ -155,7 +155,7 @@ languages = {
} # type: Dict[unicode, Any]
-class _JavaScriptIndex(object):
+class _JavaScriptIndex:
"""
The search index as javascript file that calls a function
on the documentation search object to register the index.
@@ -236,7 +236,7 @@ class WordCollector(NodeVisitor):
self.found_words.extend(keywords)
-class IndexBuilder(object):
+class IndexBuilder:
"""
Helper class that creates a searchindex based on the doctrees
passed to the `feed` method.
@@ -305,7 +305,7 @@ class IndexBuilder(object):
def load_terms(mapping):
# type: (Dict[unicode, Any]) -> Dict[unicode, Set[unicode]]
rv = {}
- for k, v in iteritems(mapping):
+ for k, v in mapping.items():
if isinstance(v, int):
rv[k] = set([index2fn[v]])
else:
@@ -328,7 +328,7 @@ class IndexBuilder(object):
rv = {} # type: Dict[unicode, Dict[unicode, Tuple[int, int, int, unicode]]]
otypes = self._objtypes
onames = self._objnames
- for domainname, domain in sorted(iteritems(self.env.domains)):
+ for domainname, domain in sorted(self.env.domains.items()):
for fullname, dispname, type, docname, anchor, prio in \
sorted(domain.get_objects()):
if docname not in fn2index:
@@ -364,7 +364,7 @@ class IndexBuilder(object):
# type: (Dict) -> Tuple[Dict[unicode, List[unicode]], Dict[unicode, List[unicode]]]
rvs = {}, {} # type: Tuple[Dict[unicode, List[unicode]], Dict[unicode, List[unicode]]]
for rv, mapping in zip(rvs, (self._mapping, self._title_mapping)):
- for k, v in iteritems(mapping):
+ for k, v in mapping.items():
if len(v) == 1:
fn, = v
if fn in fn2index:
@@ -383,7 +383,7 @@ class IndexBuilder(object):
objects = self.get_objects(fn2index) # populates _objtypes
objtypes = dict((v, k[0] + ':' + k[1])
- for (k, v) in iteritems(self._objtypes))
+ for (k, v) in self._objtypes.items())
objnames = self._objnames
return dict(docnames=docnames, filenames=filenames, titles=titles, terms=terms,
objects=objects, objtypes=objtypes, objnames=objnames,
@@ -404,9 +404,9 @@ class IndexBuilder(object):
new_filenames[docname] = self._filenames[docname]
self._titles = new_titles
self._filenames = new_filenames
- for wordnames in itervalues(self._mapping):
+ for wordnames in self._mapping.values():
wordnames.intersection_update(docnames)
- for wordnames in itervalues(self._title_mapping):
+ for wordnames in self._title_mapping.values():
wordnames.intersection_update(docnames)
def feed(self, docname, filename, title, doctree):
diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py
index a48a0df69..f28013b0b 100644
--- a/sphinx/search/ja.py
+++ b/sphinx/search/ja.py
@@ -22,8 +22,6 @@ import re
import sys
import warnings
-from six import iteritems, PY3
-
try:
import MeCab
native_module = True
@@ -46,7 +44,7 @@ if False:
from typing import Any, Dict, List # NOQA
-class BaseSplitter(object):
+class BaseSplitter:
def __init__(self, options):
# type: (Dict) -> None
@@ -77,16 +75,12 @@ class MecabSplitter(BaseSplitter):
def split(self, input):
# type: (unicode) -> List[unicode]
- input2 = input if PY3 else input.encode(self.dict_encode)
if native_module:
- result = self.native.parse(input2)
+ result = self.native.parse(input)
else:
result = self.ctypes_libmecab.mecab_sparse_tostr(
self.ctypes_mecab, input.encode(self.dict_encode))
- if PY3:
- return result.split(' ')
- else:
- return result.decode(self.dict_encode).split(' ')
+ return result.split(' ')
def init_native(self, options):
# type: (Dict) -> None
@@ -162,14 +156,14 @@ class JanomeSplitter(BaseSplitter):
class DefaultSplitter(BaseSplitter):
- patterns_ = dict([(re.compile(pattern), value) for pattern, value in iteritems({
+ patterns_ = dict([(re.compile(pattern), value) for pattern, value in {
u'[一二三四五六七八九十百千万億兆]': u'M',
u'[一-龠々〆ヵヶ]': u'H',
u'[ぁ-ん]': u'I',
u'[ァ-ヴーア-ン゙ー]': u'K',
u'[a-zA-Za-zA-Z]': u'A',
u'[0-90-9]': u'N',
- })])
+ }.items()])
BIAS__ = -332
BC1__ = {u'HH': 6, u'II': 2461, u'KH': 406, u'OH': -1378}
BC2__ = {u'AA': -3267, u'AI': 2744, u'AN': -878, u'HH': -4070, u'HM': -1711,
@@ -434,7 +428,7 @@ class DefaultSplitter(BaseSplitter):
# ctype_
def ctype_(self, char):
# type: (unicode) -> unicode
- for pattern, value in iteritems(self.patterns_):
+ for pattern, value in self.patterns_.items():
if pattern.match(char):
return value
return u'O'
diff --git a/sphinx/templates/latex/latex.tex_t b/sphinx/templates/latex/latex.tex_t
index 633525551..2c49c3179 100644
--- a/sphinx/templates/latex/latex.tex_t
+++ b/sphinx/templates/latex/latex.tex_t
@@ -36,7 +36,7 @@
<%= hyperref %>
<%= contentsname %>
<%= numfig_format %>
-<%= translatablestrings %>
+\input{sphinxmessages.sty}
<%= pageautorefname %>
<%= tocdepth %>
<%= secnumdepth %>
@@ -47,7 +47,11 @@
\release{<%= release %>}
\author{<%= author %>}
\newcommand{\sphinxlogo}{<%= logo %>}
-\renewcommand{\releasename}{<%= releasename %>}
+<%- if releasename or release %>
+\renewcommand{\releasename}{<%= releasename or _('Release') | e %>}
+<%- else %>
+\renewcommand{\releasename}{}
+<%- endif %>
<%= makeindex %>
\begin{document}
<%= shorthandoff %>
@@ -59,6 +63,6 @@
<%= body %>
<%= atendofbody %>
<%= indices %>
-\renewcommand{\indexname}{<%= indexname %>}
+\renewcommand{\indexname}{<%= _('Index') | e %>}
<%= printindex %>
\end{document}
diff --git a/sphinx/templates/latex/sphinxmessages.sty_t b/sphinx/templates/latex/sphinxmessages.sty_t
new file mode 100644
index 000000000..2413a1725
--- /dev/null
+++ b/sphinx/templates/latex/sphinxmessages.sty_t
@@ -0,0 +1,10 @@
+%
+% sphinxmessages.sty
+%
+% message resources for Sphinx
+%
+\renewcommand{\literalblockcontinuedname}{<%= _('continued from previous page') | e %>}
+\renewcommand{\literalblockcontinuesname}{<%= _('continues on next page') | e %>}
+\renewcommand{\sphinxnonalphabeticalgroupname}{<%= _('Non-alphabetical') | e %>}
+\renewcommand{\sphinxsymbolsname}{<%= _('Symbols') | e %>}
+\renewcommand{\sphinxnumbersname}{<%= _('Numbers') | e %>}
diff --git a/sphinx/templates/quickstart/conf.py_t b/sphinx/templates/quickstart/conf.py_t
index 6128c0235..a29a6eb71 100644
--- a/sphinx/templates/quickstart/conf.py_t
+++ b/sphinx/templates/quickstart/conf.py_t
@@ -62,9 +62,11 @@ templates_path = ['{{ dot }}templates']
# source_suffix = ['.rst', '.md']
source_suffix = '{{ suffix }}'
+{% if master_doc != 'index' -%}
# The master toctree document.
master_doc = '{{ master_str }}'
+{% endif -%}
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py
index fcf1028fd..4ea634b10 100644
--- a/sphinx/testing/fixtures.py
+++ b/sphinx/testing/fixtures.py
@@ -173,7 +173,7 @@ def make_app(test_params, monkeypatch):
app_.cleanup()
-class SharedResult(object):
+class SharedResult:
cache = {} # type: Dict[str, Dict[str, str]]
def store(self, key, app_):
diff --git a/sphinx/testing/path.py b/sphinx/testing/path.py
index 1c9781dea..78c3cb7bc 100644
--- a/sphinx/testing/path.py
+++ b/sphinx/testing/path.py
@@ -9,9 +9,8 @@
import os
import shutil
import sys
-from io import open
-from six import PY2, text_type
+from six import text_type
if False:
# For type annotation
@@ -25,13 +24,6 @@ class path(text_type):
"""
Represents a path which behaves like a string.
"""
- if PY2:
- def __new__(cls, s, encoding=FILESYSTEMENCODING, errors='strict'):
- # type: (unicode, unicode, unicode) -> path
- if isinstance(s, str):
- s = s.decode(encoding, errors)
- return text_type.__new__(cls, s) # type: ignore
- return text_type.__new__(cls, s) # type: ignore
@property
def parent(self):
@@ -161,7 +153,7 @@ class path(text_type):
"""
if isinstance(text, bytes):
text = text.decode(encoding)
- with open(self, 'w', encoding=encoding, **kwargs) as f:
+ with open(self, 'w', encoding=encoding, **kwargs) as f: # type: ignore
f.write(text)
def text(self, encoding='utf-8', **kwargs):
@@ -169,8 +161,7 @@ class path(text_type):
"""
Returns the text in the file.
"""
- mode = 'rU' if PY2 else 'r'
- with open(self, mode=mode, encoding=encoding, **kwargs) as f:
+ with open(self, mode='r', encoding=encoding, **kwargs) as f: # type: ignore
return f.read()
def bytes(self):
diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py
index 4c18d1c0c..cd2073aaa 100644
--- a/sphinx/testing/util.py
+++ b/sphinx/testing/util.py
@@ -20,7 +20,7 @@ from six import string_types
from sphinx import application, locale
from sphinx.builders.latex import LaTeXBuilder
-from sphinx.ext.autodoc import AutoDirective
+from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.pycode import ModuleAnalyzer
from sphinx.testing.path import path
from sphinx.util.osutil import relpath
@@ -93,7 +93,7 @@ def etree_parse(path):
return ElementTree.parse(path) # type: ignore
-class Struct(object):
+class Struct:
def __init__(self, **kwds):
# type: (Any) -> None
self.__dict__.update(kwds)
@@ -146,7 +146,6 @@ class SphinxTestApp(application.Sphinx):
def cleanup(self, doctrees=False):
# type: (bool) -> None
- AutoDirective._registry.clear()
ModuleAnalyzer.cache.clear()
LaTeXBuilder.usepackages = []
locale.translators.clear()
@@ -165,7 +164,7 @@ class SphinxTestApp(application.Sphinx):
return '<%s buildername=%r>' % (self.__class__.__name__, self.builder.name)
-class SphinxTestAppWrapperForSkipBuilding(object):
+class SphinxTestAppWrapperForSkipBuilding:
"""
This class is a wrapper for SphinxTestApp to speed up the test by skipping
`app.build` process if it is already built and there is even one output
@@ -193,6 +192,8 @@ _unicode_literals_re = re.compile(r'u(".*?")|u(\'.*?\')')
def remove_unicode_literals(s):
# type: (unicode) -> unicode
+ warnings.warn('remove_unicode_literals() is deprecated.',
+ RemovedInSphinx40Warning)
return _unicode_literals_re.sub(lambda x: x.group(1) or x.group(2), s)
diff --git a/sphinx/themes/agogo/layout.html b/sphinx/themes/agogo/layout.html
index f2c880537..f50a2d78f 100644
--- a/sphinx/themes/agogo/layout.html
+++ b/sphinx/themes/agogo/layout.html
@@ -52,8 +52,6 @@
<form class="search" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" />
<input type="submit" value="{{ _('Go') }}" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
</form>
</div>
{%- endblock %}
diff --git a/sphinx/themes/basic/opensearch.xml b/sphinx/themes/basic/opensearch.xml
index 03875be49..a750b3041 100644
--- a/sphinx/themes/basic/opensearch.xml
+++ b/sphinx/themes/basic/opensearch.xml
@@ -4,7 +4,7 @@
<Description>{% trans docstitle=docstitle|e %}Search {{ docstitle }}{% endtrans %}</Description>
<InputEncoding>utf-8</InputEncoding>
<Url type="text/html" method="get"
- template="{{ use_opensearch }}/{{ pathto('search') }}?q={searchTerms}&amp;check_keywords=yes&amp;area=default"/>
+ template="{{ use_opensearch }}/{{ pathto('search') }}?q={searchTerms}"/>
<LongName>{{ docstitle|e }}</LongName>
{% block extra %} {# Put e.g. an <Image> element here. #} {% endblock %}
</OpenSearchDescription>
diff --git a/sphinx/themes/basic/searchbox.html b/sphinx/themes/basic/searchbox.html
index 506877410..6feaa93e0 100644
--- a/sphinx/themes/basic/searchbox.html
+++ b/sphinx/themes/basic/searchbox.html
@@ -14,8 +14,6 @@
<form class="search" action="{{ pathto('search') }}" method="get">
<input type="text" name="q" />
<input type="submit" value="{{ _('Go') }}" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
</form>
</div>
</div>
diff --git a/sphinx/themes/basic/static/searchtools.js b/sphinx/themes/basic/static/searchtools.js
index 7473859b2..f5183ba7d 100644
--- a/sphinx/themes/basic/static/searchtools.js
+++ b/sphinx/themes/basic/static/searchtools.js
@@ -56,6 +56,14 @@ var Search = {
_queued_query : null,
_pulse_status : -1,
+ htmlToText : function(htmlString) {
+ var htmlElement = document.createElement('span');
+ htmlElement.innerHTML = htmlString;
+ $(htmlElement).find('.headerlink').remove();
+ docContent = $(htmlElement).find('[role=main]')[0];
+ return docContent.textContent || docContent.innerText;
+ },
+
init : function() {
var params = $.getQueryParameters();
if (params.q) {
@@ -260,11 +268,7 @@ var Search = {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
- var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX;
- if (suffix === undefined) {
- suffix = '.txt';
- }
- $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix),
+ $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX,
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
@@ -457,7 +461,8 @@ var Search = {
* words. the first one is used to find the occurrence, the
* latter for highlighting it.
*/
- makeSearchSummary : function(text, keywords, hlwords) {
+ makeSearchSummary : function(htmlText, keywords, hlwords) {
+ var text = Search.htmlToText(htmlText);
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
diff --git a/sphinx/theming.py b/sphinx/theming.py
index 944c446c3..6687dd27b 100644
--- a/sphinx/theming.py
+++ b/sphinx/theming.py
@@ -9,19 +9,16 @@
:license: BSD, see LICENSE for details.
"""
+import configparser
import os
import shutil
import tempfile
-import warnings
from os import path
from zipfile import ZipFile
import pkg_resources
-from six import string_types, iteritems
-from six.moves import configparser
from sphinx import package_dir
-from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.errors import ThemeError
from sphinx.locale import __
from sphinx.util import logging
@@ -53,7 +50,7 @@ def extract_zip(filename, targetdir):
fp.write(archive.read(name))
-class Theme(object):
+class Theme:
"""A Theme is a set of HTML templates and configurations.
This class supports both theme directory and theme archive (zipped theme)."""
@@ -75,7 +72,7 @@ class Theme(object):
extract_zip(theme_path, self.themedir)
self.config = configparser.RawConfigParser()
- self.config.read(path.join(self.themedir, THEMECONF)) # type: ignore
+ self.config.read(path.join(self.themedir, THEMECONF))
try:
inherit = self.config.get('theme', 'inherit')
@@ -107,7 +104,7 @@ class Theme(object):
base theme chain.
"""
try:
- return self.config.get(section, name) # type: ignore
+ return self.config.get(section, name)
except (configparser.NoOptionError, configparser.NoSectionError):
if self.base:
return self.base.get_config(section, name, default)
@@ -131,7 +128,7 @@ class Theme(object):
except configparser.NoSectionError:
pass
- for option, value in iteritems(overrides):
+ for option, value in overrides.items():
if option not in options:
logger.warning(__('unsupported theme option %r given') % option)
else:
@@ -161,7 +158,7 @@ def is_archived_theme(filename):
return False
-class HTMLThemeFactory(object):
+class HTMLThemeFactory:
"""A factory class for HTML Themes."""
def __init__(self, app):
@@ -176,7 +173,7 @@ class HTMLThemeFactory(object):
# type: () -> None
"""Load built-in themes."""
themes = self.find_themes(path.join(package_dir, 'themes'))
- for name, theme in iteritems(themes):
+ for name, theme in themes.items():
self.themes[name] = theme
def load_additional_themes(self, theme_paths):
@@ -185,7 +182,7 @@ class HTMLThemeFactory(object):
for theme_path in theme_paths:
abs_theme_path = path.abspath(path.join(self.app.confdir, theme_path))
themes = self.find_themes(abs_theme_path)
- for name, theme in iteritems(themes):
+ for name, theme in themes.items():
self.themes[name] = theme
def load_extra_theme(self, name):
@@ -229,25 +226,6 @@ class HTMLThemeFactory(object):
except StopIteration:
pass
- # look up for old styled entry_points
- for entry_point in pkg_resources.iter_entry_points('sphinx_themes'):
- target = entry_point.load()
- if callable(target):
- themedir = target()
- if not isinstance(themedir, string_types):
- logger.warning(__('Theme extension %r does not respond correctly.') %
- entry_point.module_name)
- else:
- themedir = target
-
- themes = self.find_themes(themedir)
- for entry, theme in iteritems(themes):
- if name == entry:
- warnings.warn('``sphinx_themes`` entry point is now deprecated. '
- 'Please use ``sphinx.html_themes`` instead.',
- RemovedInSphinx20Warning)
- self.themes[name] = theme
-
def find_themes(self, theme_path):
# type: (unicode) -> Dict[unicode, unicode]
"""Search themes from specified directory."""
diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py
index f49e27df3..727a12be6 100644
--- a/sphinx/transforms/i18n.py
+++ b/sphinx/transforms/i18n.py
@@ -10,6 +10,7 @@
"""
from os import path
+from typing import Any
from docutils import nodes
from docutils.io import StringInput
@@ -22,14 +23,14 @@ from sphinx.transforms import SphinxTransform
from sphinx.util import split_index_msg, logging
from sphinx.util.i18n import find_catalog
from sphinx.util.nodes import (
- LITERAL_TYPE_NODES, IMAGE_TYPE_NODES,
+ LITERAL_TYPE_NODES, IMAGE_TYPE_NODES, NodeMatcher,
extract_messages, is_pending_meta, traverse_translatable_index,
)
from sphinx.util.pycompat import indent
if False:
# For type annotation
- from typing import Any, Dict, List, Tuple # NOQA
+ from typing import Dict, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA
@@ -183,11 +184,8 @@ class Locale(SphinxTransform):
self.document.note_implicit_target(section_node)
# replace target's refname to new target name
- def is_named_target(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.target) and \
- node.get('refname') == old_name
- for old_target in self.document.traverse(is_named_target):
+ matcher = NodeMatcher(nodes.target, refname=old_name)
+ for old_target in self.document.traverse(matcher):
old_target['refname'] = new_name
processed = True
@@ -276,16 +274,14 @@ class Locale(SphinxTransform):
continue # skip
# auto-numbered foot note reference should use original 'ids'.
- def is_autofootnote_ref(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.footnote_reference) and node.get('auto')
-
def list_replace_or_append(lst, old, new):
# type: (List, Any, Any) -> None
if old in lst:
lst[lst.index(old)] = new
else:
lst.append(new)
+
+ is_autofootnote_ref = NodeMatcher(nodes.footnote_reference, auto=Any)
old_foot_refs = node.traverse(is_autofootnote_ref)
new_foot_refs = patch.traverse(is_autofootnote_ref)
if len(old_foot_refs) != len(new_foot_refs):
@@ -328,10 +324,7 @@ class Locale(SphinxTransform):
# * reference target ".. _Python: ..." is not translatable.
# * use translated refname for section refname.
# * inline reference "`Python <...>`_" has no 'refname'.
- def is_refnamed_ref(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.reference) and \
- 'refname' in node
+ is_refnamed_ref = NodeMatcher(nodes.reference, refname=Any)
old_refs = node.traverse(is_refnamed_ref)
new_refs = patch.traverse(is_refnamed_ref)
if len(old_refs) != len(new_refs):
@@ -358,10 +351,7 @@ class Locale(SphinxTransform):
self.document.note_refname(new)
# refnamed footnote should use original 'ids'.
- def is_refnamed_footnote_ref(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.footnote_reference) and \
- 'refname' in node
+ is_refnamed_footnote_ref = NodeMatcher(nodes.footnote_reference, refname=Any)
old_foot_refs = node.traverse(is_refnamed_footnote_ref)
new_foot_refs = patch.traverse(is_refnamed_footnote_ref)
refname_ids_map = {}
@@ -380,10 +370,7 @@ class Locale(SphinxTransform):
new["ids"] = refname_ids_map[refname]
# citation should use original 'ids'.
- def is_citation_ref(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.citation_reference) and \
- 'refname' in node
+ is_citation_ref = NodeMatcher(nodes.citation_reference, refname=Any)
old_cite_refs = node.traverse(is_citation_ref)
new_cite_refs = patch.traverse(is_citation_ref)
refname_ids_map = {}
@@ -474,10 +461,7 @@ class Locale(SphinxTransform):
node['entries'] = new_entries
# remove translated attribute that is used for avoiding double translation.
- def has_translatable(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, nodes.Element) and 'translated' in node
- for node in self.document.traverse(has_translatable):
+ for node in self.document.traverse(NodeMatcher(translated=Any)):
node.delattr('translated')
@@ -492,7 +476,8 @@ class RemoveTranslatableInline(SphinxTransform):
from sphinx.builders.gettext import MessageCatalogBuilder
if isinstance(self.app.builder, MessageCatalogBuilder):
return
- for inline in self.document.traverse(nodes.inline):
- if 'translatable' in inline:
- inline.parent.remove(inline)
- inline.parent += inline.children
+
+ matcher = NodeMatcher(nodes.inline, translatable=Any)
+ for inline in self.document.traverse(matcher):
+ inline.parent.remove(inline)
+ inline.parent += inline.children
diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py
index 6e53fec1d..a5cb897d9 100644
--- a/sphinx/transforms/post_transforms/__init__.py
+++ b/sphinx/transforms/post_transforms/__init__.py
@@ -9,13 +9,9 @@
:license: BSD, see LICENSE for details.
"""
-import warnings
-
from docutils import nodes
-from docutils.utils import get_source_line
from sphinx import addnodes
-from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.environment import NoUri
from sphinx.locale import __
from sphinx.transforms import SphinxTransform
@@ -32,35 +28,6 @@ if False:
logger = logging.getLogger(__name__)
-class DocReferenceMigrator(SphinxTransform):
- """Migrate :doc: reference to std domain."""
-
- default_priority = 5 # before ReferencesResolver
-
- def apply(self):
- # type: () -> None
- for node in self.document.traverse(addnodes.pending_xref):
- if node.get('reftype') == 'doc' and node.get('refdomain') is None:
- source, line = get_source_line(node)
- if source and line:
- location = "%s:%s" % (source, line)
- elif source:
- location = "%s:" % source
- elif line:
- location = "<unknown>:%s" % line
- else:
- location = None
-
- message = ('Invalid pendig_xref node detected. '
- ':doc: reference should have refdomain=std attribute.')
- if location:
- warnings.warn("%s: %s" % (location, message),
- RemovedInSphinx20Warning)
- else:
- warnings.warn(message, RemovedInSphinx20Warning)
- node['refdomain'] = 'std'
-
-
class ReferencesResolver(SphinxTransform):
"""
Resolves cross-references on doctrees.
@@ -191,7 +158,6 @@ class OnlyNodeTransform(SphinxTransform):
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
- app.add_post_transform(DocReferenceMigrator)
app.add_post_transform(ReferencesResolver)
app.add_post_transform(OnlyNodeTransform)
diff --git a/sphinx/transforms/references.py b/sphinx/transforms/references.py
index 40efbf615..bb7c51da7 100644
--- a/sphinx/transforms/references.py
+++ b/sphinx/transforms/references.py
@@ -11,7 +11,6 @@
from docutils import nodes
from docutils.transforms.references import Substitutions
-from six import itervalues
from sphinx.transforms import SphinxTransform
@@ -34,5 +33,5 @@ class SphinxDomains(SphinxTransform):
def apply(self):
# type: () -> None
- for domain in itervalues(self.env.domains):
+ for domain in self.env.domains.values():
domain.process_doc(self.env, self.env.docname, self.document)
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index a9d112a9f..8bb18debd 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -27,8 +27,7 @@ from os import path
from time import mktime, strptime
from docutils.utils import relative_path
-from six import text_type, binary_type, itervalues
-from six.moves import range
+from six import text_type, binary_type
from six.moves.urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl, urlencode
from sphinx.deprecation import RemovedInSphinx30Warning
@@ -88,7 +87,7 @@ def get_matching_files(dirname, exclude_matchers=()):
dirname = path.normpath(path.abspath(dirname))
dirlen = len(dirname) + 1 # exclude final os.path.sep
- for root, dirs, files in walk(dirname, followlinks=True):
+ for root, dirs, files in os.walk(dirname, followlinks=True):
relativeroot = root[dirlen:]
qdirs = enumerate(path_stabilize(path.join(relativeroot, dn))
@@ -267,7 +266,7 @@ def save_traceback(app):
jinja2.__version__, # type: ignore
last_msgs)).encode('utf-8'))
if app is not None:
- for ext in itervalues(app.extensions):
+ for ext in app.extensions.values():
modfile = getattr(ext.module, '__file__', 'unknown')
if isinstance(modfile, bytes):
modfile = modfile.decode(fs_encoding, 'replace')
@@ -404,7 +403,7 @@ def detect_encoding(readline):
# Low-level utility functions and classes.
-class Tee(object):
+class Tee:
"""
File-like object writing to two streams.
"""
@@ -536,7 +535,7 @@ def format_exception_cut_frames(x=1):
return ''.join(res)
-class PeekableIterator(object):
+class PeekableIterator:
"""
An iterator which wraps any iterable and makes it possible to peek to see
what's the next item.
@@ -677,8 +676,7 @@ def xmlname_checker():
[u'\u2C00', u'\u2FEF'], [u'\u3001', u'\uD7FF'], [u'\uF900', u'\uFDCF'],
[u'\uFDF0', u'\uFFFD']]
- if sys.version_info.major == 3:
- name_start_chars.append([u'\U00010000', u'\U000EFFFF'])
+ name_start_chars.append([u'\U00010000', u'\U000EFFFF'])
name_chars = [
u"\\-", u"\\.", [u'0', u'9'], u'\u00B7', [u'\u0300', u'\u036F'],
diff --git a/sphinx/util/build_phase.py b/sphinx/util/build_phase.py
index e5a53551c..48e75675d 100644
--- a/sphinx/util/build_phase.py
+++ b/sphinx/util/build_phase.py
@@ -9,10 +9,7 @@
:license: BSD, see LICENSE for details.
"""
-try:
- from enum import IntEnum
-except ImportError: # py27
- IntEnum = object # type: ignore
+from enum import IntEnum
class BuildPhase(IntEnum):
diff --git a/sphinx/util/compat.py b/sphinx/util/compat.py
index 43ced1f5e..1f3b0f445 100644
--- a/sphinx/util/compat.py
+++ b/sphinx/util/compat.py
@@ -14,9 +14,12 @@ from __future__ import absolute_import
import sys
import warnings
-from six import string_types, iteritems
+from docutils.utils import get_source_line
+from six import string_types
-from sphinx.deprecation import RemovedInSphinx30Warning
+from sphinx import addnodes
+from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning
+from sphinx.transforms import SphinxTransform
from sphinx.util import import_object
if False:
@@ -32,7 +35,7 @@ def deprecate_source_parsers(app, config):
warnings.warn('The config variable "source_parsers" is deprecated. '
'Please use app.add_source_parser() API instead.',
RemovedInSphinx30Warning)
- for suffix, parser in iteritems(config.source_parsers):
+ for suffix, parser in config.source_parsers.items():
if isinstance(parser, string_types):
parser = import_object(parser, 'source parser') # type: ignore
app.add_source_parser(suffix, parser)
@@ -52,8 +55,23 @@ def register_application_for_autosummary(app):
autosummary._app = app
+class IndexEntriesMigrator(SphinxTransform):
+ """Migrating indexentries from old style (4columns) to new style (5columns)."""
+ default_priority = 700
+
+ def apply(self):
+ for node in self.document.traverse(addnodes.index):
+ for entries in node['entries']:
+ if len(entries) == 4:
+ source, line = get_source_line(node)
+ warnings.warn('An old styled index node found: %r at (%s:%s)' %
+ (node, source, line), RemovedInSphinx40Warning)
+ entries.extend([None])
+
+
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
+ app.add_transform(IndexEntriesMigrator)
app.connect('config-inited', deprecate_source_parsers)
app.connect('builder-inited', register_application_for_autosummary)
diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py
index 94968e148..d0899130e 100644
--- a/sphinx/util/docfields.py
+++ b/sphinx/util/docfields.py
@@ -36,7 +36,7 @@ def _is_single_paragraph(node):
return False
-class Field(object):
+class Field:
"""A doc field that is never grouped. It can have an argument or not, the
argument can be linked using a specified *rolename*. Field should be used
for doc fields that usually don't occur more than once.
@@ -235,7 +235,7 @@ class TypedField(GroupedField):
return nodes.field('', fieldname, fieldbody)
-class DocFieldTransformer(object):
+class DocFieldTransformer:
"""
Transforms field lists in "doc field" syntax into better-looking
equivalents, using the field type definitions given on a domain.
diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py
index 874eb6baf..9ce4087ac 100644
--- a/sphinx/util/docutils.py
+++ b/sphinx/util/docutils.py
@@ -10,7 +10,6 @@
"""
from __future__ import absolute_import
-import codecs
import os
import re
import types
@@ -148,7 +147,7 @@ class ElementLookupError(Exception):
pass
-class sphinx_domains(object):
+class sphinx_domains:
"""Monkey-patch directive and role dispatch, so that domain-specific
markup takes precedence.
"""
@@ -223,7 +222,7 @@ class sphinx_domains(object):
return self.role_func(name, lang_module, lineno, reporter)
-class WarningStream(object):
+class WarningStream:
def write(self, text):
# type: (unicode) -> None
matched = report_re.search(text)
@@ -314,7 +313,7 @@ class SphinxFileOutput(FileOutput):
# type: (unicode) -> unicode
if (self.destination_path and self.autoclose and 'b' not in self.mode and
self.overwrite_if_changed and os.path.exists(self.destination_path)):
- with codecs.open(self.destination_path, encoding=self.encoding) as f:
+ with open(self.destination_path, encoding=self.encoding) as f: # type: ignore
# skip writing: content not changed
if f.read() == data:
return data
diff --git a/sphinx/util/fileutil.py b/sphinx/util/fileutil.py
index fcbc8abe6..7dc376807 100644
--- a/sphinx/util/fileutil.py
+++ b/sphinx/util/fileutil.py
@@ -10,13 +10,12 @@
"""
from __future__ import absolute_import
-import codecs
import os
import posixpath
from docutils.utils import relative_path
-from sphinx.util.osutil import copyfile, ensuredir, walk
+from sphinx.util.osutil import copyfile, ensuredir
if False:
# For type annotation
@@ -44,15 +43,15 @@ def copy_asset_file(source, destination, context=None, renderer=None):
# Use source filename if destination points a directory
destination = os.path.join(destination, os.path.basename(source))
- if source.lower().endswith('_t') and context:
+ if source.lower().endswith('_t') and context is not None:
if renderer is None:
from sphinx.util.template import SphinxRenderer
renderer = SphinxRenderer()
- with codecs.open(source, 'r', encoding='utf-8') as fsrc: # type: ignore
+ with open(source, 'r', encoding='utf-8') as fsrc: # type: ignore
if destination.lower().endswith('_t'):
destination = destination[:-2]
- with codecs.open(destination, 'w', encoding='utf-8') as fdst: # type: ignore
+ with open(destination, 'w', encoding='utf-8') as fdst: # type: ignore
fdst.write(renderer.render_string(fsrc.read(), context))
else:
copyfile(source, destination)
@@ -83,7 +82,7 @@ def copy_asset(source, destination, excluded=lambda path: False, context=None, r
copy_asset_file(source, destination, context, renderer)
return
- for root, dirs, files in walk(source, followlinks=True):
+ for root, dirs, files in os.walk(source, followlinks=True):
reldir = relative_path(source, root)
for dir in dirs[:]:
if excluded(posixpath.join(reldir, dir)):
diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py
index edaebebda..4e25115a7 100644
--- a/sphinx/util/i18n.py
+++ b/sphinx/util/i18n.py
@@ -9,7 +9,6 @@
:license: BSD, see LICENSE for details.
"""
import gettext
-import io
import os
import re
import warnings
@@ -26,7 +25,7 @@ from sphinx.errors import SphinxError
from sphinx.locale import __
from sphinx.util import logging
from sphinx.util.matching import Matcher
-from sphinx.util.osutil import SEP, relpath, walk
+from sphinx.util.osutil import SEP, relpath
logger = logging.getLogger(__name__)
@@ -69,14 +68,14 @@ class CatalogInfo(LocaleFileInfoBase):
def write_mo(self, locale):
# type: (unicode) -> None
- with io.open(self.po_path, 'rt', encoding=self.charset) as file_po:
+ with open(self.po_path, 'rt', encoding=self.charset) as file_po: # type: ignore
try:
po = read_po(file_po, locale)
except Exception as exc:
logger.warning(__('reading error: %s, %s'), self.po_path, exc)
return
- with io.open(self.mo_path, 'wb') as file_mo:
+ with open(self.mo_path, 'wb') as file_mo:
try:
write_mo(file_mo, po)
except Exception as exc:
@@ -140,7 +139,7 @@ def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact
if not path.exists(base_dir):
continue # locale path is not found
- for dirpath, dirnames, filenames in walk(base_dir, followlinks=True):
+ for dirpath, dirnames, filenames in os.walk(base_dir, followlinks=True):
filenames = [f for f in filenames if f.endswith('.po')]
for filename in filenames:
if excluded(path.join(relpath(dirpath, base_dir), filename)):
diff --git a/sphinx/util/images.py b/sphinx/util/images.py
index d5e0db2d7..85fbf17f1 100644
--- a/sphinx/util/images.py
+++ b/sphinx/util/images.py
@@ -14,11 +14,12 @@ import base64
import imghdr
import warnings
from collections import OrderedDict
+from io import BytesIO
from os import path
from typing import NamedTuple
import imagesize
-from six import PY3, BytesIO, iteritems
+from six import text_type
from sphinx.deprecation import RemovedInSphinx30Warning
@@ -34,9 +35,6 @@ if False:
# For type annotation
from typing import Dict, IO, List, Tuple # NOQA
-if PY3:
- unicode = str # special alias for static typing...
-
mime_suffixes = OrderedDict([
('.gif', 'image/gif'),
('.jpg', 'image/jpeg'),
@@ -46,8 +44,8 @@ mime_suffixes = OrderedDict([
('.svgz', 'image/svg+xml'),
]) # type: Dict[unicode, unicode]
-DataURI = NamedTuple('DataURI', [('mimetype', unicode),
- ('charset', unicode),
+DataURI = NamedTuple('DataURI', [('mimetype', text_type),
+ ('charset', text_type),
('data', bytes)])
@@ -81,7 +79,7 @@ def guess_mimetype_for_stream(stream, default=None):
def guess_mimetype(filename='', content=None, default=None):
- # type: (unicode, unicode, unicode) -> unicode
+ # type: (unicode, bytes, unicode) -> unicode
_, ext = path.splitext(filename.lower())
if ext in mime_suffixes:
return mime_suffixes[ext]
@@ -98,7 +96,7 @@ def guess_mimetype(filename='', content=None, default=None):
def get_image_extension(mimetype):
# type: (unicode) -> unicode
- for ext, _mimetype in iteritems(mime_suffixes):
+ for ext, _mimetype in mime_suffixes.items():
if mimetype == _mimetype:
return ext
@@ -128,7 +126,7 @@ def parse_data_uri(uri):
def test_svg(h, f):
- # type: (unicode, IO) -> unicode
+ # type: (bytes, IO) -> unicode
"""An additional imghdr library helper; test the header is SVG's or not."""
try:
if '<svg' in h.decode('utf-8').lower():
diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py
index 6fdbcc123..541d5f5c5 100644
--- a/sphinx/util/inspect.py
+++ b/sphinx/util/inspect.py
@@ -10,15 +10,15 @@
"""
from __future__ import absolute_import
+import builtins
+import enum
import inspect
import re
import sys
import typing
-from collections import OrderedDict
from functools import partial
-from six import PY2, PY3, StringIO, binary_type, string_types, itervalues
-from six.moves import builtins
+from six import StringIO, binary_type, string_types
from sphinx.util import force_decode
from sphinx.util import logging
@@ -33,112 +33,73 @@ logger = logging.getLogger(__name__)
memory_address_re = re.compile(r' at 0x[0-9a-f]{8,16}(?=>)', re.IGNORECASE)
-if PY3:
- # Copied from the definition of inspect.getfullargspec from Python master,
- # and modified to remove the use of special flags that break decorated
- # callables and bound methods in the name of backwards compatibility. Used
- # under the terms of PSF license v2, which requires the above statement
- # and the following:
- #
- # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- # 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software
- # Foundation; All Rights Reserved
- def getargspec(func):
- """Like inspect.getfullargspec but supports bound methods, and wrapped
- methods."""
- # On 3.5+, signature(int) or similar raises ValueError. On 3.4, it
- # succeeds with a bogus signature. We want a TypeError uniformly, to
- # match historical behavior.
- if (isinstance(func, type) and
- is_builtin_class_method(func, "__new__") and
- is_builtin_class_method(func, "__init__")):
- raise TypeError(
- "can't compute signature for built-in type {}".format(func))
-
- sig = inspect.signature(func)
-
- args = []
- varargs = None
- varkw = None
- kwonlyargs = []
- defaults = ()
- annotations = {}
- defaults = ()
- kwdefaults = {}
-
- if sig.return_annotation is not sig.empty:
- annotations['return'] = sig.return_annotation
-
- for param in sig.parameters.values():
- kind = param.kind
- name = param.name
-
- if kind is inspect.Parameter.POSITIONAL_ONLY:
- args.append(name)
- elif kind is inspect.Parameter.POSITIONAL_OR_KEYWORD:
- args.append(name)
- if param.default is not param.empty:
- defaults += (param.default,)
- elif kind is inspect.Parameter.VAR_POSITIONAL:
- varargs = name
- elif kind is inspect.Parameter.KEYWORD_ONLY:
- kwonlyargs.append(name)
- if param.default is not param.empty:
- kwdefaults[name] = param.default
- elif kind is inspect.Parameter.VAR_KEYWORD:
- varkw = name
-
- if param.annotation is not param.empty:
- annotations[name] = param.annotation
-
- if not kwdefaults:
- # compatibility with 'func.__kwdefaults__'
- kwdefaults = None
-
- if not defaults:
- # compatibility with 'func.__defaults__'
- defaults = None
-
- return inspect.FullArgSpec(args, varargs, varkw, defaults,
- kwonlyargs, kwdefaults, annotations)
-
-else: # 2.7
- def getargspec(func):
- # type: (Any) -> Any
- """Like inspect.getargspec but supports functools.partial as well."""
- if inspect.ismethod(func):
- func = func.__func__
- parts = 0, () # type: Tuple[int, Tuple[unicode, ...]]
- if type(func) is partial:
- keywords = func.keywords
- if keywords is None:
- keywords = {}
- parts = len(func.args), keywords.keys()
- func = func.func
- if not inspect.isfunction(func):
- raise TypeError('%r is not a Python function' % func)
- args, varargs, varkw = inspect.getargs(func.__code__)
- func_defaults = func.__defaults__
- if func_defaults is None:
- func_defaults = []
- else:
- func_defaults = list(func_defaults)
- if parts[0]:
- args = args[parts[0]:]
- if parts[1]:
- for arg in parts[1]:
- i = args.index(arg) - len(args) # type: ignore
- del args[i]
- try:
- del func_defaults[i]
- except IndexError:
- pass
- return inspect.ArgSpec(args, varargs, varkw, func_defaults) # type: ignore
-
-try:
- import enum
-except ImportError:
- enum = None
+# Copied from the definition of inspect.getfullargspec from Python master,
+# and modified to remove the use of special flags that break decorated
+# callables and bound methods in the name of backwards compatibility. Used
+# under the terms of PSF license v2, which requires the above statement
+# and the following:
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+# 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software
+# Foundation; All Rights Reserved
+def getargspec(func):
+ """Like inspect.getfullargspec but supports bound methods, and wrapped
+ methods."""
+ # On 3.5+, signature(int) or similar raises ValueError. On 3.4, it
+ # succeeds with a bogus signature. We want a TypeError uniformly, to
+ # match historical behavior.
+ if (isinstance(func, type) and
+ is_builtin_class_method(func, "__new__") and
+ is_builtin_class_method(func, "__init__")):
+ raise TypeError(
+ "can't compute signature for built-in type {}".format(func))
+
+ sig = inspect.signature(func) # type: ignore
+
+ args = []
+ varargs = None
+ varkw = None
+ kwonlyargs = []
+ defaults = ()
+ annotations = {}
+ defaults = ()
+ kwdefaults = {}
+
+ if sig.return_annotation is not sig.empty:
+ annotations['return'] = sig.return_annotation
+
+ for param in sig.parameters.values():
+ kind = param.kind
+ name = param.name
+
+ if kind is inspect.Parameter.POSITIONAL_ONLY: # type: ignore
+ args.append(name)
+ elif kind is inspect.Parameter.POSITIONAL_OR_KEYWORD: # type: ignore
+ args.append(name)
+ if param.default is not param.empty:
+ defaults += (param.default,) # type: ignore
+ elif kind is inspect.Parameter.VAR_POSITIONAL: # type: ignore
+ varargs = name
+ elif kind is inspect.Parameter.KEYWORD_ONLY: # type: ignore
+ kwonlyargs.append(name)
+ if param.default is not param.empty:
+ kwdefaults[name] = param.default
+ elif kind is inspect.Parameter.VAR_KEYWORD: # type: ignore
+ varkw = name
+
+ if param.annotation is not param.empty:
+ annotations[name] = param.annotation
+
+ if not kwdefaults:
+ # compatibility with 'func.__kwdefaults__'
+ kwdefaults = None
+
+ if not defaults:
+ # compatibility with 'func.__defaults__'
+ defaults = None
+
+ return inspect.FullArgSpec(args, varargs, varkw, defaults, # type: ignore
+ kwonlyargs, kwdefaults, annotations)
def isenumclass(x):
@@ -275,9 +236,15 @@ def object_description(object):
except TypeError:
pass # Cannot sort set values, fall back to generic repr
else:
- template = "{%s}" if PY3 else "set([%s])"
- return template % ", ".join(object_description(x)
- for x in sorted_values)
+ return "{%s}" % ", ".join(object_description(x) for x in sorted_values)
+ if isinstance(object, frozenset):
+ try:
+ sorted_values = sorted(object)
+ except TypeError:
+ pass # Cannot sort frozenset values, fall back to generic repr
+ else:
+ return "frozenset({%s})" % ", ".join(object_description(x)
+ for x in sorted_values)
try:
s = repr(object)
except Exception:
@@ -308,7 +275,7 @@ def is_builtin_class_method(obj, attr_name):
return getattr(builtins, safe_getattr(cls, '__name__', '')) is cls # type: ignore
-class Parameter(object):
+class Parameter:
"""Fake parameter class for python2."""
POSITIONAL_ONLY = 0
POSITIONAL_OR_KEYWORD = 1
@@ -325,7 +292,7 @@ class Parameter(object):
self.annotation = self.empty
-class Signature(object):
+class Signature:
"""The Signature object represents the call signature of a callable object and
its return annotation.
"""
@@ -342,20 +309,17 @@ class Signature(object):
self.has_retval = has_retval
self.partialmethod_with_noargs = False
- if PY3:
- try:
- self.signature = inspect.signature(subject)
- except IndexError:
- # Until python 3.6.4, cpython has been crashed on inspection for
- # partialmethods not having any arguments.
- # https://bugs.python.org/issue33009
- if hasattr(subject, '_partialmethod'):
- self.signature = None
- self.partialmethod_with_noargs = True
- else:
- raise
- else:
- self.argspec = getargspec(subject)
+ try:
+ self.signature = inspect.signature(subject) # type: ignore
+ except IndexError:
+ # Until python 3.6.4, cpython has been crashed on inspection for
+ # partialmethods not having any arguments.
+ # https://bugs.python.org/issue33009
+ if hasattr(subject, '_partialmethod'):
+ self.signature = None
+ self.partialmethod_with_noargs = True
+ else:
+ raise
try:
if ispartial(subject):
@@ -375,53 +339,32 @@ class Signature(object):
if bound_method:
# client gives a hint that the subject is a bound method
- if PY3 and inspect.ismethod(subject):
+ if inspect.ismethod(subject):
# inspect.signature already considers the subject is bound method.
# So it is not need to skip first argument.
self.skip_first_argument = False
else:
self.skip_first_argument = True
else:
- if PY3:
- # inspect.signature recognizes type of method properly without any hints
- self.skip_first_argument = False
- else:
- # check the subject is bound method or not
- self.skip_first_argument = inspect.ismethod(subject) and subject.__self__ # type: ignore # NOQA
+ # inspect.signature recognizes type of method properly without any hints
+ self.skip_first_argument = False
@property
def parameters(self):
# type: () -> Dict
- if PY3:
- if self.partialmethod_with_noargs:
- return {}
- else:
- return self.signature.parameters
+ if self.partialmethod_with_noargs:
+ return {}
else:
- params = OrderedDict() # type: Dict
- positionals = len(self.argspec.args) - len(self.argspec.defaults)
- for i, arg in enumerate(self.argspec.args):
- if i < positionals:
- params[arg] = Parameter(arg)
- else:
- default = self.argspec.defaults[i - positionals]
- params[arg] = Parameter(arg, default=default)
- if self.argspec.varargs:
- params[self.argspec.varargs] = Parameter(self.argspec.varargs,
- Parameter.VAR_POSITIONAL)
- if self.argspec.keywords:
- params[self.argspec.keywords] = Parameter(self.argspec.keywords,
- Parameter.VAR_KEYWORD)
- return params
+ return self.signature.parameters
@property
def return_annotation(self):
# type: () -> Any
- if PY3 and self.signature:
+ if self.signature:
if self.has_retval:
return self.signature.return_annotation
else:
- return inspect.Parameter.empty
+ return inspect.Parameter.empty # type: ignore
else:
return None
@@ -429,7 +372,7 @@ class Signature(object):
# type: () -> unicode
args = []
last_kind = None
- for i, param in enumerate(itervalues(self.parameters)):
+ for i, param in enumerate(self.parameters.values()):
# skip first argument if subject is bound method
if self.skip_first_argument and i == 0:
continue
@@ -472,7 +415,7 @@ class Signature(object):
args.append(arg.getvalue())
last_kind = param.kind
- if PY2 or self.return_annotation is inspect.Parameter.empty:
+ if self.return_annotation is inspect.Parameter.empty: # type: ignore
return '(%s)' % ', '.join(args)
else:
if 'return' in self.annotations:
@@ -643,108 +586,6 @@ class Signature(object):
return qualname
-if sys.version_info >= (3, 5):
- _getdoc = inspect.getdoc
-else:
- # code copied from the inspect.py module of the standard library
- # of Python 3.5
-
- def _findclass(func):
- # type: (Any) -> Any
- cls = sys.modules.get(func.__module__)
- if cls is None:
- return None
- if hasattr(func, 'im_class'):
- cls = func.im_class
- else:
- for name in func.__qualname__.split('.')[:-1]:
- cls = getattr(cls, name)
- if not inspect.isclass(cls):
- return None
- return cls
-
- def _finddoc(obj):
- # type: (Any) -> unicode
- if inspect.isclass(obj):
- for base in obj.__mro__:
- if base is not object:
- try:
- doc = base.__doc__
- except AttributeError:
- continue
- if doc is not None:
- return doc
- return None
-
- if inspect.ismethod(obj) and getattr(obj, '__self__', None):
- name = obj.__func__.__name__
- self = obj.__self__
- if (inspect.isclass(self) and
- getattr(getattr(self, name, None), '__func__')
- is obj.__func__):
- # classmethod
- cls = self
- else:
- cls = self.__class__
- elif inspect.isfunction(obj) or inspect.ismethod(obj):
- name = obj.__name__
- cls = _findclass(obj)
- if cls is None or getattr(cls, name) != obj:
- return None
- elif inspect.isbuiltin(obj):
- name = obj.__name__
- self = obj.__self__
- if (inspect.isclass(self) and
- self.__qualname__ + '.' + name == obj.__qualname__):
- # classmethod
- cls = self
- else:
- cls = self.__class__
- # Should be tested before isdatadescriptor().
- elif isinstance(obj, property):
- func = obj.fget
- name = func.__name__
- cls = _findclass(func)
- if cls is None or getattr(cls, name) is not obj:
- return None
- elif inspect.ismethoddescriptor(obj) or inspect.isdatadescriptor(obj):
- name = obj.__name__
- cls = obj.__objclass__
- if getattr(cls, name) is not obj:
- return None
- else:
- return None
-
- for base in cls.__mro__:
- try:
- doc = getattr(base, name).__doc__
- except AttributeError:
- continue
- if doc is not None:
- return doc
- return None
-
- def _getdoc(object):
- # type: (Any) -> unicode
- """Get the documentation string for an object.
-
- All tabs are expanded to spaces. To clean up docstrings that are
- indented to line up with blocks of code, any whitespace than can be
- uniformly removed from the second line onwards is removed."""
- try:
- doc = object.__doc__
- except AttributeError:
- return None
- if doc is None:
- try:
- doc = _finddoc(object)
- except (AttributeError, TypeError):
- return None
- if not isinstance(doc, str):
- return None
- return inspect.cleandoc(doc)
-
-
def getdoc(obj, attrgetter=safe_getattr, allow_inherited=False):
# type: (Any, Callable, bool) -> unicode
"""Get the docstring for the object.
@@ -758,6 +599,6 @@ def getdoc(obj, attrgetter=safe_getattr, allow_inherited=False):
if ispartial(obj) and doc == obj.__class__.__doc__:
return getdoc(obj.func)
elif doc is None and allow_inherited:
- doc = _getdoc(obj)
+ doc = inspect.getdoc(obj)
return doc
diff --git a/sphinx/util/inventory.py b/sphinx/util/inventory.py
index ed4e55bc2..58ad8de33 100644
--- a/sphinx/util/inventory.py
+++ b/sphinx/util/inventory.py
@@ -12,7 +12,7 @@ import os
import re
import zlib
-from six import PY3
+from six import text_type
from sphinx.util import logging
@@ -22,17 +22,14 @@ if False:
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
- if PY3:
- unicode = str
-
- Inventory = Dict[unicode, Dict[unicode, Tuple[unicode, unicode, unicode, unicode]]]
+ Inventory = Dict[text_type, Dict[text_type, Tuple[text_type, text_type, text_type, text_type]]] # NOQA
BUFSIZE = 16 * 1024
logger = logging.getLogger(__name__)
-class InventoryFileReader(object):
+class InventoryFileReader:
"""A file reader for inventory file.
This reader supports mixture of texts and compressed texts.
@@ -94,7 +91,7 @@ class InventoryFileReader(object):
pos = buf.find(b'\n')
-class InventoryFile(object):
+class InventoryFile:
@classmethod
def load(cls, stream, uri, joinfunc):
# type: (IO, unicode, Callable) -> Inventory
diff --git a/sphinx/util/jsdump.py b/sphinx/util/jsdump.py
index 6776691cf..17865f956 100644
--- a/sphinx/util/jsdump.py
+++ b/sphinx/util/jsdump.py
@@ -12,7 +12,7 @@
import re
-from six import iteritems, integer_types, string_types
+from six import integer_types, string_types
from sphinx.util.pycompat import u
@@ -102,7 +102,7 @@ def dumps(obj, key=False):
return '{%s}' % ','.join(sorted('%s:%s' % (
dumps(key, True),
dumps(value)
- ) for key, value in iteritems(obj)))
+ ) for key, value in obj.items()))
elif isinstance(obj, set):
return '[%s]' % ','.join(sorted(dumps(x) for x in obj))
elif isinstance(obj, (tuple, list)):
diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py
index 09cef4b48..a5bd7cd05 100644
--- a/sphinx/util/logging.py
+++ b/sphinx/util/logging.py
@@ -17,7 +17,6 @@ from contextlib import contextmanager
from docutils import nodes
from docutils.utils import get_source_line
-from six import PY2, StringIO
from sphinx.errors import SphinxWarning
from sphinx.util.console import colorize
@@ -162,28 +161,7 @@ class WarningStreamHandler(logging.StreamHandler):
pass
-class NewLineStreamHandlerPY2(logging.StreamHandler):
- """StreamHandler which switches line terminator by record.nonl flag."""
-
- def emit(self, record):
- # type: (logging.LogRecord) -> None
- try:
- self.acquire()
- stream = self.stream
- if getattr(record, 'nonl', False):
- # remove return code forcely when nonl=True
- self.stream = StringIO()
- super(NewLineStreamHandlerPY2, self).emit(record)
- stream.write(self.stream.getvalue()[:-1])
- stream.flush()
- else:
- super(NewLineStreamHandlerPY2, self).emit(record)
- finally:
- self.stream = stream
- self.release()
-
-
-class NewLineStreamHandlerPY3(logging.StreamHandler):
+class NewLineStreamHandler(logging.StreamHandler):
"""StreamHandler which switches line terminator by record.nonl flag."""
def emit(self, record):
@@ -193,18 +171,12 @@ class NewLineStreamHandlerPY3(logging.StreamHandler):
if getattr(record, 'nonl', False):
# skip appending terminator when nonl=True
self.terminator = ''
- super(NewLineStreamHandlerPY3, self).emit(record)
+ super(NewLineStreamHandler, self).emit(record)
finally:
self.terminator = '\n'
self.release()
-if PY2:
- NewLineStreamHandler = NewLineStreamHandlerPY2
-else:
- NewLineStreamHandler = NewLineStreamHandlerPY3
-
-
class MemoryHandler(logging.handlers.BufferingHandler):
"""Handler buffering all logs."""
@@ -315,7 +287,7 @@ def skip_warningiserror(skip=True):
handler.removeFilter(disabler)
-class LogCollector(object):
+class LogCollector:
def __init__(self):
# type: () -> None
self.logs = [] # type: List[logging.LogRecord]
@@ -496,7 +468,7 @@ class ColorizeFormatter(logging.Formatter):
return message
-class SafeEncodingWriter(object):
+class SafeEncodingWriter:
"""Stream writer which ignores UnicodeEncodeError silently"""
def __init__(self, stream):
# type: (IO) -> None
@@ -518,7 +490,7 @@ class SafeEncodingWriter(object):
self.stream.flush()
-class LastMessagesWriter(object):
+class LastMessagesWriter:
"""Stream writer which memories last 10 messages to save trackback"""
def __init__(self, app, stream):
# type: (Sphinx, IO) -> None
diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py
index bddf84f5c..43e68949a 100644
--- a/sphinx/util/matching.py
+++ b/sphinx/util/matching.py
@@ -68,7 +68,7 @@ def compile_matchers(patterns):
return [re.compile(_translate_pattern(pat)).match for pat in patterns]
-class Matcher(object):
+class Matcher:
"""A pattern matcher for Multiple shell-style glob patterns.
Note: this modifies the patterns to work with copy_asset().
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py
index 03e06c416..ff73819ee 100644
--- a/sphinx/util/nodes.py
+++ b/sphinx/util/nodes.py
@@ -11,6 +11,7 @@
from __future__ import absolute_import
import re
+from typing import Any
from docutils import nodes
from six import text_type
@@ -33,6 +34,57 @@ explicit_title_re = re.compile(r'^(.+?)\s*(?<!\x00)<(.*?)>$', re.DOTALL)
caption_ref_re = explicit_title_re # b/w compat alias
+class NodeMatcher:
+ """A helper class for Node.traverse().
+
+ It checks that given node is an instance of specified node-classes and it has
+ specified node-attributes.
+
+ For example, following example searches ``reference`` node having ``refdomain``
+ and ``reftype`` attributes::
+
+ matcher = NodeMatcher(nodes.reference, refdomain='std', reftype='citation')
+ doctree.traverse(matcher)
+ # => [<reference ...>, <reference ...>, ...]
+
+ A special value ``typing.Any`` matches any kind of node-attributes. For example,
+ following example searches ``reference`` node having ``refdomain`` attributes::
+
+ from typing import Any
+ matcher = NodeMatcher(nodes.reference, refdomain=Any)
+ doctree.traverse(matcher)
+ # => [<reference ...>, <reference ...>, ...]
+ """
+
+ def __init__(self, *classes, **attrs):
+ # type: (nodes.Node, Any) -> None
+ self.classes = classes
+ self.attrs = attrs
+
+ def match(self, node):
+ # type: (nodes.Node) -> bool
+ try:
+ if self.classes and not isinstance(node, self.classes):
+ return False
+
+ for key, value in self.attrs.items():
+ if key not in node:
+ return False
+ elif value is Any:
+ continue
+ elif node.get(key) != value:
+ return False
+ else:
+ return True
+ except Exception:
+ # for non-Element nodes
+ return False
+
+ def __call__(self, node):
+ # type: (nodes.Node) -> bool
+ return self.match(node)
+
+
def get_full_module_name(node):
# type: (nodes.Node) -> str
"""
@@ -241,11 +293,7 @@ def traverse_parent(node, cls=None):
def traverse_translatable_index(doctree):
# type: (nodes.Node) -> Iterable[Tuple[nodes.Node, List[unicode]]]
"""Traverse translatable index node from a document tree."""
- def is_block_index(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, addnodes.index) and \
- node.get('inline') is False
- for node in doctree.traverse(is_block_index):
+ for node in doctree.traverse(NodeMatcher(addnodes.index, inline=False)):
if 'raw_entries' in node:
entries = node['raw_entries']
else:
diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py
index 4c75009ee..11b082e7d 100644
--- a/sphinx/util/osutil.py
+++ b/sphinx/util/osutil.py
@@ -13,7 +13,6 @@ from __future__ import print_function
import contextlib
import errno
import filecmp
-import locale
import os
import re
import shutil
@@ -23,9 +22,9 @@ import warnings
from io import BytesIO, StringIO
from os import path
-from six import PY2, PY3, text_type
+from six import text_type
-from sphinx.deprecation import RemovedInSphinx30Warning
+from sphinx.deprecation import RemovedInSphinx30Warning, RemovedInSphinx40Warning
if False:
# For type annotation
@@ -37,9 +36,6 @@ ENOENT = getattr(errno, 'ENOENT', 0)
EPIPE = getattr(errno, 'EPIPE', 0)
EINVAL = getattr(errno, 'EINVAL', 0)
-if PY3:
- unicode = str # special alias for static typing...
-
# SEP separates path elements in the canonical file names
#
# Define SEP as a manifest constant, not so much because we expect it to change
@@ -94,39 +90,12 @@ def ensuredir(path):
raise
-# This function is same as os.walk of Python2.7 except a customization
-# that check UnicodeError.
-# The customization obstacle to replace the function with the os.walk.
def walk(top, topdown=True, followlinks=False):
# type: (unicode, bool, bool) -> Iterator[Tuple[unicode, List[unicode], List[unicode]]]
- """Backport of os.walk from 2.6, where the *followlinks* argument was
- added.
- """
- names = os.listdir(top)
-
- dirs, nondirs = [], []
- for name in names:
- try:
- fullpath = path.join(top, name)
- except UnicodeError:
- print('%s:: ERROR: non-ASCII filename not supported on this '
- 'filesystem encoding %r, skipped.' % (name, fs_encoding),
- file=sys.stderr)
- continue
- if path.isdir(fullpath):
- dirs.append(name)
- else:
- nondirs.append(name)
-
- if topdown:
- yield top, dirs, nondirs
- for name in dirs:
- fullpath = path.join(top, name)
- if followlinks or not path.islink(fullpath):
- for x in walk(fullpath, topdown, followlinks):
- yield x
- if not topdown:
- yield top, dirs, nondirs
+ warnings.warn('sphinx.util.osutil.walk() is deprecated for removal. '
+ 'Please use os.walk() instead.',
+ RemovedInSphinx40Warning)
+ return os.walk(top, topdown=topdown, followlinks=followlinks)
def mtimes_of_files(dirnames, suffix):
@@ -195,19 +164,13 @@ def ustrftime(format, *args):
if source_date_epoch is not None:
time_struct = time.gmtime(float(source_date_epoch))
args = [time_struct] # type: ignore
- if PY2:
- # if a locale is set, the time strings are encoded in the encoding
- # given by LC_TIME; if that is available, use it
- enc = locale.getlocale(locale.LC_TIME)[1] or 'utf-8'
- return time.strftime(text_type(format).encode(enc), *args).decode(enc)
- else: # Py3
- # On Windows, time.strftime() and Unicode characters will raise UnicodeEncodeError.
- # https://bugs.python.org/issue8304
- try:
- return time.strftime(format, *args)
- except UnicodeEncodeError:
- r = time.strftime(format.encode('unicode-escape').decode(), *args)
- return r.encode().decode('unicode-escape')
+ # On Windows, time.strftime() and Unicode characters will raise UnicodeEncodeError.
+ # https://bugs.python.org/issue8304
+ try:
+ return time.strftime(format, *args) # type: ignore
+ except UnicodeEncodeError:
+ r = time.strftime(format.encode('unicode-escape').decode(), *args) # type: ignore
+ return r.encode().decode('unicode-escape')
def relpath(path, start=os.curdir):
@@ -243,15 +206,16 @@ def abspath(pathdir):
def getcwd():
# type: () -> unicode
- if hasattr(os, 'getcwdu'):
- return os.getcwdu()
+ warnings.warn('sphinx.util.osutil.getcwd() is deprecated. '
+ 'Please use os.getcwd() instead.',
+ RemovedInSphinx40Warning)
return os.getcwd()
@contextlib.contextmanager
def cd(target_dir):
# type: (unicode) -> Iterator[None]
- cwd = getcwd()
+ cwd = os.getcwd()
try:
os.chdir(target_dir)
yield
@@ -259,7 +223,7 @@ def cd(target_dir):
os.chdir(cwd)
-class FileAvoidWrite(object):
+class FileAvoidWrite:
"""File-like object that buffers output and only writes if content changed.
Use this class like when writing to a file to avoid touching the original
diff --git a/sphinx/util/parallel.py b/sphinx/util/parallel.py
index 066e3c93a..8b3edd314 100644
--- a/sphinx/util/parallel.py
+++ b/sphinx/util/parallel.py
@@ -15,8 +15,6 @@ import time
import traceback
from math import sqrt
-from six import iteritems
-
try:
import multiprocessing
except ImportError:
@@ -36,7 +34,7 @@ logger = logging.getLogger(__name__)
parallel_available = multiprocessing and (os.name == 'posix')
-class SerialTasks(object):
+class SerialTasks:
"""Has the same interface as ParallelTasks, but executes tasks directly."""
def __init__(self, nproc=1):
@@ -57,7 +55,7 @@ class SerialTasks(object):
pass
-class ParallelTasks(object):
+class ParallelTasks:
"""Executes *nproc* tasks in parallel after forking."""
def __init__(self, nproc):
@@ -115,7 +113,7 @@ class ParallelTasks(object):
def _join_one(self):
# type: () -> None
- for tid, pipe in iteritems(self._precvs):
+ for tid, pipe in self._precvs.items():
if pipe.poll():
exc, logs, result = pipe.recv()
if exc:
diff --git a/sphinx/util/pycompat.py b/sphinx/util/pycompat.py
index 8bcf7e4f8..a33a832c8 100644
--- a/sphinx/util/pycompat.py
+++ b/sphinx/util/pycompat.py
@@ -9,10 +9,12 @@
:license: BSD, see LICENSE for details.
"""
-import codecs
import sys
+from html import escape as htmlescape # NOQA
+from io import TextIOWrapper # NOQA
+from textwrap import indent # type: ignore # NOQA
-from six import PY3, text_type, exec_
+from six import text_type, exec_
if False:
# For type annotation
@@ -25,114 +27,51 @@ NoneType = type(None)
# Python 2/3 compatibility
# prefix for Unicode strings
-if PY3:
- u = ''
-else:
- u = 'u'
-
-
-# TextIOWrapper
-if PY3:
- from io import TextIOWrapper
-else:
- def TextIOWrapper(stream, encoding):
- # type: (file, str) -> Any
- return codecs.lookup(encoding or 'ascii')[2](stream)
+u = ''
# sys_encoding: some kind of default system encoding; should be used with
# a lenient error handler
-if PY3:
- sys_encoding = sys.getdefaultencoding()
-else:
- sys_encoding = __import__('locale').getpreferredencoding()
+sys_encoding = sys.getdefaultencoding()
# terminal_safe(): safely encode a string for printing to the terminal
-if PY3:
- def terminal_safe(s):
- # type: (unicode) -> unicode
- return s.encode('ascii', 'backslashreplace').decode('ascii')
-else:
- def terminal_safe(s):
- # type: (unicode) -> unicode
- return s.encode('ascii', 'backslashreplace')
+def terminal_safe(s):
+ # type: (unicode) -> unicode
+ return s.encode('ascii', 'backslashreplace').decode('ascii')
# convert_with_2to3():
-if PY3:
- # support for running 2to3 over config files
- def convert_with_2to3(filepath):
- # type: (unicode) -> unicode
- from lib2to3.refactor import RefactoringTool, get_fixers_from_package
- from lib2to3.pgen2.parse import ParseError
- fixers = get_fixers_from_package('lib2to3.fixes')
- refactoring_tool = RefactoringTool(fixers)
- source = refactoring_tool._read_python_source(filepath)[0]
- try:
- tree = refactoring_tool.refactor_string(source, 'conf.py')
- except ParseError as err:
- # do not propagate lib2to3 exceptions
- lineno, offset = err.context[1]
- # try to match ParseError details with SyntaxError details
- raise SyntaxError(err.msg, (filepath, lineno, offset, err.value))
- return text_type(tree)
-else:
- # no need to refactor on 2.x versions
- convert_with_2to3 = None
-
-
-# htmlescape()
-if PY3:
- from html import escape as htmlescape
-else:
- from cgi import escape as htmlescape # NOQA
-
-
-# UnicodeMixin
-if PY3:
- class UnicodeMixin(object):
- """Mixin class to handle defining the proper __str__/__unicode__
- methods in Python 2 or 3."""
-
- def __str__(self):
- return self.__unicode__()
-else:
- class UnicodeMixin(object):
- """Mixin class to handle defining the proper __str__/__unicode__
- methods in Python 2 or 3."""
-
- def __str__(self):
- # type: () -> str
- return self.__unicode__().encode('utf8') # type: ignore
-
-
-# indent()
-if PY3:
- from textwrap import indent
-else:
- # backport from python3
- def indent(text, prefix, predicate=None):
- # type: (unicode, unicode, Callable) -> unicode
- if predicate is None:
- def predicate(line):
- # type: (unicode) -> unicode
- return line.strip()
-
- def prefixed_lines():
- # type: () -> Generator
- for line in text.splitlines(True):
- yield (prefix + line if predicate(line) else line)
- return ''.join(prefixed_lines())
+# support for running 2to3 over config files
+def convert_with_2to3(filepath):
+ # type: (unicode) -> unicode
+ from lib2to3.refactor import RefactoringTool, get_fixers_from_package
+ from lib2to3.pgen2.parse import ParseError
+ fixers = get_fixers_from_package('lib2to3.fixes')
+ refactoring_tool = RefactoringTool(fixers)
+ source = refactoring_tool._read_python_source(filepath)[0]
+ try:
+ tree = refactoring_tool.refactor_string(source, 'conf.py')
+ except ParseError as err:
+ # do not propagate lib2to3 exceptions
+ lineno, offset = err.context[1]
+ # try to match ParseError details with SyntaxError details
+ raise SyntaxError(err.msg, (filepath, lineno, offset, err.value))
+ return text_type(tree)
+
+
+class UnicodeMixin:
+ """Mixin class to handle defining the proper __str__/__unicode__
+ methods in Python 2 or 3."""
+
+ def __str__(self):
+ return self.__unicode__()
def execfile_(filepath, _globals, open=open):
# type: (unicode, Any, Callable) -> None
from sphinx.util.osutil import fs_encoding
- # get config source -- 'b' is a no-op under 2.x, while 'U' is
- # ignored under 3.x (but 3.x compile() accepts \r\n newlines)
- mode = 'rb' if PY3 else 'rbU'
- with open(filepath, mode) as f:
+ with open(filepath, 'rb') as f:
source = f.read()
# compile to a code object, handle syntax errors
diff --git a/sphinx/util/stemmer/__init__.py b/sphinx/util/stemmer/__init__.py
index a10da7370..43aef5032 100644
--- a/sphinx/util/stemmer/__init__.py
+++ b/sphinx/util/stemmer/__init__.py
@@ -18,7 +18,7 @@ except ImportError:
PYSTEMMER = False
-class BaseStemmer(object):
+class BaseStemmer:
def stem(self, word):
# type: (unicode) -> unicode
raise NotImplementedError()
diff --git a/sphinx/util/stemmer/porter.py b/sphinx/util/stemmer/porter.py
index beb860c9e..4f2f1a089 100644
--- a/sphinx/util/stemmer/porter.py
+++ b/sphinx/util/stemmer/porter.py
@@ -14,7 +14,7 @@
only differing from it at the points maked --DEPARTURE-- below.
- See also http://www.tartarus.org/~martin/PorterStemmer
+ See also https://tartarus.org/martin/PorterStemmer/
The algorithm as described in the paper could be exactly replicated
by adjusting the points of DEPARTURE, but this is barely necessary,
@@ -29,7 +29,7 @@
"""
-class PorterStemmer(object):
+class PorterStemmer:
def __init__(self):
# type: () -> None
diff --git a/sphinx/util/tags.py b/sphinx/util/tags.py
index 43a351f65..4d0dc7f9a 100644
--- a/sphinx/util/tags.py
+++ b/sphinx/util/tags.py
@@ -46,7 +46,7 @@ class BooleanParser(Parser):
return node
-class Tags(object):
+class Tags:
def __init__(self, tags=None):
# type: (List[unicode]) -> None
self.tags = dict.fromkeys(tags or [], True)
diff --git a/sphinx/util/template.py b/sphinx/util/template.py
index 5a415d329..01c772069 100644
--- a/sphinx/util/template.py
+++ b/sphinx/util/template.py
@@ -16,6 +16,7 @@ from jinja2.sandbox import SandboxedEnvironment
from sphinx import package_dir
from sphinx.jinja2glue import SphinxFileSystemLoader
from sphinx.locale import get_translator
+from sphinx.util import texescape
if False:
# For type annotation
@@ -23,7 +24,7 @@ if False:
from jinja2.loaders import BaseLoader # NOQA
-class BaseRenderer(object):
+class BaseRenderer:
def __init__(self, loader=None):
# type: (BaseLoader) -> None
self.env = SandboxedEnvironment(loader=loader, extensions=['jinja2.ext.i18n'])
@@ -72,6 +73,10 @@ class LaTeXRenderer(SphinxRenderer):
template_path = os.path.join(package_dir, 'templates', 'latex')
super(LaTeXRenderer, self).__init__(template_path)
+ # use texescape as escape filter
+ self.env.filters['e'] = texescape.escape
+ self.env.filters['escape'] = texescape.escape
+
# use JSP/eRuby like tagging instead because curly bracket; the default
# tagging of jinja2 is not good for LaTeX sources.
self.env.variable_start_string = '<%='
diff --git a/sphinx/util/texescape.py b/sphinx/util/texescape.py
index 8d37e0f60..0f1783def 100644
--- a/sphinx/util/texescape.py
+++ b/sphinx/util/texescape.py
@@ -11,6 +11,10 @@
from __future__ import unicode_literals
+if False:
+ # For type annotation
+ from typing import Dict # NOQA
+
tex_replacements = [
# map TeX special chars
('$', r'\$'),
@@ -117,11 +121,17 @@ tex_replacements = [
('Ω', r'\(\Omega\)'),
]
-tex_escape_map = {}
+tex_escape_map = {} # type: Dict[int, unicode]
tex_replace_map = {}
tex_hl_escape_map_new = {}
+def escape(s):
+ # type: (unicode) -> unicode
+ """Escape text for LaTeX output."""
+ return s.translate(tex_escape_map)
+
+
def init():
# type: () -> None
for a, b in tex_replacements:
diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py
index a26dac473..d31fa7c68 100644
--- a/sphinx/util/typing.py
+++ b/sphinx/util/typing.py
@@ -13,15 +13,12 @@ from typing import Callable, Dict, List, Tuple
from docutils import nodes
from docutils.parsers.rst.states import Inliner
-from six import PY3
+from six import text_type
-if PY3:
- unicode = str
-
# common role functions
-RoleFunction = Callable[[unicode, unicode, unicode, int, Inliner, Dict, List[unicode]],
+RoleFunction = Callable[[text_type, text_type, text_type, int, Inliner, Dict, List[text_type]],
Tuple[List[nodes.Node], List[nodes.Node]]]
# title getter functions for enumerable nodes (see sphinx.domains.std)
-TitleGetter = Callable[[nodes.Node], unicode]
+TitleGetter = Callable[[nodes.Node], text_type]
diff --git a/sphinx/versioning.py b/sphinx/versioning.py
index 58b648069..e65c9fd8f 100644
--- a/sphinx/versioning.py
+++ b/sphinx/versioning.py
@@ -9,13 +9,13 @@
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
+import pickle
import warnings
from itertools import product
from operator import itemgetter
+from os import path
from uuid import uuid4
-from six import iteritems
-from six.moves import cPickle as pickle
from six.moves import range, zip_longest
from sphinx.deprecation import RemovedInSphinx30Warning
@@ -102,7 +102,7 @@ def merge_doctrees(old, new, condition):
# choose the old node with the best ratio for each new node and set the uid
# as long as the ratio is under a certain value, in which case we consider
# them not changed but different
- ratios = sorted(iteritems(ratios), key=itemgetter(1)) # type: ignore
+ ratios = sorted(ratios.items(), key=itemgetter(1)) # type: ignore
for (old_node, new_node), ratio in ratios:
if new_node in seen:
continue
@@ -169,7 +169,7 @@ class UIDTransform(SphinxTransform):
if env.versioning_compare:
# get old doctree
try:
- filename = env.doc2path(env.docname, env.doctreedir, '.doctree')
+ filename = path.join(env.doctreedir, env.docname + '.doctree')
with open(filename, 'rb') as f:
old_doctree = pickle.load(f)
except EnvironmentError:
diff --git a/sphinx/websupport/__init__.py b/sphinx/websupport/__init__.py
deleted file mode 100644
index 51d906fa6..000000000
--- a/sphinx/websupport/__init__.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport
- ~~~~~~~~~~~~~~~~~
-
- Base Module for web support functions.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-import warnings
-
-from sphinx.deprecation import RemovedInSphinx20Warning
-
-try:
- from sphinxcontrib.websupport import WebSupport # NOQA
- from sphinxcontrib.websupport import errors # NOQA
- from sphinxcontrib.websupport.search import BaseSearch, SEARCH_ADAPTERS # NOQA
- from sphinxcontrib.websupport.storage import StorageBackend # NOQA
-
- warnings.warn('sphinx.websupport module is now provided as sphinxcontrib-websupport. '
- 'sphinx.websupport will be removed at Sphinx-2.0. '
- 'Please use the package instead.',
- RemovedInSphinx20Warning)
-except ImportError:
- warnings.warn('Since Sphinx-1.6, sphinx.websupport module is now separated to '
- 'sphinxcontrib-websupport package. Please add it into your dependency list.')
diff --git a/sphinx/websupport/errors.py b/sphinx/websupport/errors.py
deleted file mode 100644
index 7456659ec..000000000
--- a/sphinx/websupport/errors.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.errors
- ~~~~~~~~~~~~~~~~~~~~~~~~
-
- Contains Error classes for the web support package.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.errors import * # NOQA
diff --git a/sphinx/websupport/search/__init__.py b/sphinx/websupport/search/__init__.py
deleted file mode 100644
index e1e871ba0..000000000
--- a/sphinx/websupport/search/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.search
- ~~~~~~~~~~~~~~~~~~~~~~~~
-
- Server side search support for the web support package.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.search import BaseSearch, SEARCH_ADAPTERS # NOQA
diff --git a/sphinx/websupport/search/nullsearch.py b/sphinx/websupport/search/nullsearch.py
deleted file mode 100644
index 422b398c9..000000000
--- a/sphinx/websupport/search/nullsearch.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.search.nullsearch
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- The default search adapter, does nothing.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.search.nullsearch import NullSearch # NOQA
diff --git a/sphinx/websupport/search/whooshsearch.py b/sphinx/websupport/search/whooshsearch.py
deleted file mode 100644
index 94cce8ed7..000000000
--- a/sphinx/websupport/search/whooshsearch.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.search.whooshsearch
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Whoosh search adapter.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.search.whooshsearch import WhooshSearch # NOQA
diff --git a/sphinx/websupport/search/xapiansearch.py b/sphinx/websupport/search/xapiansearch.py
deleted file mode 100644
index 4df4769e2..000000000
--- a/sphinx/websupport/search/xapiansearch.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.search.xapiansearch
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Xapian search adapter.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.search.xapiansearch import XapianSearch # NOQA
diff --git a/sphinx/websupport/storage/__init__.py b/sphinx/websupport/storage/__init__.py
deleted file mode 100644
index 727e86da4..000000000
--- a/sphinx/websupport/storage/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.storage
- ~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Storage for the websupport package.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.storage import StorageBackend # NOQA
diff --git a/sphinx/websupport/storage/differ.py b/sphinx/websupport/storage/differ.py
deleted file mode 100644
index 1358d8645..000000000
--- a/sphinx/websupport/storage/differ.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.storage.differ
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- A differ for creating an HTML representations of proposal diffs
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.storage.differ import CombinedHtmlDiff # NOQA
diff --git a/sphinx/websupport/storage/sqlalchemy_db.py b/sphinx/websupport/storage/sqlalchemy_db.py
deleted file mode 100644
index e1c86dd9d..000000000
--- a/sphinx/websupport/storage/sqlalchemy_db.py
+++ /dev/null
@@ -1,13 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.storage.sqlalchemy_db
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- SQLAlchemy table and mapper definitions used by the
- :class:`sphinx.websupport.storage.sqlalchemystorage.SQLAlchemyStorage`.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.storage.sqlalchemy_db import Node, Comment, CommentVote # NOQA
diff --git a/sphinx/websupport/storage/sqlalchemystorage.py b/sphinx/websupport/storage/sqlalchemystorage.py
deleted file mode 100644
index b018ea0a3..000000000
--- a/sphinx/websupport/storage/sqlalchemystorage.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- sphinx.websupport.storage.sqlalchemystorage
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- An SQLAlchemy storage backend.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinxcontrib.websupport.storage.sqlalchemystorage import SQLAlchemyStorage # NOQA
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 4ef8ddbca..f9af2a1f8 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -20,7 +20,7 @@ from os import path
from docutils import nodes, writers
from docutils.writers.latex2e import Babel
-from six import itervalues, text_type
+from six import text_type
from sphinx import addnodes
from sphinx import highlighting
@@ -115,7 +115,6 @@ DEFAULT_SETTINGS = {
'tocdepth': '',
'secnumdepth': '',
'pageautorefname': '',
- 'translatablestrings': '',
} # type: Dict[unicode, unicode]
ADDITIONAL_SETTINGS = {
@@ -257,7 +256,7 @@ class ExtBabel(Babel):
return None
-class Table(object):
+class Table:
"""A table data"""
def __init__(self, node):
@@ -378,7 +377,7 @@ class Table(object):
return None
-class TableCell(object):
+class TableCell:
"""A cell data of tables."""
def __init__(self, table, row, col):
@@ -472,33 +471,10 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.first_param = 0
# sort out some elements
- self.elements = DEFAULT_SETTINGS.copy()
- self.elements.update(ADDITIONAL_SETTINGS.get(builder.config.latex_engine, {}))
- # for xelatex+French, don't use polyglossia
- if self.elements['latex_engine'] == 'xelatex':
- if builder.config.language:
- if builder.config.language[:2] == 'fr':
- self.elements.update({
- 'polyglossia': '',
- 'babel': '\\usepackage{babel}',
- })
- # allow the user to override them all
- self.elements.update(builder.config.latex_elements)
+ self.elements = builder.context.copy()
# but some have other interface in config file
- self.elements.update({
- 'wrapperclass': self.format_docclass(document.settings.docclass),
- # if empty, the title is set to the first section title
- 'title': document.settings.title, # treat as a raw LaTeX code
- 'release': self.encode(builder.config.release),
- 'author': document.settings.author, # treat as a raw LaTeX code
- 'indexname': _('Index'),
- 'use_xindy': builder.config.latex_use_xindy,
- })
- if not self.elements['releasename'] and self.elements['release']:
- self.elements.update({
- 'releasename': _('Release'),
- })
+ self.elements['wrapperclass'] = self.format_docclass(document.settings.docclass)
# we assume LaTeX class provides \chapter command except in case
# of non-Japanese 'howto' case
@@ -651,23 +627,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
if self.elements['extraclassoptions']:
self.elements['classoptions'] += ',' + \
self.elements['extraclassoptions']
- self.elements['translatablestrings'] = (
- self.babel_renewcommand(
- '\\literalblockcontinuedname', self.encode(_('continued from previous page'))
- ) +
- self.babel_renewcommand(
- '\\literalblockcontinuesname', self.encode(_('continues on next page'))
- ) +
- self.babel_renewcommand(
- '\\sphinxnonalphabeticalgroupname', self.encode(_('Non-alphabetical'))
- ) +
- self.babel_renewcommand(
- '\\sphinxsymbolsname', self.encode(_('Symbols'))
- ) +
- self.babel_renewcommand(
- '\\sphinxnumbersname', self.encode(_('Numbers'))
- )
- )
self.elements['pageautorefname'] = \
self.babel_defmacro('\\pageautorefname', self.encode(_('page')))
self.elements['numfig_format'] = self.generate_numfig_format(builder)
@@ -849,7 +808,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
# latex_domain_indices can be False/True or a list of index names
indices_config = self.builder.config.latex_domain_indices
if indices_config:
- for domain in itervalues(self.builder.env.domains):
+ for domain in self.builder.env.domains.values():
for indexcls in domain.indices:
indexname = '%s-%s' % (domain.name, indexcls.name)
if isinstance(indices_config, list):
diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py
index 45a800533..471e58813 100644
--- a/sphinx/writers/manpage.py
+++ b/sphinx/writers/manpage.py
@@ -11,16 +11,15 @@
from docutils import nodes
from docutils.writers.manpage import (
- MACRO_DEF,
Writer,
Translator as BaseTranslator
)
-import sphinx.util.docutils
from sphinx import addnodes
from sphinx.locale import admonitionlabels, _
from sphinx.util import logging
from sphinx.util.i18n import format_date
+from sphinx.util.nodes import NodeMatcher
if False:
# For type annotation
@@ -46,7 +45,7 @@ class ManualPageWriter(Writer):
self.output = visitor.astext()
-class NestedInlineTransform(object):
+class NestedInlineTransform:
"""
Flatten nested inline nodes:
@@ -63,16 +62,13 @@ class NestedInlineTransform(object):
def apply(self):
# type: () -> None
- def is_inline(node):
- # type: (nodes.Node) -> bool
- return isinstance(node, (nodes.literal, nodes.emphasis, nodes.strong))
-
- for node in self.document.traverse(is_inline):
- if any(is_inline(subnode) for subnode in node):
+ matcher = NodeMatcher(nodes.literal, nodes.emphasis, nodes.strong)
+ for node in self.document.traverse(matcher):
+ if any(matcher(subnode) for subnode in node):
pos = node.parent.index(node)
for subnode in reversed(node[1:]):
node.remove(subnode)
- if is_inline(subnode):
+ if matcher(subnode):
node.parent.insert(pos + 1, subnode)
else:
newnode = node.__class__('', subnode, **node.attributes)
@@ -113,10 +109,6 @@ class ManualPageTranslator(BaseTranslator):
self._docinfo['version'] = builder.config.version
self._docinfo['manual_group'] = builder.config.project
- # In docutils < 0.11 self.append_header() was never called
- if sphinx.util.docutils.__version_info__ < (0, 11):
- self.body.append(MACRO_DEF)
-
# Overwrite admonition label translations with our own
for label, translation in admonitionlabels.items():
self.language.labels[label] = self.deunicode(translation)
diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py
index 701880a61..91e534278 100644
--- a/sphinx/writers/texinfo.py
+++ b/sphinx/writers/texinfo.py
@@ -14,8 +14,6 @@ import textwrap
from os import path
from docutils import nodes, writers
-from six import itervalues
-from six.moves import range
from sphinx import addnodes, __display_version__
from sphinx.errors import ExtensionError
@@ -498,7 +496,7 @@ class TexinfoTranslator(nodes.NodeVisitor):
indices_config = self.builder.config.texinfo_domain_indices
if indices_config:
- for domain in itervalues(self.builder.env.domains):
+ for domain in self.builder.env.domains.values():
for indexcls in domain.indices:
indexname = '%s-%s' % (domain.name, indexcls.name)
if isinstance(indices_config, list):
diff --git a/tests/conftest.py b/tests/conftest.py
index 9f46b1868..65142d84a 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -9,7 +9,6 @@
import os
import shutil
-import sys
import docutils
import pytest
@@ -22,13 +21,6 @@ pytest_plugins = 'sphinx.testing.fixtures'
# Exclude 'roots' dirs for pytest test collector
collect_ignore = ['roots']
-# Disable Python version-specific
-if sys.version_info < (3,):
- collect_ignore += ['py3']
-
-if sys.version_info < (3, 5):
- collect_ignore += ['py35']
-
@pytest.fixture(scope='session')
def rootdir():
diff --git a/tests/py3/test_util_inspect_py3.py b/tests/py3/test_util_inspect_py3.py
deleted file mode 100644
index 6d02025f9..000000000
--- a/tests/py3/test_util_inspect_py3.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- py3/test_util_inspect
- ~~~~~~~~~~~~~~~~~~~~~
-
- Tests util.inspect functions.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-from sphinx.util import inspect
-
-
-def test_Signature_keyword_only_arguments():
- def func1(arg1, arg2, *, arg3=None, arg4=None):
- pass
-
- def func2(*, arg3, arg4):
- pass
-
- sig = inspect.Signature(func1).format_args()
- assert sig == '(arg1, arg2, *, arg3=None, arg4=None)'
-
- sig = inspect.Signature(func2).format_args()
- assert sig == '(*, arg3, arg4)'
diff --git a/tests/py35/test_autodoc_py35.py b/tests/py35/test_autodoc_py35.py
deleted file mode 100644
index 046fb93b4..000000000
--- a/tests/py35/test_autodoc_py35.py
+++ /dev/null
@@ -1,348 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- test_autodoc
- ~~~~~~~~~~~~
-
- Test the autodoc extension. This tests mainly the Documenters; the auto
- directives are tested in a test source file translated by test_build.
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-# "raises" imported for usage by autodoc
-import sys
-
-import pytest
-import six
-from docutils.statemachine import ViewList
-from six import StringIO
-
-from sphinx.ext.autodoc import add_documenter, FunctionDocumenter, ALL, Options # NOQA
-from sphinx.testing.util import SphinxTestApp, Struct
-from sphinx.util import logging
-
-app = None
-
-
-@pytest.fixture(scope='module', autouse=True)
-def setup_module(rootdir, sphinx_test_tempdir):
- global app
- srcdir = sphinx_test_tempdir / 'autodoc-root'
- if not srcdir.exists():
- (rootdir / 'test-root').copytree(srcdir)
- app = SphinxTestApp(srcdir=srcdir)
- app.builder.env.app = app
- app.builder.env.temp_data['docname'] = 'dummy'
- app.connect('autodoc-process-docstring', process_docstring)
- app.connect('autodoc-process-signature', process_signature)
- app.connect('autodoc-skip-member', skip_member)
- yield
- app.cleanup()
-
-
-directive = options = None
-
-
-@pytest.fixture
-def setup_test():
- global options, directive
- global processed_docstrings, processed_signatures
-
- options = Options(
- inherited_members = False,
- undoc_members = False,
- private_members = False,
- special_members = False,
- imported_members = False,
- show_inheritance = False,
- noindex = False,
- annotation = None,
- synopsis = '',
- platform = '',
- deprecated = False,
- members = [],
- member_order = 'alphabetic',
- exclude_members = set(),
- )
-
- directive = Struct(
- env = app.builder.env,
- genopt = options,
- result = ViewList(),
- filename_set = set(),
- )
-
- processed_docstrings = []
- processed_signatures = []
-
-
-processed_docstrings = []
-processed_signatures = []
-
-
-def process_docstring(app, what, name, obj, options, lines):
- processed_docstrings.append((what, name))
- if name == 'bar':
- lines.extend(['42', ''])
-
-
-def process_signature(app, what, name, obj, options, args, retann):
- processed_signatures.append((what, name))
- if name == 'bar':
- return '42', None
-
-
-def skip_member(app, what, name, obj, skip, options):
- if name in ('__special1__', '__special2__'):
- return skip
- if name.startswith('_'):
- return True
- if name == 'skipmeth':
- return True
-
-
-@pytest.mark.usefixtures('setup_test')
-def test_generate():
- logging.setup(app, app._status, app._warning)
-
- def assert_warns(warn_str, objtype, name, **kw):
- inst = app.registry.documenters[objtype](directive, name)
- inst.generate(**kw)
- assert len(directive.result) == 0, directive.result
- assert warn_str in app._warning.getvalue()
- app._warning.truncate(0)
- app._warning.seek(0)
-
- def assert_works(objtype, name, **kw):
- inst = app.registry.documenters[objtype](directive, name)
- inst.generate(**kw)
- assert directive.result
- # print '\n'.join(directive.result)
- assert app._warning.getvalue() == ''
- del directive.result[:]
-
- def assert_processes(items, objtype, name, **kw):
- del processed_docstrings[:]
- del processed_signatures[:]
- assert_works(objtype, name, **kw)
- assert set(processed_docstrings) | set(processed_signatures) == set(items)
-
- def assert_result_contains(item, objtype, name, **kw):
- inst = app.registry.documenters[objtype](directive, name)
- inst.generate(**kw)
- # print '\n'.join(directive.result)
- assert app._warning.getvalue() == ''
- assert item in directive.result
- del directive.result[:]
-
- def assert_order(items, objtype, name, member_order, **kw):
- inst = app.registry.documenters[objtype](directive, name)
- inst.options.member_order = member_order
- inst.generate(**kw)
- assert app._warning.getvalue() == ''
- items = list(reversed(items))
- lineiter = iter(directive.result)
- # for line in directive.result:
- # if line.strip():
- # print repr(line)
- while items:
- item = items.pop()
- for line in lineiter:
- if line == item:
- break
- else: # ran out of items!
- assert False, ('item %r not found in result or not in the '
- ' correct order' % item)
- del directive.result[:]
-
- options.members = []
-
- # no module found?
- assert_warns("import for autodocumenting 'foobar'",
- 'function', 'foobar', more_content=None)
- # importing
- assert_warns("failed to import module 'test_foobar'",
- 'module', 'test_foobar', more_content=None)
- # attributes missing
- assert_warns("failed to import function 'foobar' from module 'util'",
- 'function', 'util.foobar', more_content=None)
- # method missing
- assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc_py35';",
- 'method', 'test_autodoc_py35.Class.foobar', more_content=None)
-
- # test auto and given content mixing
- directive.env.ref_context['py:module'] = 'test_autodoc_py35'
- assert_result_contains(' Function.', 'method', 'Class.meth')
- add_content = ViewList()
- add_content.append('Content.', '', 0)
- assert_result_contains(' Function.', 'method',
- 'Class.meth', more_content=add_content)
- assert_result_contains(' Content.', 'method',
- 'Class.meth', more_content=add_content)
-
- # test check_module
- inst = FunctionDocumenter(directive, 'add_documenter')
- inst.generate(check_module=True)
- assert len(directive.result) == 0
-
- # assert that exceptions can be documented
- assert_works('exception', 'test_autodoc_py35.CustomEx', all_members=True)
- assert_works('exception', 'test_autodoc_py35.CustomEx')
-
- # test diverse inclusion settings for members
- should = [('class', 'test_autodoc_py35.Class')]
- assert_processes(should, 'class', 'Class')
- should.extend([('method', 'test_autodoc_py35.Class.meth')])
- options.members = ['meth']
- options.exclude_members = set(['excludemeth'])
- assert_processes(should, 'class', 'Class')
- should.extend([('attribute', 'test_autodoc_py35.Class.prop'),
- ('attribute', 'test_autodoc_py35.Class.descr'),
- ('attribute', 'test_autodoc_py35.Class.attr'),
- ('attribute', 'test_autodoc_py35.Class.docattr'),
- ('attribute', 'test_autodoc_py35.Class.udocattr'),
- ('attribute', 'test_autodoc_py35.Class.mdocattr'),
- ('attribute', 'test_autodoc_py35.Class.inst_attr_comment'),
- ('attribute', 'test_autodoc_py35.Class.inst_attr_inline'),
- ('attribute', 'test_autodoc_py35.Class.inst_attr_string'),
- ('method', 'test_autodoc_py35.Class.moore'),
- ])
- if six.PY3 and sys.version_info[:2] >= (3, 5):
- should.extend([
- ('method', 'test_autodoc_py35.Class.do_coroutine'),
- ])
- options.members = ALL
- assert_processes(should, 'class', 'Class')
- options.undoc_members = True
- should.extend((('attribute', 'test_autodoc_py35.Class.skipattr'),
- ('method', 'test_autodoc_py35.Class.undocmeth'),
- ('method', 'test_autodoc_py35.Class.roger')))
- assert_processes(should, 'class', 'Class')
- options.inherited_members = True
- should.append(('method', 'test_autodoc_py35.Class.inheritedmeth'))
- assert_processes(should, 'class', 'Class')
-
- # test special members
- options.special_members = ['__special1__']
- should.append(('method', 'test_autodoc_py35.Class.__special1__'))
- assert_processes(should, 'class', 'Class')
- options.special_members = ALL
- should.append(('method', 'test_autodoc_py35.Class.__special2__'))
- assert_processes(should, 'class', 'Class')
- options.special_members = False
-
-
-# --- generate fodder ------------
-__all__ = ['Class']
-
-#: documentation for the integer
-integer = 1
-
-
-class CustomEx(Exception):
- """My custom exception."""
-
- def f(self):
- """Exception method."""
-
-
-class CustomDataDescriptor(object):
- """Descriptor class docstring."""
-
- def __init__(self, doc):
- self.__doc__ = doc
-
- def __get__(self, obj, type=None):
- if obj is None:
- return self
- return 42
-
- def meth(self):
- """Function."""
- return "The Answer"
-
-
-def _funky_classmethod(name, b, c, d, docstring=None):
- """Generates a classmethod for a class from a template by filling out
- some arguments."""
- def template(cls, a, b, c, d=4, e=5, f=6):
- return a, b, c, d, e, f
- from functools import partial
- function = partial(template, b=b, c=c, d=d)
- function.__name__ = name
- function.__doc__ = docstring
- return classmethod(function)
-
-
-class Base(object):
- def inheritedmeth(self):
- """Inherited function."""
-
-
-if six.PY3 and sys.version_info[:2] >= (3, 5):
- async def _other_coro_func():
- return "run"
-
-
-class Class(Base):
- """Class to document."""
-
- descr = CustomDataDescriptor("Descriptor instance docstring.")
-
- def meth(self):
- """Function."""
-
- def undocmeth(self):
- pass
-
- def skipmeth(self):
- """Method that should be skipped."""
-
- def excludemeth(self):
- """Method that should be excluded."""
-
- # should not be documented
- skipattr = 'foo'
-
- #: should be documented -- süß
- attr = 'bar'
-
- @property
- def prop(self):
- """Property."""
-
- docattr = 'baz'
- """should likewise be documented -- süß"""
-
- udocattr = 'quux'
- u"""should be documented as well - süß"""
-
- # initialized to any class imported from another module
- mdocattr = StringIO()
- """should be documented as well - süß"""
-
- roger = _funky_classmethod("roger", 2, 3, 4)
-
- moore = _funky_classmethod("moore", 9, 8, 7,
- docstring="moore(a, e, f) -> happiness")
-
- def __init__(self, arg):
- self.inst_attr_inline = None #: an inline documented instance attr
- #: a documented instance attribute
- self.inst_attr_comment = None
- self.inst_attr_string = None
- """a documented instance attribute"""
-
- def __special1__(self):
- """documented special method"""
-
- def __special2__(self):
- # undocumented special method
- pass
-
- if six.PY3 and sys.version_info[:2] >= (3, 5):
-
- async def do_coroutine(self):
- """A documented coroutine function"""
- attr_coro_result = await _other_coro_func() # NOQA
diff --git a/tests/roots/test-api-set-translator/conf.py b/tests/roots/test-api-set-translator/conf.py
index c1ad24e56..9a7312d65 100644
--- a/tests/roots/test-api-set-translator/conf.py
+++ b/tests/roots/test-api-set-translator/conf.py
@@ -11,7 +11,6 @@ from sphinx.writers.latex import LaTeXTranslator
from sphinx.writers.manpage import ManualPageTranslator
from sphinx.writers.texinfo import TexinfoTranslator
from sphinx.writers.text import TextTranslator
-from sphinx.writers.websupport import WebSupportTranslator
project = 'test'
@@ -54,10 +53,6 @@ class ConfTextTranslator(TextTranslator):
pass
-class ConfWebSupportTranslator(WebSupportTranslator):
- pass
-
-
class ConfXMLTranslator(XMLTranslator):
pass
@@ -76,6 +71,5 @@ def setup(app):
app.set_translator('man', ConfManualPageTranslator)
app.set_translator('texinfo', ConfTexinfoTranslator)
app.set_translator('text', ConfTextTranslator)
- app.set_translator('websupport', ConfWebSupportTranslator)
app.set_translator('xml', ConfXMLTranslator)
app.set_translator('pseudoxml', ConfPseudoXMLTranslator)
diff --git a/tests/roots/test-autosummary/contents.rst b/tests/roots/test-autosummary/index.rst
index 5ddc4bd40..5ddc4bd40 100644
--- a/tests/roots/test-autosummary/contents.rst
+++ b/tests/roots/test-autosummary/index.rst
diff --git a/tests/roots/test-build-text/conf.py b/tests/roots/test-build-text/conf.py
index 23d0ae840..fd9eefbf6 100644
--- a/tests/roots/test-build-text/conf.py
+++ b/tests/roots/test-build-text/conf.py
@@ -1,3 +1,2 @@
-master_doc = 'contents'
source_suffix = '.txt'
exclude_patterns = ['_build']
diff --git a/tests/roots/test-build-text/contents.txt b/tests/roots/test-build-text/index.txt
index ca9f8dc6c..ca9f8dc6c 100644
--- a/tests/roots/test-build-text/contents.txt
+++ b/tests/roots/test-build-text/index.txt
diff --git a/tests/roots/test-circular/contents.rst b/tests/roots/test-circular/index.rst
index 294e674dd..294e674dd 100644
--- a/tests/roots/test-circular/contents.rst
+++ b/tests/roots/test-circular/index.rst
diff --git a/tests/roots/test-circular/sub.rst b/tests/roots/test-circular/sub.rst
index 070c39743..cebfd6587 100644
--- a/tests/roots/test-circular/sub.rst
+++ b/tests/roots/test-circular/sub.rst
@@ -1,3 +1,3 @@
.. toctree::
- contents
+ index
diff --git a/tests/roots/test-correct-year/contents.rst b/tests/roots/test-correct-year/index.rst
index 938dfd503..938dfd503 100644
--- a/tests/roots/test-correct-year/contents.rst
+++ b/tests/roots/test-correct-year/index.rst
diff --git a/tests/roots/test-directive-only/contents.rst b/tests/roots/test-directive-only/index.rst
index 80ec00313..80ec00313 100644
--- a/tests/roots/test-directive-only/contents.rst
+++ b/tests/roots/test-directive-only/index.rst
diff --git a/tests/roots/test-docutilsconf/contents.txt b/tests/roots/test-docutilsconf/index.txt
index b20204e61..b20204e61 100644
--- a/tests/roots/test-docutilsconf/contents.txt
+++ b/tests/roots/test-docutilsconf/index.txt
diff --git a/tests/roots/test-ext-autodoc/contents.rst b/tests/roots/test-ext-autodoc/index.rst
index ce4302204..ce4302204 100644
--- a/tests/roots/test-ext-autodoc/contents.rst
+++ b/tests/roots/test-ext-autodoc/index.rst
diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py
index 9bb50bca9..c97269d35 100644
--- a/tests/roots/test-ext-autodoc/target/__init__.py
+++ b/tests/roots/test-ext-autodoc/target/__init__.py
@@ -4,7 +4,7 @@ import enum
from six import StringIO, add_metaclass
-from sphinx.ext.autodoc import add_documenter # NOQA
+from sphinx.util import save_traceback # NOQA
__all__ = ['Class']
diff --git a/tests/roots/test-ext-autodoc/target/coroutine.py b/tests/roots/test-ext-autodoc/target/coroutine.py
new file mode 100644
index 000000000..b3223a820
--- /dev/null
+++ b/tests/roots/test-ext-autodoc/target/coroutine.py
@@ -0,0 +1,8 @@
+class AsyncClass:
+ async def do_coroutine(self):
+ """A documented coroutine function"""
+ attr_coro_result = await _other_coro_func() # NOQA
+
+
+async def _other_coro_func():
+ return "run"
diff --git a/tests/roots/test-ext-autosummary/contents.rst b/tests/roots/test-ext-autosummary/index.rst
index fc84927bb..fc84927bb 100644
--- a/tests/roots/test-ext-autosummary/contents.rst
+++ b/tests/roots/test-ext-autosummary/index.rst
diff --git a/tests/roots/test-gettext-template/contents.rst b/tests/roots/test-gettext-template/index.rst
index e69de29bb..e69de29bb 100644
--- a/tests/roots/test-gettext-template/contents.rst
+++ b/tests/roots/test-gettext-template/index.rst
diff --git a/tests/roots/test-inheritance/contents.rst b/tests/roots/test-inheritance/index.rst
index db4fbacb8..db4fbacb8 100644
--- a/tests/roots/test-inheritance/contents.rst
+++ b/tests/roots/test-inheritance/index.rst
diff --git a/tests/roots/test-intl/_templates/index.html b/tests/roots/test-intl/_templates/contents.html
index d730545d1..d730545d1 100644
--- a/tests/roots/test-intl/_templates/index.html
+++ b/tests/roots/test-intl/_templates/contents.html
diff --git a/tests/roots/test-intl/conf.py b/tests/roots/test-intl/conf.py
index aafd9ba79..0306ff38e 100644
--- a/tests/roots/test-intl/conf.py
+++ b/tests/roots/test-intl/conf.py
@@ -4,7 +4,7 @@ project = 'Sphinx intl <Tests>'
source_suffix = '.txt'
keep_warnings = True
templates_path = ['_templates']
-html_additional_pages = {'index': 'index.html'}
+html_additional_pages = {'contents': 'contents.html'}
release = version = '2013.120'
gettext_additional_targets = ['index']
exclude_patterns = ['_build']
diff --git a/tests/roots/test-intl/contents.po b/tests/roots/test-intl/index.po
index 76ef049f0..76ef049f0 100644
--- a/tests/roots/test-intl/contents.po
+++ b/tests/roots/test-intl/index.po
diff --git a/tests/roots/test-intl/contents.txt b/tests/roots/test-intl/index.txt
index b818e99c7..cd63b5ec3 100644
--- a/tests/roots/test-intl/contents.txt
+++ b/tests/roots/test-intl/index.txt
@@ -10,7 +10,7 @@ CONTENTS
:numbered:
:caption: Table of Contents
- subdir/contents
+ subdir/index
bom
warnings
footnote
diff --git a/tests/roots/test-intl/role_xref.po b/tests/roots/test-intl/role_xref.po
index 5b6d114c0..81ee22c6e 100644
--- a/tests/roots/test-intl/role_xref.po
+++ b/tests/roots/test-intl/role_xref.po
@@ -19,8 +19,8 @@ msgstr ""
msgid "i18n role xref"
msgstr "I18N ROCK'N ROLE XREF"
-msgid "link to :term:`Some term`, :ref:`i18n-role-xref`, :doc:`contents`."
-msgstr "LINK TO :ref:`i18n-role-xref`, :doc:`contents`, :term:`SOME NEW TERM`."
+msgid "link to :term:`Some term`, :ref:`i18n-role-xref`, :doc:`index`."
+msgstr "LINK TO :ref:`i18n-role-xref`, :doc:`index`, :term:`SOME NEW TERM`."
msgid "same type links"
msgstr "SAME TYPE LINKS"
@@ -31,8 +31,8 @@ msgstr "LINK TO :term:`SOME OTHER NEW TERM` AND :term:`SOME NEW TERM`."
msgid "link to :ref:`i18n-role-xref` and :ref:`same-type-links`."
msgstr "LINK TO :ref:`same-type-links` AND :ref:`i18n-role-xref`."
-msgid "link to :doc:`contents` and :doc:`glossary_terms`."
-msgstr "LINK TO :doc:`glossary_terms` AND :doc:`contents`."
+msgid "link to :doc:`index` and :doc:`glossary_terms`."
+msgstr "LINK TO :doc:`glossary_terms` AND :doc:`index`."
msgid "link to :option:`-m` and :option:`--module`."
msgstr "LINK TO :option:`--module` AND :option:`-m`."
diff --git a/tests/roots/test-intl/role_xref.txt b/tests/roots/test-intl/role_xref.txt
index b3d42d127..875af4667 100644
--- a/tests/roots/test-intl/role_xref.txt
+++ b/tests/roots/test-intl/role_xref.txt
@@ -5,7 +5,7 @@
i18n role xref
==============
-link to :term:`Some term`, :ref:`i18n-role-xref`, :doc:`contents`.
+link to :term:`Some term`, :ref:`i18n-role-xref`, :doc:`index`.
.. _same-type-links:
@@ -16,7 +16,7 @@ link to :term:`Some term` and :term:`Some other term`.
link to :ref:`i18n-role-xref` and :ref:`same-type-links`.
-link to :doc:`contents` and :doc:`glossary_terms`.
+link to :doc:`index` and :doc:`glossary_terms`.
link to :option:`-m` and :option:`--module`.
diff --git a/tests/roots/test-intl/subdir/contents.txt b/tests/roots/test-intl/subdir/index.txt
index 7578ce387..7578ce387 100644
--- a/tests/roots/test-intl/subdir/contents.txt
+++ b/tests/roots/test-intl/subdir/index.txt
diff --git a/tests/roots/test-numbered-circular/contents.rst b/tests/roots/test-numbered-circular/index.rst
index c3129cd48..c3129cd48 100644
--- a/tests/roots/test-numbered-circular/contents.rst
+++ b/tests/roots/test-numbered-circular/index.rst
diff --git a/tests/roots/test-numbered-circular/sub.rst b/tests/roots/test-numbered-circular/sub.rst
index 070c39743..cebfd6587 100644
--- a/tests/roots/test-numbered-circular/sub.rst
+++ b/tests/roots/test-numbered-circular/sub.rst
@@ -1,3 +1,3 @@
.. toctree::
- contents
+ index
diff --git a/tests/roots/test-root/autodoc_target.py b/tests/roots/test-root/autodoc_target.py
index 62ca9f691..4f14afc03 100644
--- a/tests/roots/test-root/autodoc_target.py
+++ b/tests/roots/test-root/autodoc_target.py
@@ -4,8 +4,6 @@ import enum
from six import StringIO, add_metaclass
-from sphinx.ext.autodoc import add_documenter # NOQA
-
__all__ = ['Class']
diff --git a/tests/roots/test-root/conf.py b/tests/roots/test-root/conf.py
index d5029a776..42b8295a2 100644
--- a/tests/roots/test-root/conf.py
+++ b/tests/roots/test-root/conf.py
@@ -18,7 +18,6 @@ jsmath_path = 'dummy.js'
templates_path = ['_templates']
-master_doc = 'contents'
source_suffix = ['.txt', '.add', '.foo']
project = 'Sphinx <Tests>'
@@ -37,8 +36,7 @@ rst_epilog = '.. |subst| replace:: global substitution'
html_sidebars = {'**': ['localtoc.html', 'relations.html', 'sourcelink.html',
'customsb.html', 'searchbox.html'],
- 'contents': ['contentssb.html', 'localtoc.html',
- 'globaltoc.html']}
+ 'index': ['contentssb.html', 'localtoc.html', 'globaltoc.html']}
html_style = 'default.css'
html_last_updated_fmt = '%b %d, %Y'
html_context = {'hckey': 'hcval', 'hckey_co': 'wrong_hcval_co'}
@@ -49,19 +47,19 @@ applehelp_bundle_id = 'org.sphinx-doc.Sphinx.help'
applehelp_disable_external_tools = True
latex_documents = [
- ('contents', 'SphinxTests.tex', 'Sphinx Tests Documentation',
+ ('index', 'SphinxTests.tex', 'Sphinx Tests Documentation',
'Georg Brandl \\and someone else', 'manual'),
]
latex_additional_files = ['svgimg.svg']
texinfo_documents = [
- ('contents', 'SphinxTests', 'Sphinx Tests',
+ ('index', 'SphinxTests', 'Sphinx Tests',
'Georg Brandl \\and someone else', 'Sphinx Testing', 'Miscellaneous'),
]
man_pages = [
- ('contents', 'SphinxTests', 'Sphinx Tests Documentation',
+ ('index', 'SphinxTests', 'Sphinx Tests Documentation',
'Georg Brandl and someone else', 1),
]
diff --git a/tests/roots/test-root/contents.txt b/tests/roots/test-root/index.txt
index d5ff24115..d5ff24115 100644
--- a/tests/roots/test-root/contents.txt
+++ b/tests/roots/test-root/index.txt
diff --git a/tests/roots/test-setup/doc/contents.txt b/tests/roots/test-setup/doc/index.txt
index 56960f53e..56960f53e 100644
--- a/tests/roots/test-setup/doc/contents.txt
+++ b/tests/roots/test-setup/doc/index.txt
diff --git a/tests/roots/test-templating/contents.txt b/tests/roots/test-templating/index.txt
index 04a40e21c..04a40e21c 100644
--- a/tests/roots/test-templating/contents.txt
+++ b/tests/roots/test-templating/index.txt
diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py
index 18ef3b584..f469a6be3 100644
--- a/tests/test_autodoc.py
+++ b/tests/test_autodoc.py
@@ -17,10 +17,9 @@ from warnings import catch_warnings
import pytest
from docutils.statemachine import ViewList
-from six import PY3
from sphinx.ext.autodoc import (
- AutoDirective, ModuleLevelDocumenter, cut_lines, between, ALL,
+ ModuleLevelDocumenter, cut_lines, between, ALL,
merge_autodoc_default_flags, Options
)
from sphinx.ext.autodoc.directive import DocumenterBridge, process_documenter_options
@@ -30,11 +29,6 @@ from sphinx.util.docutils import LoggingReporter
app = None
-if PY3:
- ROGER_METHOD = ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)'
-else:
- ROGER_METHOD = ' .. py:classmethod:: Class.roger(a, e=5, f=6)'
-
IS_PYPY = platform.python_implementation() == 'PyPy'
@@ -112,7 +106,7 @@ def setup_test():
yield
- AutoDirective._special_attrgetters.clear()
+ app.registry.autodoc_attrgettrs.clear()
processed_docstrings = []
@@ -216,7 +210,7 @@ def test_format_signature():
class D:
pass
- class E(object):
+ class E:
pass
# no signature for classes without __init__
for C in (D, E):
@@ -226,7 +220,7 @@ def test_format_signature():
def __init__(self, a, b=None):
pass
- class G(F, object):
+ class G(F):
pass
for C in (F, G):
assert formatsig('class', 'C', C, None, None) == '(a, b=None)'
@@ -243,7 +237,7 @@ def test_format_signature():
some docstring for __init__.
'''
- class G2(F2, object):
+ class G2(F2):
pass
assert formatsig('class', 'F2', F2, None, None) == \
@@ -399,7 +393,7 @@ def test_get_doc():
assert getdocl('class', E) == ['Class docstring', '', 'Init docstring']
# class does not have __init__ method
- class F(object):
+ class F:
"""Class docstring"""
# docstring in the __init__ method of base class will be discard
@@ -413,7 +407,7 @@ def test_get_doc():
assert getdocl('class', F) == ['Class docstring']
# class has __init__ method with no docstring
- class G(object):
+ class G:
"""Class docstring"""
def __init__(self):
pass
@@ -566,7 +560,7 @@ def test_attrgetter_using():
getattr_spy.append((obj, name))
return None
return getattr(obj, name, *defargs)
- AutoDirective._special_attrgetters[type] = special_getattr
+ app.add_autodoc_attrgetter(type, special_getattr)
del getattr_spy[:]
inst = app.registry.documenters[objtype](directive, name)
@@ -722,7 +716,7 @@ def test_autodoc_undoc_members(app):
' .. py:method:: Class.meth()',
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
' .. py:attribute:: Class.prop',
- ROGER_METHOD,
+ ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)',
' .. py:attribute:: Class.skipattr',
' .. py:method:: Class.skipmeth()',
' .. py:attribute:: Class.udocattr',
@@ -752,7 +746,7 @@ def test_autodoc_imported_members(app):
"imported-members": None,
"ignore-module-all": None}
actual = do_autodoc(app, 'module', 'target', options)
- assert '.. py:function:: add_documenter(cls)' in actual
+ assert '.. py:function:: save_traceback(app)' in actual
@pytest.mark.sphinx('html', testroot='ext-autodoc')
@@ -802,7 +796,7 @@ def test_autodoc_special_members(app):
' .. py:method:: Class.meth()',
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
' .. py:attribute:: Class.prop',
- ROGER_METHOD,
+ ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)',
' .. py:attribute:: Class.skipattr',
' .. py:method:: Class.skipmeth()',
' .. py:attribute:: Class.udocattr',
@@ -875,11 +869,6 @@ def test_autodoc_subclass_of_builtin_class(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_inner_class(app):
- if PY3:
- builtins = ' alias of :class:`builtins.dict`'
- else:
- builtins = ' alias of :class:`__builtin__.dict`'
-
options = {"members": None}
actual = do_autodoc(app, 'class', 'target.Outer', options)
assert list(actual) == [
@@ -905,7 +894,7 @@ def test_autodoc_inner_class(app):
' .. py:attribute:: Outer.factory',
' :module: target',
' ',
- builtins
+ ' alias of :class:`builtins.dict`'
]
actual = do_autodoc(app, 'class', 'target.Outer.Inner', options)
@@ -974,7 +963,7 @@ def test_autodoc_member_order(app):
' .. py:attribute:: Class.docattr',
' .. py:attribute:: Class.udocattr',
' .. py:attribute:: Class.mdocattr',
- ROGER_METHOD,
+ ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)',
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
' .. py:attribute:: Class.inst_attr_inline',
' .. py:attribute:: Class.inst_attr_comment',
@@ -993,7 +982,7 @@ def test_autodoc_member_order(app):
' .. py:method:: Class.excludemeth()',
' .. py:method:: Class.meth()',
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
- ROGER_METHOD,
+ ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)',
' .. py:method:: Class.skipmeth()',
' .. py:method:: Class.undocmeth()',
' .. py:attribute:: Class._private_inst_attr',
@@ -1028,7 +1017,7 @@ def test_autodoc_member_order(app):
' .. py:method:: Class.meth()',
' .. py:classmethod:: Class.moore(a, e, f) -> happiness',
' .. py:attribute:: Class.prop',
- ROGER_METHOD,
+ ' .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)',
' .. py:attribute:: Class.skipattr',
' .. py:method:: Class.skipmeth()',
' .. py:attribute:: Class.udocattr',
@@ -1426,8 +1415,24 @@ def test_partialfunction():
assert call_autodoc('module', 'target.partialfunction') == expected
-@pytest.mark.skipif(sys.version_info < (3, 4),
- reason='functools.partialmethod is available on py34 or above')
+@pytest.mark.usefixtures('setup_test')
+def test_coroutine():
+ options = {"members": None}
+ actual = do_autodoc(app, 'class', 'target.coroutine.AsyncClass', options)
+ assert list(actual) == [
+ '',
+ '.. py:class:: AsyncClass',
+ ' :module: target.coroutine',
+ '',
+ ' ',
+ ' .. py:method:: AsyncClass.do_coroutine()',
+ ' :module: target.coroutine',
+ ' ',
+ ' A documented coroutine function',
+ ' '
+ ]
+
+
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_partialmethod(app):
expected = [
diff --git a/tests/test_build.py b/tests/test_build.py
index 47d76b2a2..3c181dda2 100644
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -33,11 +33,6 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
# If supported, build in a non-ASCII source dir
test_name = u'\u65e5\u672c\u8a9e'
basedir = sphinx_test_tempdir / request.node.originalname
- # Windows with versions prior to 3.2 (I think) doesn't support unicode on system path
- # so we force a non-unicode path in that case
- if (sys.platform == "win32" and
- not (sys.version_info.major >= 3 and sys.version_info.minor >= 2)):
- return basedir / 'all'
try:
srcdir = basedir / test_name
if not srcdir.exists():
@@ -51,7 +46,7 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
=======================
"""))
- master_doc = srcdir / 'contents.txt'
+ master_doc = srcdir / 'index.txt'
master_doc.write_text(master_doc.text() + dedent(u"""
.. toctree::
@@ -93,10 +88,10 @@ def test_circular_toctree(app, status, warning):
warnings = warning.getvalue()
assert (
'circular toctree references detected, ignoring: '
- 'sub <- contents <- sub') in warnings
+ 'sub <- index <- sub') in warnings
assert (
'circular toctree references detected, ignoring: '
- 'contents <- sub <- contents') in warnings
+ 'index <- sub <- index') in warnings
@pytest.mark.sphinx(buildername='text', testroot='numbered-circular')
@@ -105,10 +100,10 @@ def test_numbered_circular_toctree(app, status, warning):
warnings = warning.getvalue()
assert (
'circular toctree references detected, ignoring: '
- 'sub <- contents <- sub') in warnings
+ 'sub <- index <- sub') in warnings
assert (
'circular toctree references detected, ignoring: '
- 'contents <- sub <- contents') in warnings
+ 'index <- sub <- index') in warnings
@pytest.mark.sphinx(buildername='dummy', testroot='images')
diff --git a/tests/test_build_applehelp.py b/tests/test_build_applehelp.py
index ed0022ce1..9c5d46941 100644
--- a/tests/test_build_applehelp.py
+++ b/tests/test_build_applehelp.py
@@ -17,12 +17,6 @@ import pytest
from sphinx.testing.path import path
-# Use plistlib.load in 3.4 and above
-try:
- read_plist = plistlib.load
-except AttributeError:
- read_plist = plistlib.readPlist
-
def check_structure(outdir):
contentsdir = outdir / 'Contents'
@@ -30,7 +24,7 @@ def check_structure(outdir):
assert (contentsdir / 'Info.plist').isfile()
with open(contentsdir / 'Info.plist', 'rb') as f:
- plist = read_plist(f)
+ plist = plistlib.load(f)
assert plist
assert len(plist)
assert plist.get('CFBundleIdentifier', None) == 'org.sphinx-doc.Sphinx.help'
diff --git a/tests/test_build_epub.py b/tests/test_build_epub.py
index f9872f28c..0d45cd289 100644
--- a/tests/test_build_epub.py
+++ b/tests/test_build_epub.py
@@ -28,7 +28,7 @@ def runnable(command):
return p.returncode == 0
-class EPUBElementTree(object):
+class EPUBElementTree:
"""Test helper for content.opf and toc.ncx"""
namespaces = {
'idpf': 'http://www.idpf.org/2007/opf',
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index aae53615b..8a908b8e3 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -16,10 +16,9 @@ from itertools import cycle, chain
import pytest
from html5lib import getTreeBuilder, HTMLParser
-from six import PY3
from sphinx.errors import ConfigError
-from sphinx.testing.util import remove_unicode_literals, strip_escseq
+from sphinx.testing.util import strip_escseq
from sphinx.util.inventory import InventoryFile
@@ -30,10 +29,10 @@ ENV_WARNINGS = """\
%(root)s/autodoc_fodder.py:docstring of autodoc_fodder.MarkupError:\\d+: \
WARNING: Explicit markup ends without a blank line; unexpected unindent.
%(root)s/index.rst:\\d+: WARNING: Encoding 'utf-8-sig' used for reading included \
-file u'%(root)s/wrongenc.inc' seems to be wrong, try giving an :encoding: option
+file '%(root)s/wrongenc.inc' seems to be wrong, try giving an :encoding: option
%(root)s/index.rst:\\d+: WARNING: image file not readable: foo.png
%(root)s/index.rst:\\d+: WARNING: download file not readable: %(root)s/nonexisting.png
-%(root)s/index.rst:\\d+: WARNING: invalid single index entry u''
+%(root)s/index.rst:\\d+: WARNING: invalid single index entry ''
%(root)s/undecodable.rst:\\d+: WARNING: undecodable source characters, replacing \
with "\\?": b?'here: >>>(\\\\|/)xbb<<<((\\\\|/)r)?'
"""
@@ -45,10 +44,6 @@ HTML_WARNINGS = ENV_WARNINGS + """\
%(root)s/index.rst:\\d+: WARNING: Could not lex literal_block as "c". Highlighting skipped.
"""
-if PY3:
- ENV_WARNINGS = remove_unicode_literals(ENV_WARNINGS)
- HTML_WARNINGS = remove_unicode_literals(HTML_WARNINGS)
-
etree_cache = {}
@@ -248,7 +243,7 @@ def test_html_warnings(app, warning):
# footnote reference
(".//a[@class='footnote-reference']", r'\[1\]'),
# created by reference lookup
- (".//a[@href='contents.html#ref1']", ''),
+ (".//a[@href='index.html#ref1']", ''),
# ``seealso`` directive
(".//div/p[@class='first admonition-title']", 'See also'),
# a ``hlist`` directive
@@ -347,7 +342,7 @@ def test_html_warnings(app, warning):
(".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'-p'),
],
- 'contents.html': [
+ 'index.html': [
(".//meta[@name='hc'][@content='hcval']", ''),
(".//meta[@name='hc_co'][@content='hcval_co']", ''),
(".//td[@class='label']", r'\[Ref1\]'),
diff --git a/tests/test_build_html5.py b/tests/test_build_html5.py
index e4c51eaea..fc2c7e8eb 100644
--- a/tests/test_build_html5.py
+++ b/tests/test_build_html5.py
@@ -157,7 +157,7 @@ def cached_etree_parse():
# footnote reference
(".//a[@class='footnote-reference brackets']", r'1'),
# created by reference lookup
- (".//a[@href='contents.html#ref1']", ''),
+ (".//a[@href='index.html#ref1']", ''),
# ``seealso`` directive
(".//div/p[@class='admonition-title']", 'See also'),
# a ``hlist`` directive
@@ -249,7 +249,7 @@ def cached_etree_parse():
(".//a[@class='reference internal'][@href='#cmdoption-git-commit-p']/code/span",
'-p'),
],
- 'contents.html': [
+ 'index.html': [
(".//meta[@name='hc'][@content='hcval']", ''),
(".//meta[@name='hc_co'][@content='hcval_co']", ''),
(".//dt[@class='label']/span[@class='brackets']", r'Ref1'),
diff --git a/tests/test_build_htmlhelp.py b/tests/test_build_htmlhelp.py
new file mode 100644
index 000000000..6eb7e3689
--- /dev/null
+++ b/tests/test_build_htmlhelp.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+"""
+ test_build_htmlhelp
+ ~~~~~~~~~~~~~~~~~~~
+
+ Test the HTML Help builder and check output against XPath.
+
+ :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+import pytest
+
+
+@pytest.mark.sphinx('htmlhelp', testroot='basic')
+def test_default_htmlhelp_file_suffix(app, warning):
+ assert app.builder.out_suffix == '.html'
+
+
+@pytest.mark.sphinx('htmlhelp', testroot='basic',
+ confoverrides={'htmlhelp_file_suffix': '.htm'})
+def test_htmlhelp_file_suffix(app, warning):
+ assert app.builder.out_suffix == '.htm'
diff --git a/tests/test_build_latex.py b/tests/test_build_latex.py
index b2ae24c52..5da8a90ee 100644
--- a/tests/test_build_latex.py
+++ b/tests/test_build_latex.py
@@ -17,11 +17,10 @@ from shutil import copyfile
from subprocess import Popen, PIPE
import pytest
-from six import PY3
from test_build_html import ENV_WARNINGS
from sphinx.errors import SphinxError
-from sphinx.testing.util import remove_unicode_literals, strip_escseq
+from sphinx.testing.util import strip_escseq
from sphinx.util import docutils
from sphinx.util.osutil import cd, ensuredir
from sphinx.writers.latex import LaTeXTranslator
@@ -40,9 +39,6 @@ LATEX_WARNINGS = ENV_WARNINGS + """\
%(root)s/index.rst:\\d+: WARNING: Could not lex literal_block as "c". Highlighting skipped.
"""
-if PY3:
- LATEX_WARNINGS = remove_unicode_literals(LATEX_WARNINGS)
-
# only run latex if all needed packages are there
def kpsetest(*filenames):
@@ -112,6 +108,7 @@ def skip_if_stylefiles_notfound(testfunc):
def test_build_latex_doc(app, status, warning, engine, docclass):
app.config.latex_engine = engine
app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,)
+ app.builder.init_context()
LaTeXTranslator.ignore_missing_images = True
app.builder.build_all()
diff --git a/tests/test_build_texinfo.py b/tests/test_build_texinfo.py
index b1fd8c2a9..a1af11df7 100644
--- a/tests/test_build_texinfo.py
+++ b/tests/test_build_texinfo.py
@@ -15,10 +15,9 @@ import re
from subprocess import Popen, PIPE
import pytest
-from six import PY3
from test_build_html import ENV_WARNINGS
-from sphinx.testing.util import remove_unicode_literals, strip_escseq
+from sphinx.testing.util import strip_escseq
from sphinx.writers.texinfo import TexinfoTranslator
@@ -30,9 +29,6 @@ TEXINFO_WARNINGS = ENV_WARNINGS + """\
\\['application/pdf', 'image/svg\\+xml'\\] \\(svgimg.\\*\\)
"""
-if PY3:
- TEXINFO_WARNINGS = remove_unicode_literals(TEXINFO_WARNINGS)
-
@pytest.mark.sphinx('texinfo', testroot='warnings', freshenv=True)
def test_texinfo_warnings(app, status, warning):
diff --git a/tests/test_build_text.py b/tests/test_build_text.py
index f89187c85..b9e0e61a1 100644
--- a/tests/test_build_text.py
+++ b/tests/test_build_text.py
@@ -116,8 +116,8 @@ def test_list_items_in_admonition(app, status, warning):
@with_text_app()
def test_secnums(app, status, warning):
app.builder.build_all()
- contents = (app.outdir / 'contents.txt').text(encoding='utf8')
- lines = contents.splitlines()
+ index = (app.outdir / 'index.txt').text(encoding='utf8')
+ lines = index.splitlines()
assert lines[0] == "* 1. Section A"
assert lines[1] == ""
assert lines[2] == "* 2. Section B"
@@ -142,8 +142,8 @@ def test_secnums(app, status, warning):
app.config.text_secnumber_suffix = " "
app.builder.build_all()
- contents = (app.outdir / 'contents.txt').text(encoding='utf8')
- lines = contents.splitlines()
+ index = (app.outdir / 'index.txt').text(encoding='utf8')
+ lines = index.splitlines()
assert lines[0] == "* 1 Section A"
assert lines[1] == ""
assert lines[2] == "* 2 Section B"
@@ -168,8 +168,8 @@ def test_secnums(app, status, warning):
app.config.text_add_secnumbers = False
app.builder.build_all()
- contents = (app.outdir / 'contents.txt').text(encoding='utf8')
- lines = contents.splitlines()
+ index = (app.outdir / 'index.txt').text(encoding='utf8')
+ lines = index.splitlines()
assert lines[0] == "* Section A"
assert lines[1] == ""
assert lines[2] == "* Section B"
diff --git a/tests/test_builder.py b/tests/test_builder.py
index d58091e8d..dbc9d3dae 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -22,7 +22,7 @@ def test_incremental_reading(app):
# before second reading, add, modify and remove source files
(app.srcdir / 'new.txt').write_text('New file\n========\n')
- app.env.all_docs['contents'] = 0 # mark as modified
+ app.env.all_docs['index'] = 0 # mark as modified
(app.srcdir / 'autodoc.txt').unlink()
# second reading
@@ -31,7 +31,7 @@ def test_incremental_reading(app):
# "includes" and "images" are in there because they contain references
# to nonexisting downloadable or image files, which are given another
# chance to exist
- assert set(updated) == set(['contents', 'new', 'includes', 'images'])
+ assert set(updated) == set(['index', 'new', 'includes', 'images'])
assert 'autodoc' not in app.env.all_docs
assert 'autodoc' not in app.env.found_docs
diff --git a/tests/test_config.py b/tests/test_config.py
index 5dd05550c..f8df52863 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -11,7 +11,6 @@
"""
import mock
import pytest
-from six import PY3
import sphinx
from sphinx.config import Config, ENUM, string_classes, check_confval_types
@@ -78,7 +77,7 @@ def test_extension_values():
config = Config()
# check standard settings
- assert config.master_doc == 'contents'
+ assert config.master_doc == 'index'
# can't override it by add_config_value()
with pytest.raises(ExtensionError) as excinfo:
@@ -136,19 +135,6 @@ def test_errors_warnings(logger, tempdir):
assert cfg.project == u'Jägermeister'
assert logger.called is False
- # test the warning for bytestrings with non-ascii content
- # bytestrings with non-ascii content are a syntax error in python3 so we
- # skip the test there
- if PY3:
- return
- (tempdir / 'conf.py').write_text(
- u'# -*- coding: latin-1\nproject = "fooä"\n', encoding='latin-1')
- cfg = Config.read(tempdir, {}, None)
-
- assert logger.warning.called is False
- cfg.check_unicode()
- assert logger.warning.called is True
-
def test_errors_if_setup_is_not_callable(tempdir, make_app):
# test the error to call setup() in the config file
@@ -218,7 +204,7 @@ def test_builtin_conf(app, status, warning):
# example classes for type checking
-class A(object):
+class A:
pass
@@ -242,7 +228,7 @@ TYPECHECK_WARNINGS = [
('value8', B(), None, C(), False), # sibling type
('value9', None, None, 'foo', False), # no default or no annotations
('value10', None, None, 123, False), # no default or no annotations
- ('value11', None, [str], u'bar', False if PY3 else True), # str vs unicode
+ ('value11', None, [str], u'bar', False), # str vs unicode
('value12', 'string', None, u'bar', False), # str vs unicode
('value13', None, string_classes, 'bar', False), # string_classes
('value14', None, string_classes, u'bar', False), # string_classes
@@ -261,6 +247,27 @@ def test_check_types(logger, name, default, annotation, actual, warned):
assert logger.warning.called == warned
+TYPECHECK_WARNING_MESSAGES = [
+ ('value1', 'string', [str], ['foo', 'bar'],
+ "The config value `value1' has type `list'; expected `str'."),
+ ('value1', 'string', [str, int], ['foo', 'bar'],
+ "The config value `value1' has type `list'; expected `str' or `int'."),
+ ('value1', 'string', [str, int, tuple], ['foo', 'bar'],
+ "The config value `value1' has type `list'; expected `str', `int', or `tuple'."),
+]
+
+
+@mock.patch("sphinx.config.logger")
+@pytest.mark.parametrize("name,default,annotation,actual,message", TYPECHECK_WARNING_MESSAGES)
+def test_conf_warning_message(logger, name, default, annotation, actual, message):
+ config = Config({name: actual})
+ config.add(name, default, False, annotation or ())
+ config.init_values()
+ check_confval_types(None, config)
+ logger.warning.assert_called()
+ assert logger.warning.call_args[0][0] == message
+
+
@mock.patch("sphinx.config.logger")
def test_check_enum(logger):
config = Config()
diff --git a/tests/test_correct_year.py b/tests/test_correct_year.py
index e7501bb6a..8995cef5b 100644
--- a/tests/test_correct_year.py
+++ b/tests/test_correct_year.py
@@ -33,5 +33,5 @@ def expect_date(request, monkeypatch):
@pytest.mark.sphinx('html', testroot='correct-year')
def test_correct_year(expect_date, app):
app.build()
- content = (app.outdir / 'contents.html').text()
+ content = (app.outdir / 'index.html').text()
assert expect_date in content
diff --git a/tests/test_docutilsconf.py b/tests/test_docutilsconf.py
index 989edc6a8..65e59340f 100644
--- a/tests/test_docutilsconf.py
+++ b/tests/test_docutilsconf.py
@@ -10,7 +10,6 @@
"""
import re
-import sys
import pytest
@@ -27,7 +26,7 @@ def test_html_with_default_docutilsconf(app, status, warning):
with patch_docutils(app.confdir):
app.builder.build(['contents'])
- result = (app.outdir / 'contents.html').text(encoding='utf-8')
+ result = (app.outdir / 'index.html').text(encoding='utf-8')
assert regex_count(r'<th class="field-name">', result) == 1
assert regex_count(r'<th class="field-name" colspan="2">', result) == 1
@@ -45,7 +44,7 @@ def test_html_with_docutilsconf(app, status, warning):
with patch_docutils(app.confdir):
app.builder.build(['contents'])
- result = (app.outdir / 'contents.html').text(encoding='utf-8')
+ result = (app.outdir / 'index.html').text(encoding='utf-8')
assert regex_count(r'<th class="field-name">', result) == 0
assert regex_count(r'<th class="field-name" colspan="2">', result) == 2
@@ -82,9 +81,6 @@ def test_texinfo(app, status, warning):
@pytest.mark.sphinx('html', testroot='docutilsconf',
docutilsconf='[general]\nsource_link=true\n')
-@pytest.mark.skip(sys.platform == "win32" and
- not (sys.version_info.major >= 3 and sys.version_info.minor >= 2),
- reason="Python < 3.2 on Win32 doesn't handle non-ASCII paths right")
def test_docutils_source_link_with_nonascii_file(app, status, warning):
srcdir = path(app.srcdir)
mb_name = u'\u65e5\u672c\u8a9e'
diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py
index b8856824b..0d47f69b2 100644
--- a/tests/test_domain_cpp.py
+++ b/tests/test_domain_cpp.py
@@ -22,7 +22,7 @@ from sphinx.domains.cpp import Symbol, _max_id, _id_prefix
def parse(name, string):
- class Config(object):
+ class Config:
cpp_id_attributes = ["id_attr"]
cpp_paren_attributes = ["paren_attr"]
parser = DefinitionParser(string, None, Config())
@@ -86,7 +86,7 @@ def check(name, input, idDict, output=None):
def test_fundamental_types():
- # see http://en.cppreference.com/w/cpp/language/types
+ # see https://en.cppreference.com/w/cpp/language/types
for t, id_v2 in cppDomain._id_fundamental_v2.items():
def makeIdV1():
if t == 'decltype(auto)':
@@ -804,7 +804,7 @@ not found in `{test}`
assert result, expect
return set(result.group('classes').split())
- class RoleClasses(object):
+ class RoleClasses:
"""Collect the classes from the layout that was generated for a given role."""
def __init__(self, role, root, contents):
diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py
index 44470771d..50716f8e6 100644
--- a/tests/test_ext_autodoc.py
+++ b/tests/test_ext_autodoc.py
@@ -20,7 +20,7 @@ from sphinx import addnodes
def test_autodoc(app, status, warning):
app.builder.build_all()
- content = pickle.loads((app.doctreedir / 'contents.doctree').bytes())
+ content = pickle.loads((app.doctreedir / 'index.doctree').bytes())
assert isinstance(content[3], addnodes.desc)
assert content[3][0].astext() == 'autodoc_dummy_module.test'
assert content[3][1].astext() == 'Dummy function using dummy.*'
diff --git a/tests/test_ext_autosummary.py b/tests/test_ext_autosummary.py
index 9b98a59d1..e75fb71fd 100644
--- a/tests/test_ext_autosummary.py
+++ b/tests/test_ext_autosummary.py
@@ -10,7 +10,7 @@
"""
import pytest
-from six import iteritems, StringIO
+from six import StringIO
from sphinx.ext.autosummary import mangle_signature, import_by_name, extract_summary
from sphinx.testing.util import etree_parse
@@ -140,7 +140,7 @@ def test_get_items_summary(make_app, app_params):
'C.prop_attr2': 'This is a attribute docstring',
'C.C2': 'This is a nested inner class docstring',
}
- for key, expected in iteritems(expected_values):
+ for key, expected in expected_values.items():
assert autosummary_items[key][2] == expected, 'Summary for %s was %r -'\
' expected %r' % (key, autosummary_items[key], expected)
diff --git a/tests/test_ext_doctest.py b/tests/test_ext_doctest.py
index f7b6ca5f8..13e0066f6 100644
--- a/tests/test_ext_doctest.py
+++ b/tests/test_ext_doctest.py
@@ -14,7 +14,6 @@ from collections import Counter
import pytest
from packaging.specifiers import InvalidSpecifier
from packaging.version import InvalidVersion
-from six import PY2
from sphinx.ext.doctest import is_allowed_version
@@ -112,9 +111,6 @@ def record(directive, part, should_skip):
return 'Recorded {} {} {}'.format(directive, part, should_skip)
-@pytest.mark.xfail(
- PY2, reason='node.source points to document instead of filename',
-)
@pytest.mark.sphinx('doctest', testroot='ext-doctest-with-autodoc')
def test_reporting_with_autodoc(app, status, warning, capfd):
# Patch builder to get a copy of the output
diff --git a/tests/test_ext_napoleon.py b/tests/test_ext_napoleon.py
index 31130ad54..fd7eb0b9f 100644
--- a/tests/test_ext_napoleon.py
+++ b/tests/test_ext_napoleon.py
@@ -37,7 +37,7 @@ def __special_undoc__():
pass
-class SampleClass(object):
+class SampleClass:
def _private_doc(self):
"""SampleClass._private_doc.DOCSTRING"""
pass
diff --git a/tests/test_ext_napoleon_docstring.py b/tests/test_ext_napoleon_docstring.py
index a4d127d0d..2bc7f626c 100644
--- a/tests/test_ext_napoleon_docstring.py
+++ b/tests/test_ext_napoleon_docstring.py
@@ -77,6 +77,34 @@ Sample namedtuple subclass
self.assertEqual(expected, actual)
+class InlineAttributeTest(BaseDocstringTest):
+
+ def test_class_data_member(self):
+ config = Config()
+ docstring = """data member description:
+
+- a: b
+"""
+ actual = str(GoogleDocstring(docstring, config=config, app=None,
+ what='attribute', name='some_data', obj=0))
+ expected = """data member description:
+
+- a: b"""
+
+ self.assertEqual(expected, actual)
+
+ def test_class_data_member_inline(self):
+ config = Config()
+ docstring = """b: data member description with :ref:`reference`"""
+ actual = str(GoogleDocstring(docstring, config=config, app=None,
+ what='attribute', name='some_data', obj=0))
+ expected = """data member description with :ref:`reference`
+
+:type: b"""
+
+ self.assertEqual(expected, actual)
+
+
class GoogleDocstringTest(BaseDocstringTest):
docstrings = [(
"""Single line summary""",
@@ -452,8 +480,8 @@ Raises:
""", """
Example Function
-:raises: * :exc:`RuntimeError` -- A setting wasn't specified, or was invalid.
- * :exc:`ValueError` -- Something something value error.
+:raises RuntimeError: A setting wasn't specified, or was invalid.
+:raises ValueError: Something something value error.
"""),
################################
("""
@@ -465,7 +493,7 @@ Raises:
""", """
Example Function
-:raises: :exc:`InvalidDimensionsError`
+:raises InvalidDimensionsError:
"""),
################################
("""
@@ -477,7 +505,7 @@ Raises:
""", """
Example Function
-:raises: Invalid Dimensions Error
+:raises Invalid Dimensions Error:
"""),
################################
("""
@@ -489,7 +517,7 @@ Raises:
""", """
Example Function
-:raises: *Invalid Dimensions Error* -- With description
+:raises Invalid Dimensions Error: With description
"""),
################################
("""
@@ -501,7 +529,7 @@ Raises:
""", """
Example Function
-:raises: :exc:`InvalidDimensionsError` -- If the dimensions couldn't be parsed.
+:raises InvalidDimensionsError: If the dimensions couldn't be parsed.
"""),
################################
("""
@@ -513,7 +541,7 @@ Raises:
""", """
Example Function
-:raises: *Invalid Dimensions Error* -- If the dimensions couldn't be parsed.
+:raises Invalid Dimensions Error: If the dimensions couldn't be parsed.
"""),
################################
("""
@@ -525,7 +553,7 @@ Raises:
""", """
Example Function
-:raises: If the dimensions couldn't be parsed.
+:raises If the dimensions couldn't be parsed.:
"""),
################################
("""
@@ -537,7 +565,7 @@ Raises:
""", """
Example Function
-:raises: :class:`exc.InvalidDimensionsError`
+:raises exc.InvalidDimensionsError:
"""),
################################
("""
@@ -549,8 +577,7 @@ Raises:
""", """
Example Function
-:raises: :class:`exc.InvalidDimensionsError` -- If the dimensions couldn't """
- """be parsed.
+:raises exc.InvalidDimensionsError: If the dimensions couldn't be parsed.
"""),
################################
("""
@@ -563,9 +590,8 @@ Raises:
""", """
Example Function
-:raises: :class:`exc.InvalidDimensionsError` -- If the dimensions couldn't """
- """be parsed,
- then a :class:`exc.InvalidDimensionsError` will be raised.
+:raises exc.InvalidDimensionsError: If the dimensions couldn't be parsed,
+ then a :class:`exc.InvalidDimensionsError` will be raised.
"""),
################################
("""
@@ -578,9 +604,8 @@ Raises:
""", """
Example Function
-:raises: * :class:`exc.InvalidDimensionsError` -- If the dimensions """
- """couldn't be parsed.
- * :class:`exc.InvalidArgumentsError` -- If the arguments are invalid.
+:raises exc.InvalidDimensionsError: If the dimensions couldn't be parsed.
+:raises exc.InvalidArgumentsError: If the arguments are invalid.
"""),
################################
("""
@@ -593,8 +618,8 @@ Raises:
""", """
Example Function
-:raises: * :class:`exc.InvalidDimensionsError`
- * :class:`exc.InvalidArgumentsError`
+:raises exc.InvalidDimensionsError:
+:raises exc.InvalidArgumentsError:
""")]
for docstring, expected in docstrings:
actual = str(GoogleDocstring(docstring))
@@ -1346,8 +1371,8 @@ Raises
""", """
Example Function
-:raises: * :exc:`RuntimeError` -- A setting wasn't specified, or was invalid.
- * :exc:`ValueError` -- Something something value error.
+:raises RuntimeError: A setting wasn't specified, or was invalid.
+:raises ValueError: Something something value error.
"""),
################################
("""
@@ -1360,7 +1385,7 @@ InvalidDimensionsError
""", """
Example Function
-:raises: :exc:`InvalidDimensionsError`
+:raises InvalidDimensionsError:
"""),
################################
("""
@@ -1373,7 +1398,7 @@ Invalid Dimensions Error
""", """
Example Function
-:raises: Invalid Dimensions Error
+:raises Invalid Dimensions Error:
"""),
################################
("""
@@ -1387,7 +1412,7 @@ Invalid Dimensions Error
""", """
Example Function
-:raises: *Invalid Dimensions Error* -- With description
+:raises Invalid Dimensions Error: With description
"""),
################################
("""
@@ -1401,7 +1426,7 @@ InvalidDimensionsError
""", """
Example Function
-:raises: :exc:`InvalidDimensionsError` -- If the dimensions couldn't be parsed.
+:raises InvalidDimensionsError: If the dimensions couldn't be parsed.
"""),
################################
("""
@@ -1415,7 +1440,7 @@ Invalid Dimensions Error
""", """
Example Function
-:raises: *Invalid Dimensions Error* -- If the dimensions couldn't be parsed.
+:raises Invalid Dimensions Error: If the dimensions couldn't be parsed.
"""),
################################
("""
@@ -1428,7 +1453,7 @@ If the dimensions couldn't be parsed.
""", """
Example Function
-:raises: If the dimensions couldn't be parsed.
+:raises If the dimensions couldn't be parsed.:
"""),
################################
("""
@@ -1441,7 +1466,7 @@ Raises
""", """
Example Function
-:raises: :class:`exc.InvalidDimensionsError`
+:raises exc.InvalidDimensionsError:
"""),
################################
("""
@@ -1455,8 +1480,7 @@ Raises
""", """
Example Function
-:raises: :class:`exc.InvalidDimensionsError` -- If the dimensions couldn't """
- """be parsed.
+:raises exc.InvalidDimensionsError: If the dimensions couldn't be parsed.
"""),
################################
("""
@@ -1471,9 +1495,8 @@ Raises
""", """
Example Function
-:raises: :class:`exc.InvalidDimensionsError` -- If the dimensions couldn't """
- """be parsed,
- then a :class:`exc.InvalidDimensionsError` will be raised.
+:raises exc.InvalidDimensionsError: If the dimensions couldn't be parsed,
+ then a :class:`exc.InvalidDimensionsError` will be raised.
"""),
################################
("""
@@ -1489,10 +1512,8 @@ Raises
""", """
Example Function
-:raises: * :class:`exc.InvalidDimensionsError` -- If the dimensions """
- """couldn't be parsed.
- * :class:`exc.InvalidArgumentsError` -- If the arguments """
- """are invalid.
+:raises exc.InvalidDimensionsError: If the dimensions couldn't be parsed.
+:raises exc.InvalidArgumentsError: If the arguments are invalid.
"""),
################################
("""
@@ -1506,8 +1527,8 @@ Raises
""", """
Example Function
-:raises: * :class:`exc.InvalidDimensionsError`
- * :class:`exc.InvalidArgumentsError`
+:raises exc.InvalidDimensionsError:
+:raises exc.InvalidArgumentsError:
""")]
for docstring, expected in docstrings:
config = Config()
diff --git a/tests/test_intl.py b/tests/test_intl.py
index c8f90e41c..8a83b711a 100644
--- a/tests/test_intl.py
+++ b/tests/test_intl.py
@@ -18,7 +18,6 @@ import re
import pytest
from babel.messages import pofile, mofile
from docutils import nodes
-from six import string_types
from sphinx.testing.util import (
path, etree_parse, strip_escseq,
@@ -78,20 +77,7 @@ def _info(app):
def elem_gettexts(elem):
- def itertext(self):
- # this function copied from Python-2.7 'ElementTree.itertext'.
- # for compatibility to Python-2.6
- tag = self.tag
- if not isinstance(tag, string_types) and tag is not None:
- return
- if self.text:
- yield self.text
- for e in self:
- for s in itertext(e):
- yield s
- if e.tail:
- yield e.tail
- return [_f for _f in [s.strip() for s in itertext(elem)] if _f]
+ return [_f for _f in [s.strip() for s in elem.itertext()] if _f]
def elem_getref(elem):
@@ -120,7 +106,7 @@ def assert_count(expected_expr, result, count):
@pytest.mark.test_params(shared_result='test_intl_basic')
def test_text_toctree(app):
app.build()
- result = (app.outdir / 'contents.txt').text(encoding='utf-8')
+ result = (app.outdir / 'index.txt').text(encoding='utf-8')
assert_startswith(result, u"CONTENTS\n********\n\nTABLE OF CONTENTS\n")
@@ -169,7 +155,7 @@ def test_text_title_underline(app):
def test_text_subdirs(app):
app.build()
# --- check translation in subdirs
- result = (app.outdir / 'subdir' / 'contents.txt').text(encoding='utf-8')
+ result = (app.outdir / 'subdir' / 'index.txt').text(encoding='utf-8')
assert_startswith(result, u"1. subdir contents\n******************\n")
@@ -462,8 +448,8 @@ def test_text_admonitions(app):
def test_gettext_toctree(app):
app.build()
# --- toctree
- expect = read_po(app.srcdir / 'contents.po')
- actual = read_po(app.outdir / 'contents.pot')
+ expect = read_po(app.srcdir / 'index.po')
+ actual = read_po(app.outdir / 'index.pot')
for expect_msg in [m for m in expect if m.id]:
assert expect_msg.id in [m.id for m in actual if m.id]
@@ -629,7 +615,7 @@ def test_gettext_dont_rebuild_mo(make_app, app_params, build_mo):
def test_html_meta(app):
app.build()
# --- test for meta
- result = (app.outdir / 'contents.html').text(encoding='utf-8')
+ result = (app.outdir / 'index.html').text(encoding='utf-8')
expected_expr = '<meta content="TESTDATA FOR I18N" name="description" />'
assert expected_expr in result
expected_expr = '<meta content="I18N, SPHINX, MARKUP" name="keywords" />'
@@ -758,7 +744,7 @@ def test_html_docfields(app):
def test_html_template(app):
app.build()
# --- gettext template
- result = (app.outdir / 'index.html').text(encoding='utf-8')
+ result = (app.outdir / 'contents.html').text(encoding='utf-8')
assert "WELCOME" in result
assert "SPHINX 2013.120" in result
@@ -941,7 +927,7 @@ def test_xml_role_xref(app):
para1,
['LINK TO', "I18N ROCK'N ROLE XREF", ',', 'CONTENTS', ',',
'SOME NEW TERM', '.'],
- ['i18n-role-xref', 'contents',
+ ['i18n-role-xref', 'index',
'glossary_terms#term-some-term'])
para2 = sec2.findall('paragraph')
@@ -958,7 +944,7 @@ def test_xml_role_xref(app):
assert_elem(
para2[2],
['LINK TO', 'I18N WITH GLOSSARY TERMS', 'AND', 'CONTENTS', '.'],
- ['glossary_terms', 'contents'])
+ ['glossary_terms', 'index'])
assert_elem(
para2[3],
['LINK TO', '--module', 'AND', '-m', '.'],
diff --git a/tests/test_markup.py b/tests/test_markup.py
index 802202639..0f401306b 100644
--- a/tests/test_markup.py
+++ b/tests/test_markup.py
@@ -18,6 +18,7 @@ from docutils.parsers.rst import Parser as RstParser
from docutils.transforms.universal import SmartQuotes
from sphinx import addnodes
+from sphinx.builders.latex import LaTeXBuilder
from sphinx.testing.util import assert_node
from sphinx.util import texescape
from sphinx.util.docutils import sphinx_domains
@@ -87,6 +88,9 @@ def verify_re_html(app, parse):
def verify_re_latex(app, parse):
def verify(rst, latex_expected):
document = parse(rst)
+ app.builder = LaTeXBuilder(app)
+ app.builder.set_environment(app.env)
+ app.builder.init_context()
latex_translator = ForgivingLaTeXTranslator(document, app.builder)
latex_translator.first_document = -1 # don't write \begin{document}
document.walkabout(latex_translator)
diff --git a/tests/test_pycode.py b/tests/test_pycode.py
index 2eab456bc..f35a57c59 100644
--- a/tests/test_pycode.py
+++ b/tests/test_pycode.py
@@ -12,8 +12,6 @@
import os
import sys
-from six import PY2
-
import sphinx
from sphinx.pycode import ModuleAnalyzer
@@ -24,20 +22,14 @@ def test_ModuleAnalyzer_for_string():
analyzer = ModuleAnalyzer.for_string('print("Hello world")', 'module_name')
assert analyzer.modname == 'module_name'
assert analyzer.srcname == '<string>'
- if PY2:
- assert analyzer.encoding == 'ascii'
- else:
- assert analyzer.encoding is None
+ assert analyzer.encoding is None
def test_ModuleAnalyzer_for_file():
analyzer = ModuleAnalyzer.for_string(SPHINX_MODULE_PATH, 'sphinx')
assert analyzer.modname == 'sphinx'
assert analyzer.srcname == '<string>'
- if PY2:
- assert analyzer.encoding == 'ascii'
- else:
- assert analyzer.encoding is None
+ assert analyzer.encoding is None
def test_ModuleAnalyzer_for_module():
diff --git a/tests/test_pycode_parser.py b/tests/test_pycode_parser.py
index 0875329a4..4fbfefcf2 100644
--- a/tests/test_pycode_parser.py
+++ b/tests/test_pycode_parser.py
@@ -12,7 +12,6 @@
import sys
import pytest
-from six import PY2
from sphinx.pycode.parser import Parser
@@ -135,7 +134,6 @@ def test_complex_assignment():
assert parser.definitions == {}
-@pytest.mark.skipif(PY2, reason='tests for py3 syntax')
def test_complex_assignment_py3():
source = ('a, *b, c = (1, 2, 3, 4) #: unpack assignment\n'
'd, *self.attr = (5, 6, 7) #: unpack assignment2\n'
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
index 64c38457d..3140f641e 100644
--- a/tests/test_quickstart.py
+++ b/tests/test_quickstart.py
@@ -13,8 +13,7 @@ import sys
import time
import pytest
-from six import PY2, text_type, StringIO
-from six.moves import input
+from six import text_type, StringIO
from sphinx import application
from sphinx.cmd import quickstart as qs
@@ -37,12 +36,7 @@ def mock_input(answers, needanswer=False):
raise AssertionError('answer for %r missing and no default '
'present' % prompt)
called.add(prompt)
- if PY2:
- prompt = str(prompt) # Python2.x raw_input emulation
- # `raw_input` encode `prompt` by default encoding to print.
- else:
- prompt = text_type(prompt) # Python3.x input emulation
- # `input` decode prompt by default encoding before print.
+ prompt = text_type(prompt)
for question in answers:
if prompt.startswith(qs.PROMPT_PREFIX + question):
return answers[question]
diff --git a/tests/test_search.py b/tests/test_search.py
index 886151831..7b5f73445 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -9,12 +9,12 @@
:license: BSD, see LICENSE for details.
"""
+from io import BytesIO
from collections import namedtuple
import pytest
from docutils import frontend, utils
from docutils.parsers import rst
-from six import BytesIO
from sphinx.search import IndexBuilder
from sphinx.util import jsdump
@@ -22,7 +22,7 @@ from sphinx.util import jsdump
DummyEnvironment = namedtuple('DummyEnvironment', ['version', 'domains'])
-class DummyDomain(object):
+class DummyDomain:
def __init__(self, data):
self.data = data
self.object_types = {}
diff --git a/tests/test_setup_command.py b/tests/test_setup_command.py
index cd1f89c0c..51cfca205 100644
--- a/tests/test_setup_command.py
+++ b/tests/test_setup_command.py
@@ -94,7 +94,7 @@ def nonascii_srcdir(request, setup_command):
==========================
"""))
- master_doc = srcdir / 'contents.txt'
+ master_doc = srcdir / 'index.txt'
master_doc.write_bytes((master_doc.text() + dedent("""
.. toctree::
diff --git a/tests/test_templating.py b/tests/test_templating.py
index 8eed1fdf8..3ae560c9e 100644
--- a/tests/test_templating.py
+++ b/tests/test_templating.py
@@ -21,7 +21,7 @@ def test_layout_overloading(make_app, app_params):
setup_documenters(app)
app.builder.build_update()
- result = (app.outdir / 'contents.html').text(encoding='utf-8')
+ result = (app.outdir / 'index.html').text(encoding='utf-8')
assert '<!-- layout overloading -->' in result
diff --git a/tests/test_util_images.py b/tests/test_util_images.py
index 624690831..5a98fa003 100644
--- a/tests/test_util_images.py
+++ b/tests/test_util_images.py
@@ -19,7 +19,7 @@ from sphinx.util.images import (
GIF_FILENAME = 'img.gif'
PNG_FILENAME = 'img.png'
PDF_FILENAME = 'img.pdf'
-TXT_FILENAME = 'contents.txt'
+TXT_FILENAME = 'index.txt'
@pytest.fixture(scope='module')
diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py
index 99033fb6e..bbaf4e97b 100644
--- a/tests/test_util_inspect.py
+++ b/tests/test_util_inspect.py
@@ -13,7 +13,6 @@ import sys
from textwrap import dedent
import pytest
-from six import PY3
from sphinx.util import inspect
@@ -25,15 +24,11 @@ def test_getargspec():
spec = inspect.getargspec(func)
assert spec.args == ['a', 'b', 'c', 'd']
assert spec.varargs == 'e'
- if PY3:
- assert spec.varkw == 'f'
- assert spec.defaults == (1, 2)
- assert spec.kwonlyargs == []
- assert spec.kwonlydefaults is None
- assert spec.annotations == {}
- else:
- assert spec.keywords == 'f'
- assert spec.defaults == [1, 2]
+ assert spec.varkw == 'f'
+ assert spec.defaults == (1, 2)
+ assert spec.kwonlyargs == []
+ assert spec.kwonlydefaults is None
+ assert spec.annotations == {}
def test_getargspec_partial():
@@ -42,19 +37,13 @@ def test_getargspec_partial():
partial = functools.partial(func1, 10, c=11)
spec = inspect.getargspec(partial)
- if PY3:
- assert spec.args == ['b']
- assert spec.varargs is None
- assert spec.varkw == 'f'
- assert spec.defaults is None
- assert spec.kwonlyargs == ['c', 'd']
- assert spec.kwonlydefaults == {'c': 11, 'd': 2}
- assert spec.annotations == {}
- else:
- assert spec.args == ['b', 'd']
- assert spec.varargs == 'e'
- assert spec.keywords == 'f'
- assert spec.defaults == [2]
+ assert spec.args == ['b']
+ assert spec.varargs is None
+ assert spec.varkw == 'f'
+ assert spec.defaults is None
+ assert spec.kwonlyargs == ['c', 'd']
+ assert spec.kwonlydefaults == {'c': 11, 'd': 2}
+ assert spec.annotations == {}
def test_getargspec_partial2():
@@ -62,19 +51,8 @@ def test_getargspec_partial2():
pass
p = functools.partial(fun, 10, c=11)
- if PY3:
- # Python 3's partial is rather cleverer than Python 2's, and we
- # have to jump through some hoops to define an equivalent function
- # in a way that won't confuse Python 2's parser:
- ns = {}
- exec(dedent("""
- def f_expected(b, *, c=11, d=2):
- pass
- """), ns)
- f_expected = ns["f_expected"]
- else:
- def f_expected(b, d=2):
- pass
+ def f_expected(b, *, c=11, d=2):
+ pass
expected = inspect.getargspec(f_expected)
assert expected == inspect.getargspec(p)
@@ -105,13 +83,8 @@ def test_getargspec_bound_methods():
pass
assert expected_unbound == inspect.getargspec(Foo.method)
- if PY3 and sys.version_info >= (3, 4, 4):
- # On py2, the inspect functions don't properly handle bound
- # methods (they include a spurious 'self' argument)
- assert expected_bound == inspect.getargspec(bound_method)
- # On py2, the inspect functions can't properly handle wrapped
- # functions (no __wrapped__ support)
- assert expected_bound == inspect.getargspec(wrapped_bound_method)
+ assert expected_bound == inspect.getargspec(bound_method)
+ assert expected_bound == inspect.getargspec(wrapped_bound_method)
def test_Signature():
@@ -143,10 +116,7 @@ def test_Signature_partial():
p = functools.partial(fun, 10, c=11)
sig = inspect.Signature(p).format_args()
- if sys.version_info < (3,):
- assert sig == '(b, d=2)'
- else:
- assert sig == '(b, *, c=11, d=2)'
+ assert sig == '(b, *, c=11, d=2)'
def test_Signature_methods():
@@ -193,20 +163,13 @@ def test_Signature_methods():
# wrapped bound method
sig = inspect.Signature(wrapped_bound_method).format_args()
- if sys.version_info < (3,):
- assert sig == '(*args, **kwargs)'
- elif sys.version_info < (3, 4, 4):
- assert sig == '(self, arg1, **kwargs)'
- else:
- assert sig == '(arg1, **kwargs)'
+ assert sig == '(arg1, **kwargs)'
-@pytest.mark.skipif(sys.version_info < (3, 4),
- reason='functools.partialmethod is available on py34 or above')
def test_Signature_partialmethod():
from functools import partialmethod
- class Foo(object):
+ class Foo:
def meth1(self, arg1, arg2, arg3=None, arg4=None):
pass
@@ -228,11 +191,9 @@ def test_Signature_partialmethod():
assert sig == '()'
-@pytest.mark.skipif(sys.version_info < (3, 4),
- reason='type annotation test is available on py34 or above')
def test_Signature_annotations():
- from typing_test_data import (
- f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, Node)
+ from typing_test_data import (f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
+ f11, f12, f13, f14, f15, f16, Node)
# Class annotations
sig = inspect.Signature(f0).format_args()
@@ -297,6 +258,14 @@ def test_Signature_annotations():
sig = inspect.Signature(f14).format_args()
assert sig == '() -> Any'
+ # keyword only arguments (1)
+ sig = inspect.Signature(f15).format_args()
+ assert sig == '(arg1, arg2, *, arg3=None, arg4=None)'
+
+ # keyword only arguments (2)
+ sig = inspect.Signature(f16).format_args()
+ assert sig == '(*, arg3, arg4)'
+
# type hints by string
sig = inspect.Signature(Node.children).format_args()
if (3, 5, 0) <= sys.version_info < (3, 5, 3):
@@ -309,7 +278,7 @@ def test_Signature_annotations():
def test_safe_getattr_with_default():
- class Foo(object):
+ class Foo:
def __getattr__(self, item):
raise Exception
@@ -321,7 +290,7 @@ def test_safe_getattr_with_default():
def test_safe_getattr_with_exception():
- class Foo(object):
+ class Foo:
def __getattr__(self, item):
raise Exception
@@ -336,7 +305,7 @@ def test_safe_getattr_with_exception():
def test_safe_getattr_with_property_exception():
- class Foo(object):
+ class Foo:
@property
def bar(self):
raise Exception
@@ -352,7 +321,7 @@ def test_safe_getattr_with_property_exception():
def test_safe_getattr_with___dict___override():
- class Foo(object):
+ class Foo:
@property
def __dict__(self):
raise Exception
@@ -376,23 +345,29 @@ def test_dictionary_sorting():
def test_set_sorting():
set_ = set("gfedcba")
description = inspect.object_description(set_)
- if PY3:
- assert description == "{'a', 'b', 'c', 'd', 'e', 'f', 'g'}"
- else:
- assert description == "set(['a', 'b', 'c', 'd', 'e', 'f', 'g'])"
+ assert description == "{'a', 'b', 'c', 'd', 'e', 'f', 'g'}"
def test_set_sorting_fallback():
set_ = set((None, 1))
description = inspect.object_description(set_)
- if PY3:
- assert description in ("{1, None}", "{None, 1}")
- else:
- assert description in ("set([1, None])", "set([None, 1])")
+ assert description in ("{1, None}", "{None, 1}")
+
+
+def test_frozenset_sorting():
+ frozenset_ = frozenset("gfedcba")
+ description = inspect.object_description(frozenset_)
+ assert description == "frozenset({'a', 'b', 'c', 'd', 'e', 'f', 'g'})"
+
+
+def test_frozenset_sorting_fallback():
+ frozenset_ = frozenset((None, 1))
+ description = inspect.object_description(frozenset_)
+ assert description in ("frozenset({1, None})", "frozenset({None, 1})")
def test_dict_customtype():
- class CustomType(object):
+ class CustomType:
def __init__(self, value):
self._value = value
@@ -419,10 +394,5 @@ def test_isstaticmethod():
assert inspect.isstaticmethod(Foo.method1, Foo, 'method1') is True
assert inspect.isstaticmethod(Foo.method2, Foo, 'method2') is False
-
- if sys.version_info < (3, 0):
- assert inspect.isstaticmethod(Bar.method1, Bar, 'method1') is False
- assert inspect.isstaticmethod(Bar.method2, Bar, 'method2') is False
- else:
- assert inspect.isstaticmethod(Bar.method1, Bar, 'method1') is True
- assert inspect.isstaticmethod(Bar.method2, Bar, 'method2') is False
+ assert inspect.isstaticmethod(Bar.method1, Bar, 'method1') is True
+ assert inspect.isstaticmethod(Bar.method2, Bar, 'method2') is False
diff --git a/tests/test_util_inventory.py b/tests/test_util_inventory.py
index af3a819cd..08a45d247 100644
--- a/tests/test_util_inventory.py
+++ b/tests/test_util_inventory.py
@@ -11,8 +11,7 @@
import posixpath
import zlib
-
-from six import BytesIO
+from io import BytesIO
from sphinx.ext.intersphinx import InventoryFile
diff --git a/tests/test_util_nodes.py b/tests/test_util_nodes.py
index d20b4b892..2fab10c1c 100644
--- a/tests/test_util_nodes.py
+++ b/tests/test_util_nodes.py
@@ -9,6 +9,7 @@
:license: BSD, see LICENSE for details.
"""
from textwrap import dedent
+from typing import Any
import pytest
from docutils import frontend
@@ -17,7 +18,7 @@ from docutils.parsers import rst
from docutils.utils import new_document
from sphinx.transforms import ApplySourceWorkaround
-from sphinx.util.nodes import extract_messages, clean_astext
+from sphinx.util.nodes import NodeMatcher, extract_messages, clean_astext
def _transform(doctree):
@@ -50,6 +51,38 @@ def assert_node_count(messages, node_type, expect_count):
% (node_type, node_list, count, expect_count))
+def test_NodeMatcher():
+ doctree = nodes.document(None, None)
+ doctree += nodes.paragraph('', 'Hello')
+ doctree += nodes.paragraph('', 'Sphinx', block=1)
+ doctree += nodes.paragraph('', 'World', block=2)
+ doctree += nodes.literal_block('', 'blah blah blah', block=3)
+
+ # search by node class
+ matcher = NodeMatcher(nodes.paragraph)
+ assert len(doctree.traverse(matcher)) == 3
+
+ # search by multiple node classes
+ matcher = NodeMatcher(nodes.paragraph, nodes.literal_block)
+ assert len(doctree.traverse(matcher)) == 4
+
+ # search by node attribute
+ matcher = NodeMatcher(block=1)
+ assert len(doctree.traverse(matcher)) == 1
+
+ # search by node attribute (Any)
+ matcher = NodeMatcher(block=Any)
+ assert len(doctree.traverse(matcher)) == 3
+
+ # search by both class and attribute
+ matcher = NodeMatcher(nodes.paragraph, block=Any)
+ assert len(doctree.traverse(matcher)) == 2
+
+ # mismatched
+ matcher = NodeMatcher(nodes.title)
+ assert len(doctree.traverse(matcher)) == 0
+
+
@pytest.mark.parametrize(
'rst,node_cls,count',
[
diff --git a/tests/test_websupport.py b/tests/test_websupport.py
deleted file mode 100644
index bf12cbade..000000000
--- a/tests/test_websupport.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- test_websupport
- ~~~~~~~~~~~~~~~
-
- Test the Web Support Package
-
- :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
-"""
-
-import pytest
-
-from sphinx.websupport import WebSupport
-try:
- sqlalchemy_missing = False
- import sqlalchemy # NOQA
-except ImportError:
- sqlalchemy_missing = True
-
-
-@pytest.mark.skipif(sqlalchemy_missing, reason='needs sqlalchemy')
-def test_build(request, rootdir, sphinx_test_tempdir):
- settings = {
- 'srcdir': rootdir / 'test-basic',
- # to use same directory for 'builddir' in each 'support' fixture, using
- # 'sphinx_test_tempdir' (static) value instead of 'tempdir' fixture value.
- # each test expect result of db value at previous test case.
- 'builddir': sphinx_test_tempdir / 'websupport'
- }
- marker = request.node.get_marker('support')
- if marker:
- settings.update(marker.kwargs)
-
- support = WebSupport(**settings)
- support.build()
diff --git a/tests/typing_test_data.py b/tests/typing_test_data.py
index 4dc2d06f5..183d075b6 100644
--- a/tests/typing_test_data.py
+++ b/tests/typing_test_data.py
@@ -76,6 +76,13 @@ def f14() -> Any:
pass
+def f15(arg1, arg2, *, arg3=None, arg4=None):
+ pass
+
+def f16(*, arg3, arg4):
+ pass
+
+
class Node:
def __init__(self, parent: Optional['Node']) -> None:
pass
diff --git a/tox.ini b/tox.ini
index 6715fd338..51a9d7e30 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,14 +1,14 @@
[tox]
minversion = 2.0
-envlist = docs,flake8,mypy,coverage,py{27,34,35,36,37,38,py},du{11,12,13,14}
+envlist = docs,flake8,mypy,coverage,py{35,36,37,38},du{12,13,14}
[testenv]
usedevelop = True
passenv =
https_proxy http_proxy no_proxy PERL PERL5LIB PYTEST_ADDOPTS EPUBCHECK_PATH
description =
- py{27,34,35,36,37,38,py}: Run unit tests against {envname}.
- du{11,12,13,14}: Run unit tests with the given version of docutils.
+ py{35,36,37,38}: Run unit tests against {envname}.
+ du{12,13,14}: Run unit tests with the given version of docutils.
# 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
@@ -16,7 +16,6 @@ description =
# https://tox.readthedocs.io/en/latest/config.html#confval-extras=MULTI-LINE-LIST
deps =
.[test,websupport]
- du11: docutils==0.11
du12: docutils==0.12
du13: docutils==0.13.1
du14: docutils==0.14
@@ -66,5 +65,7 @@ commands=
basepython = python3
description =
Build documentation.
+deps =
+ sphinxcontrib-websupport
commands =
python setup.py build_sphinx {posargs}
diff --git a/utils/bump_version.py b/utils/bump_version.py
index 444eefe07..55da12551 100755
--- a/utils/bump_version.py
+++ b/utils/bump_version.py
@@ -84,7 +84,7 @@ def processing(message):
print('done')
-class Changes(object):
+class Changes:
def __init__(self, path):
self.path = path
self.fetch_version()