Merge branch 'master' into refactor_latex

This commit is contained in:
Takeshi KOMIYA 2018-10-07 13:33:55 +09:00
commit 6eb5b29484
394 changed files with 126005 additions and 21672 deletions

View File

@ -5,8 +5,6 @@ environment:
PYTHONWARNINGS: all
matrix:
- PYTHON: 27
TEST_IGNORE: --ignore py35
- PYTHON: 37
- PYTHON: 37-x64

View File

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

View File

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

View File

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

252
CHANGES
View File

@ -1,17 +1,128 @@
Release 1.8.0 (in development)
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.
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()``
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)
==============================
Dependencies
------------
Incompatible changes
--------------------
Deprecated
----------
Features added
--------------
Bugs fixed
----------
Testing
--------
Release 1.8.1 (released Sep 22, 2018)
=====================================
Incompatible changes
--------------------
* LaTeX ``\pagestyle`` commands have been moved to the LaTeX template. No
changes in PDF, except possibly if ``\sphinxtableofcontents``, which
contained them, had been customized in :file:`conf.py`. (refs: #5455)
Bugs fixed
----------
* #5418: Incorrect default path for sphinx-build -d/doctrees files
* #5421: autodoc emits deprecation warning for :confval:`autodoc_default_flags`
* #5422: lambda object causes PicklingError on storing environment
* #5417: Sphinx fails to build with syntax error in Python 2.7.5
* #4911: add latexpdf to make.bat for non make-mode
* #5436: Autodoc does not work with enum subclasses with properties/methods
* #5437: autodoc: crashed on modules importing eggs
* #5433: latex: ImportError: cannot import name 'DEFAULT_SETTINGS'
* #5431: autodoc: ``autofunction`` emits a warning for callable objects
* #5457: Fix TypeError in error message when override is prohibited
* #5453: PDF builds of 'howto' documents have no page numbers
* #5463: mathbase: math_role and MathDirective was disappeared in 1.8.0
* #5454: latex: Index has disappeared from PDF for Japanese documents
* #5432: py domain: ``:type:`` field can't process ``:term:`` references
* #5426: py domain: TypeError has been raised for class attribute
Release 1.8.0 (released Sep 13, 2018)
=====================================
Dependencies
------------
1.8.0b1
* LaTeX: :confval:`latex_use_xindy`, if ``True`` (default for
``xelatex/lualatex``), instructs ``make latexpdf`` to use :program:`xindy`
for general index. Make sure your LaTeX distribution includes it.
(refs: #5134)
* LaTeX: ``latexmk`` is required for ``make latexpdf`` on Windows
Incompatible changes
--------------------
1.8.0b2
* #5282: html theme: refer ``pygments_style`` settings of HTML themes
preferentially
* The URL of download files are changed
* #5127: quickstart: ``Makefile`` and ``make.bat`` are not overwritten if exists
1.8.0b1
* #5156: the :py:mod:`sphinx.ext.graphviz: extension runs `dot` in the
directory of the document being built instead of in the root directory of
the documentation.
@ -53,11 +164,30 @@ Incompatible changes
before new build.
* #5163: html: hlist items are now aligned to top
* ``highlightlang`` directive is processed on resolving phase
* #4000: latex: LaTeX template has been chaned. Following elements are moved
into the template:
- ``\begin{document}``
- ``shorthandoff`` variable
- ``maketitle`` variable
- ``tableofcontents`` variable
Deprecated
----------
1.8.0b2
* ``sphinx.io.SphinxI18nReader.set_lineno_for_reporter()`` is deprecated
* ``sphinx.io.SphinxI18nReader.line`` is deprecated
* ``sphinx.util.i18n.find_catalog_source_file()`` has changed; the
*gettext_compact* argument has been deprecated
* #5403: ``sphinx.util.images.guess_mimetype()`` has changed; the *content*
argument has been deprecated
1.8.0b1
* :confval:`source_parsers` is deprecated
* :confval:`autodoc_default_flags` is deprecated
* quickstart: ``--epub`` option becomes default, so it is deprecated
* Drop function based directive support. For now, Sphinx only supports class
based directives.
@ -121,6 +251,8 @@ Deprecated
* ``sphinx.ext.mathbase.eqref`` node is deprecated
* ``sphinx.ext.mathbase.is_in_section_title()`` is deprecated
* ``sphinx.ext.mathbase.MathDomain`` is deprecated
* ``sphinx.ext.mathbase.MathDirective`` is deprecated
* ``sphinx.ext.mathbase.math_role`` is deprecated
* ``sphinx.ext.mathbase.setup_math()`` is deprecated
* ``sphinx.directives.other.VersionChanges`` is deprecated
* ``sphinx.highlighting.PygmentsBridge.unhighlight()`` is deprecated
@ -135,6 +267,13 @@ For more details, see `deprecation APIs list
Features added
--------------
1.8.0b2
* #5388: Ensure frozen object descriptions are reproducible
* #5362: apidoc: Add ``--tocfile`` option to change the filename of ToC
1.8.0b1
* Add :event:`config-inited` event
* Add ``sphinx.config.Any`` to represent the config value accepts any type of
value
@ -163,17 +302,22 @@ Features added
* Add ``Config.read()`` classmethod to create a new config object from
configuration file
* #4866: Wrap graphviz diagrams in ``<div>`` tag
* Add :event:`viewcode-find-source` event to viewcode extension.
* viewcode: Add :event:`viewcode-find-source` and
:event:`viewcode-follow-imported` to load source code without loading
* #4785: napoleon: Add strings to translation file for localisation
* #4927: Display a warning when invalid values are passed to linenothreshold
option of highlight directive
* C++, add a ``cpp:texpr`` role as a sibling to ``cpp:expr``.
* C++, add support for unions.
* C++, add support for anonymous entities using names staring with ``@``.
Fixes #3593 and #2683.
* #5147: C++, add support for (most) character literals.
* C++, cross-referencing entities inside primary templates is supported,
and now properly documented.
* C++:
- Add a ``cpp:texpr`` role as a sibling to ``cpp:expr``.
- Add support for unions.
- #3593, #2683: add support for anonymous entities using names staring with ``@``.
- #5147: add support for (most) character literals.
- Cross-referencing entities inside primary templates is supported,
and now properly documented.
- #1552: add new cross-referencing format for ``cpp:any`` and ``cpp:func`` roles,
for referencing specific function overloads.
* #3606: MathJax should be loaded with async attribute
* html: Output ``canonical_url`` metadata if :confval:`html_baseurl` set (refs:
#4193)
@ -194,10 +338,36 @@ Features added
* #4614: sphinx-build: Add ``--keep-going`` option to show all warnings
* Add :rst:role:`math:numref` role to refer equations (Same as :rst:role:`eq`)
* quickstart: epub builder is enabled by default
* #5246: Add :confval:`singlehtml_sidebars` to configure sidebars for singlehtml
builder
* #5273: doctest: Skip doctest conditionally
* #5306: autodoc: emit a warning for invalid typehints
* #4075, #5215: autodoc: Add :confval:`autodoc_default_options` which accepts
option values as dict
Bugs fixed
----------
1.8.0b2
* html: search box overrides to other elements if scrolled
* i18n: warnings for translation catalogs have wrong line numbers (refs: #5321)
* #5325: latex: cross references has been broken by multiply labeled objects
* C++, fixes for symbol addition and lookup. Lookup should no longer break
in partial builds. See also #5337.
* #5348: download reference to remote file is not displayed
* #5282: html theme: ``pygments_style`` of theme was overrided by ``conf.py``
by default
* #4379: toctree shows confusible warning when document is excluded
* #2401: autodoc: ``:members:`` causes ``:special-members:`` not to be shown
* autodoc: ImportError is replaced by AttributeError for deeper module
* #2720, #4034: Incorrect links with ``:download:``, duplicate names, and
parallel builds
* #5290: autodoc: failed to analyze source code in egg package
* #5399: Sphinx crashes if unknown po file exists
1.8.0b1
* i18n: message catalogs were reset on each initialization
* #4850: latex: footnote inside footnote was not rendered
* #4945: i18n: fix lang_COUNTRY not fallback correctly for IndexBuilder. Thanks
@ -211,24 +381,26 @@ Bugs fixed
* #5191: C++, prevent nested declarations in functions to avoid lookup problems.
* #5126: C++, add missing isPack method for certain template parameter types.
* #5187: C++, parse attributes on declerators as well.
* C++, parse delete expressions and basic new expressions as well.
* #5002: graphviz: SVGs do not adapt to the column width
Testing
--------
Features removed
----------------
1.8.0b1
* ``sphinx.ext.pngmath`` extension
Documentation
-------------
1.8.0b1
* #5083: Fix wrong make.bat option for internationalization.
* #5115: napoleon: add admonitions added by #4613 to the docs.
Release 1.7.7 (in development)
==============================
Release 1.7.10 (in development)
===============================
Dependencies
------------
@ -245,6 +417,46 @@ Features added
Bugs fixed
----------
Testing
--------
Release 1.7.9 (released Sep 05, 2018)
=====================================
Features added
--------------
* #5359: Make generated texinfo files reproducible by sorting the anchors
Bugs fixed
----------
* #5361: crashed on incremental build if document uses include directive
Release 1.7.8 (released Aug 29, 2018)
=====================================
Incompatible changes
--------------------
* The type of ``env.included`` has been changed to dict of set
Bugs fixed
----------
* #5320: intersphinx: crashed if invalid url given
* #5326: manpage: crashed when invalid docname is specified as ``man_pages``
* #5322: autodoc: ``Any`` typehint causes formatting error
* #5327: "document isn't included in any toctree" warning on rebuild with
generated files
* #5335: quickstart: escape sequence has been displayed with MacPorts' python
Release 1.7.7 (released Aug 19, 2018)
=====================================
Bugs fixed
----------
* #5198: document not in toctree warning when including files only for parallel
builds
* LaTeX: reduce "Token not allowed in a PDF string" hyperref warnings in latex
@ -255,9 +467,13 @@ Bugs fixed
1.5
* LaTeX: fix the :confval:`latex_engine` documentation regarding Latin Modern
font with XeLaTeX/LuaLateX (refs: #5251)
Testing
--------
* #5280: autodoc: Fix wrong type annotations for complex typing
* autodoc: Optional types are wrongly rendered
* #5291: autodoc crashed by ForwardRef types
* #5211: autodoc: No docs generated for functools.partial functions
* #5306: autodoc: ``getargspec()`` raises NameError for invalid typehints
* #5298: imgmath: math_number_all causes equations to have two numbers in html
* #5294: sphinx-quickstart blank prompts in PowerShell
Release 1.7.6 (released Jul 17, 2018)
=====================================
@ -1925,7 +2141,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.

995
EXAMPLES

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
.. image:: https://img.shields.io/pypi/v/sphinx.svg
:target: https://pypi.org/project/Sphinx/
:alt: Package on PyPi
:alt: Package on PyPI
.. image:: https://readthedocs.org/projects/sphinx/badge/?version=master
:target: http://www.sphinx-doc.org/

View File

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

View File

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

View File

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

View File

@ -39,10 +39,6 @@ Build environment API
**Utility methods**
.. automethod:: warn
.. automethod:: warn_node
.. automethod:: doc2path
.. automethod:: relfn2path

View File

@ -116,6 +116,31 @@ The following is a list of deprecated interface.
- (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
@ -131,6 +156,32 @@ The following is a list of deprecated interface.
- 4.0
- :meth:`~sphinx.application.Sphinx.add_js_file()`
* - :confval:`autodoc_default_flags`
- 1.8
- 4.0
- :confval:`autodoc_default_options`
* - ``content`` arguments of ``sphinx.util.image.guess_mimetype()``
- 1.8
- 3.0
- N/A
* - ``gettext_compact`` arguments of
``sphinx.util.i18n.find_catalog_source_files()``
- 1.8
- 3.0
- N/A
* - ``sphinx.io.SphinxI18nReader.set_lineno_for_reporter()``
- 1.8
- 3.0
- N/A
* - ``sphinx.io.SphinxI18nReader.line``
- 1.8
- 3.0
- N/A
* - ``sphinx.directives.other.VersionChanges``
- 1.8
- 3.0
@ -157,6 +208,16 @@ The following is a list of deprecated interface.
- 3.0
- ``sphinx.domains.math.MathDomain``
* - ``sphinx.ext.mathbase.MathDirective``
- 1.8
- 3.0
- ``sphinx.directives.patches.MathDirective``
* - ``sphinx.ext.mathbase.math_role()``
- 1.8
- 3.0
- ``docutils.parsers.rst.roles.math_role()``
* - ``sphinx.ext.mathbase.setup_math()``
- 1.8
- 3.0

View File

@ -9,9 +9,9 @@ Logging API
.. autoclass:: SphinxLoggerAdapter(logging.LoggerAdapter)
.. method:: SphinxLoggerAdapter.error(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.critical(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.warning(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.error(msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.critical(msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.warning(msg, *args, **kwargs)
Logs a message on this logger with the specified level.
Basically, the arguments are as with python's logging module.
@ -33,13 +33,14 @@ Logging API
logger.warning('Warning happened!', location=some_node)
**color**
The color of logs. By default, warning level logs are
colored as ``"darkred"``. The others are not colored.
The color of logs. By default, error level logs are colored as
``"darkred"``, critical level ones is not colored, and warning level
ones are colored as ``"red"``.
.. method:: SphinxLoggerAdapter.log(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.info(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.verbose(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.debug(level, msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.info(msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.verbose(msg, *args, **kwargs)
.. method:: SphinxLoggerAdapter.debug(msg, *args, **kwargs)
Logs a message to this logger with the specified level.
Basically, the arguments are as with python's logging module.
@ -55,9 +56,8 @@ Logging API
:meth:`SphinxLoggerAdapter.warning`.
**color**
The color of logs. By default, debug level logs are
colored as ``"darkgray"``, and debug2 level ones are ``"lightgray"``.
The others are not colored.
The color of logs. By default, info and verbose level logs are not colored,
and deug level ones are colored as ``"darkgray"``.
.. autofunction:: pending_logging()

View File

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

View File

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

View File

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

View File

@ -58,6 +58,10 @@ Options
Maximum depth for the generated table of contents file.
.. option:: --tocfile
Filename for a table of contents file. Defaults to ``modules``.
.. option:: -T, --no-toc
Do not create a table of contents file. Ignored when :option:`--full` is

View File

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

View File

@ -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.
@ -1333,6 +1330,16 @@ that use Sphinx's HTMLWriter class.
.. versionadded:: 1.6
Options for Single HTML output
-------------------------------
.. confval:: singlehtml_sidebars
Custom sidebar templates, must be a dictionary that maps document names to
template names. And it only allows a key named `'index'`. All other keys
are ignored. For more information, refer to :confval:`html_sidebars`. By
default, it is same as :confval:`html_sidebars`.
.. _htmlhelp-options:
@ -1343,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:

View File

@ -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,
@ -114,8 +118,17 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
.. autoclass:: Noodle
:members: eat, slurp
* If you want to make the ``members`` option (or other flag options described
below) the default, see :confval:`autodoc_default_flags`.
* If you want to make the ``members`` option (or other options described
below) the default, see :confval:`autodoc_default_options`.
.. tip::
You can use a negated form, :samp:`'no-{flag}'`, as an option of
autodoc directive, to disable it temporarily. For example::
.. automodule:: foo
:no-undoc-members:
* Members without docstrings will be left out, unless you give the
``undoc-members`` flag option::
@ -297,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
@ -341,20 +357,38 @@ There are also new config values that you can set:
This value is a list of autodoc directive flags that should be automatically
applied to all autodoc directives. The supported flags are ``'members'``,
``'undoc-members'``, ``'private-members'``, ``'special-members'``,
``'inherited-members'``, ``'show-inheritance'`` and ``'ignore-module-all'``.
If you set one of these flags in this config value, you can use a negated
form, :samp:`'no-{flag}'`, in an autodoc directive, to disable it once.
For example, if ``autodoc_default_flags`` is set to ``['members',
'undoc-members']``, and you write a directive like this::
.. automodule:: foo
:no-undoc-members:
the directive will be interpreted as if only ``:members:`` was given.
``'inherited-members'``, ``'show-inheritance'``, ``'ignore-module-all'``
and ``'exclude-members'``.
.. versionadded:: 1.0
.. deprecated:: 1.8
Integrated into :confval:`autodoc_default_options`.
.. confval:: autodoc_default_options
The default options for autodoc directives. They are applied to all autodoc
directives automatically. It must be a dictionary which maps option names
to the values. For example::
autodoc_default_options = {
'members': 'var1, var2',
'member-order': 'bysource',
'special-members': '__init__',
'undoc-members': None,
'exclude-members': '__weakref__'
}
Setting ``None`` is equivalent to giving the option name in the list format
(i.e. it means "yes/true/on").
The supported options are ``'members'``, ``'undoc-members'``,
``'private-members'``, ``'special-members'``, ``'inherited-members'``,
``'show-inheritance'``, ``'ignore-module-all'`` and ``'exclude-members'``.
.. versionadded:: 1.8
.. confval:: autodoc_docstring_signature
Functions imported from C modules cannot be introspected, and therefore the
@ -405,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
-----------------------

View File

@ -208,6 +208,8 @@ The following variables available in the templates:
List containing names of all inherited members of class. Only available for
classes.
.. versionadded:: 1.8.0
.. data:: functions
List containing names of "public" functions in the module. Here, "public"

View File

@ -198,6 +198,81 @@ The following is an example for the usage of the directives. The test via
This parrot wouldn't voom if you put 3000 volts through it!
Skipping tests conditionally
----------------------------
``skipif``, a string option, can be used to skip directives conditionally. This
may be useful e.g. when a different set of tests should be run depending on the
environment (hardware, network/VPN, optional dependencies or different versions
of dependencies). The ``skipif`` option is supported by all of the doctest
directives. Below are typical use cases for ``skipif`` when used for different
directives:
- :rst:dir:`testsetup` and :rst:dir:`testcleanup`
- conditionally skip test setup and/or cleanup
- customize setup/cleanup code per environment
- :rst:dir:`doctest`
- conditionally skip both a test and its output verification
- :rst:dir:`testcode`
- conditionally skip a test
- customize test code per environment
- :rst:dir:`testoutput`
- conditionally skip output assertion for a skipped test
- expect different output depending on the environment
The value of the ``skipif`` option is evaluated as a Python expression. If the
result is a true value, the directive is omitted from the test run just as if
it wasn't present in the file at all.
Instead of repeating an expression, the :confval:`doctest_global_setup`
configuration option can be used to assign it to a variable which can then be
used instead.
Here's an example which skips some tests if Pandas is not installed:
.. code-block:: py
:caption: conf.py
extensions = ['sphinx.ext.doctest']
doctest_global_setup = '''
try:
import pandas as pd
except ImportError:
pd = None
'''
.. code-block:: rst
:caption: contents.rst
.. testsetup::
:skipif: pd is None
data = pd.Series([42])
.. doctest::
:skipif: pd is None
>>> data.iloc[0]
42
.. testcode::
:skipif: pd is None
print(data.iloc[-1])
.. testoutput::
:skipif: pd is None
42
Configuration
-------------

View File

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

View File

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

View File

@ -54,7 +54,7 @@ It adds this directive:
E D F
"""
class A(object):
class A:
pass
class B(A):

View File

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

View File

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

View File

@ -25,7 +25,11 @@ from the source to the description will also be inserted.
In addition, if you don't want to import the modules by ``viewcode``,
you can tell the location of the location of source code to ``viewcode``
using :event:`viewcode-find-source` event.
using the :event:`viewcode-find-source` event.
If :confval:`viewcode_follow_imported_members` is enabled,
you will also need to resolve imported attributes
using the :event:`viewcode-follow-imported` event.
This extension works only on HTML related builders like ``html``,
``applehelp``, ``devhelp``, ``htmlhelp``, ``qthelp`` and so on except
@ -83,3 +87,13 @@ Configuration
:param app: The Sphinx application object.
:param modname: The name of the module to find source code for.
.. event:: viewcode-follow-imported (app, modname, attribute)
.. versionadded:: 1.8
Find the name of the original module for an attribute.
:param app: The Sphinx application object.
:param modname: The name of the module that the attribute belongs to.
:param attribute: The name of the member to follow.

View File

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

View File

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

View File

@ -1005,20 +1005,46 @@ These roles link to the given declaration types:
When a custom title is not needed it may be useful to use the roles for inline expressions,
:rst:role:`cpp:expr` and :rst:role:`cpp:texpr`, where angle brackets do not need escaping.
.. admonition:: Note on References to Overloaded Functions
It is currently impossible to link to a specific version of an overloaded
function. Currently the C++ domain is the first domain that has basic
support for overloaded functions and until there is more data for comparison
we don't want to select a bad syntax to reference a specific overload.
Currently Sphinx will link to the first overloaded version of the function.
Declarations without template parameters and template arguments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
For linking to non-templated declarations the name must be a nested name, e.g.,
``f`` or ``MyClass::f``.
Overloaded (member) functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When a (member) function is referenced using just its name, the reference
will point to an arbitrary matching overload.
The :rst:role:`cpp:any` and :rst:role:`cpp:func` roles will an alternative
format, which simply is a complete function declaration.
This will resolve to the exact matching overload.
As example, consider the following class declaration:
.. cpp:namespace-push:: overload_example
.. cpp:class:: C
.. cpp:function:: void f(double d) const
.. cpp:function:: void f(double d)
.. cpp:function:: void f(int i)
.. cpp:function:: void f()
References using the :rst:role:`cpp:func` role:
- Arbitrary overload: ``C::f``, :cpp:func:`C::f`
- Also arbitrary overload: ``C::f()``, :cpp:func:`C::f()`
- Specific overload: ``void C::f()``, :cpp:func:`void C::f()`
- Specific overload: ``void C::f(int)``, :cpp:func:`void C::f(int)`
- Specific overload: ``void C::f(double)``, :cpp:func:`void C::f(double)`
- Specific overload: ``void C::f(double) const``, :cpp:func:`void C::f(double) const`
Note that the :confval:`add_function_parentheses` configuration variable
does not influence specific overload references.
.. cpp:namespace-pop::
Templated declarations
^^^^^^^^^^^^^^^^^^^^^^

2584
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
},
"devDependencies": {
"jasmine-core": "^3.1.0",
"karma": "^2.0.4",
"karma": "^3.0.0",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.1.0",
"karma-jasmine": "^1.1.2"

View File

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

View File

@ -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.0+'
__released__ = '1.8.0' # 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.0' # used when Sphinx builds its own docs
#:
#: .. versionadded:: 1.2
#: Before version 1.2, check the string ``sphinx.__version__``.
version_info = (1, 8, 0, 'beta', 0)
version_info = (2, 0, 0, 'beta', 0)
package_dir = path.abspath(path.dirname(__file__))
@ -61,55 +59,10 @@ if __version__.endswith('+'):
__version__ = __version__[:-1] # remove '+' for PEP-440 version spec.
try:
import subprocess
p = subprocess.Popen(['git', 'show', '-s', '--pretty=format:%h',
path.join(package_dir, '..')],
p = subprocess.Popen(['git', 'show', '-s', '--pretty=format:%h'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
if out:
__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()

View File

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

View File

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

View File

@ -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
@ -1040,6 +953,8 @@ class Sphinx(object):
And it allows keyword arguments as attributes of script tag.
"""
self.registry.add_js_file(filename, **kwargs)
if hasattr(self.builder, 'add_js_file'):
self.builder.add_js_file(filename, **kwargs) # type: ignore
def add_css_file(self, filename, **kwargs):
# type: (unicode, **unicode) -> None
@ -1078,6 +993,8 @@ class Sphinx(object):
"""
logger.debug('[app] adding stylesheet: %r', filename)
self.registry.add_css_files(filename, **kwargs)
if hasattr(self.builder, 'add_css_file'):
self.builder.add_css_file(filename, **kwargs) # type: ignore
def add_stylesheet(self, filename, alternate=False, title=None):
# type: (unicode, bool, unicode) -> None
@ -1278,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)
@ -1290,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.

View File

@ -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
@ -261,7 +241,6 @@ class Builder(object):
[path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language,
charset=self.config.source_encoding,
gettext_compact=self.config.gettext_compact,
force_all=True,
excluded=Matcher(['**/.?**']))
message = __('all of %d po files') % len(catalogs)
@ -284,7 +263,6 @@ class Builder(object):
self.config.language,
domains=list(specified_domains),
charset=self.config.source_encoding,
gettext_compact=self.config.gettext_compact,
excluded=Matcher(['**/.?**']))
message = __('targets for %d po files that are specified') % len(catalogs)
self.compile_catalogs(catalogs, message)
@ -295,7 +273,6 @@ class Builder(object):
[path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language,
charset=self.config.source_encoding,
gettext_compact=self.config.gettext_compact,
excluded=Matcher(['**/.?**']))
message = __('targets for %d po files that are out of date') % len(catalogs)
self.compile_catalogs(catalogs, message)
@ -559,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)

View File

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

View File

@ -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'),

View File

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

View File

@ -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
@ -62,7 +62,7 @@ msgstr ""
"""[1:]
class Catalog(object):
class Catalog:
"""Catalog of translatable messages."""
def __init__(self):
@ -84,7 +84,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.
"""
@ -268,7 +268,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,

View File

@ -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):
@ -864,10 +815,10 @@ class StandaloneHTMLBuilder(Builder):
for src in status_iterator(self.env.dlfiles, __('copying downloadable files... '),
"brown", len(self.env.dlfiles), self.app.verbosity,
stringify_func=to_relpath):
dest = self.env.dlfiles[src][1]
try:
copyfile(path.join(self.srcdir, src),
path.join(self.outdir, '_downloads', dest))
dest = path.join(self.outdir, '_downloads', self.env.dlfiles[src][1])
ensuredir(path.dirname(dest))
copyfile(path.join(self.srcdir, src), dest)
except EnvironmentError as err:
logger.warning(__('cannot copy downloadable file %r: %s'),
path.join(self.srcdir, src), err)
@ -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):
@ -1066,7 +1017,8 @@ class StandaloneHTMLBuilder(Builder):
sidebars = [name.strip() for name in theme_default_sidebars.split(',')]
# user sidebar settings
for pattern, patsidebars in iteritems(self.config.html_sidebars):
html_sidebars = self.get_builder_config('sidebars', 'html')
for pattern, patsidebars in html_sidebars.items():
if patmatch(pagename, pattern):
if matched:
if has_wildcard(pattern):
@ -1084,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
@ -1161,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
@ -1191,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)
@ -1228,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)
@ -1345,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
@ -1365,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}
@ -1487,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)
@ -1714,6 +1659,8 @@ def setup(app):
app.add_config_value('html_baseurl', '', 'html')
app.add_config_value('html_math_renderer', None, 'env')
app.add_config_value('singlehtml_sidebars', lambda self: self.html_sidebars, 'html')
# event handlers
app.connect('config-inited', convert_html_css_files)
app.connect('config-inited', convert_html_js_files)

View File

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

View File

@ -35,3 +35,12 @@ class math_reference(nodes.Inline, nodes.Referential, nodes.TextElement):
class thebibliography(nodes.container):
"""A node for wrapping bibliographies."""
pass
HYPERLINK_SUPPORT_NODES = (
nodes.figure,
nodes.literal_block,
nodes.table,
nodes.section,
captioned_literal_block,
)

View File

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

View File

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

View File

@ -73,6 +73,10 @@ class ManualPageBuilder(Builder):
for info in self.config.man_pages:
docname, name, description, authors, section = info
if docname not in self.env.all_docs:
logger.warning(__('"man_pages" config value references unknown '
'document %s'), docname)
continue
if isinstance(authors, string_types):
if authors:
authors = [authors]

View File

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

View File

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

View File

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

View File

@ -219,7 +219,7 @@ def build_main(argv=sys.argv[1:]): # type: ignore
args.confdir = args.sourcedir
if not args.doctreedir:
args.doctreedir = os.path.join(args.sourcedir, '.doctrees')
args.doctreedir = os.path.join(args.outputdir, '.doctrees')
# handle remaining filename arguments
filenames = args.filenames

View File

@ -59,7 +59,7 @@ BUILDERS = [
]
class Make(object):
class Make:
def __init__(self, srcdir, builddir, opts):
# type: (unicode, unicode, List[unicode]) -> None

View File

@ -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
@ -26,18 +26,20 @@ try:
import readline
if readline.__doc__ and 'libedit' in readline.__doc__:
readline.parse_and_bind("bind ^I rl_complete")
USE_LIBEDIT = True
else:
readline.parse_and_bind("tab: complete")
USE_LIBEDIT = False
except ImportError:
pass
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
@ -80,6 +82,12 @@ DEFAULTS = {
PROMPT_PREFIX = '> '
if sys.platform == 'win32':
# On Windows, show questions as bold because of color scheme of PowerShell (refs: #5294).
COLOR_QUESTION = 'bold'
else:
COLOR_QUESTION = 'purple'
# function to get input from terminal -- overridden by the test suite
def term_input(prompt):
@ -177,21 +185,13 @@ 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')
prompt = colorize('purple', prompt, input_mode=True)
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
# on libedit.
pass
else:
prompt = colorize(COLOR_QUESTION, prompt, input_mode=True)
x = term_input(prompt).strip()
if default and not x:
x = default
@ -208,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):
@ -385,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()
@ -431,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:
@ -441,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))
@ -664,7 +663,7 @@ def main(argv=sys.argv[1:]):
except ValueError:
print(__('Invalid template variable: %s') % variable)
generate(d, templatedir=args.templatedir)
generate(d, overwrite=False, templatedir=args.templatedir)
return 0

View File

@ -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,18 +36,30 @@ if False:
logger = logging.getLogger(__name__)
CONFIG_FILENAME = 'conf.py'
UNSERIALIZEABLE_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])])
class ENUM(object):
def is_serializable(obj):
# type: (Any) -> bool
"""Check if object is serializable or not."""
if isinstance(obj, UNSERIALIZABLE_TYPES):
return False
elif isinstance(obj, dict):
for key, value in obj.items():
if not is_serializable(key) or not is_serializable(value):
return False
elif isinstance(obj, (list, tuple, set)):
return all(is_serializable(i) for i in obj)
return True
class ENUM:
"""represents the config value should be a one of candidates.
Example:
@ -68,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
@ -104,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', []),
@ -246,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)
@ -295,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):
@ -316,17 +324,17 @@ class Config(object):
"""Obtains serializable data for pickling."""
# remove potentially pickling-problematic values from config
__dict__ = {}
for key, value in iteritems(self.__dict__):
if key.startswith('_') or isinstance(value, UNSERIALIZEABLE_TYPES):
for key, value in self.__dict__.items():
if key.startswith('_') or not is_serializable(value):
pass
else:
__dict__[key] = value
# 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 isinstance(real_value, UNSERIALIZEABLE_TYPES):
if not is_serializable(real_value):
# omit unserializable value
real_value = None
@ -352,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) "
@ -388,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))
@ -456,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__}'.")
@ -476,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',

View File

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

View File

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

View File

@ -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'])

View File

@ -15,14 +15,13 @@ 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
from sphinx.locale import _
from sphinx.util import url_re, docname_join
from sphinx.util.docutils import SphinxDirective
from sphinx.util.matching import patfilter
from sphinx.util.matching import Matcher, patfilter
from sphinx.util.nodes import explicit_title_re, set_source_info, \
process_index_entry
@ -96,6 +95,7 @@ class TocTree(SphinxDirective):
all_docnames.remove(self.env.docname) # remove current document
ret = []
excluded = Matcher(self.config.exclude_patterns)
for entry in self.content:
if not entry:
continue
@ -131,9 +131,13 @@ class TocTree(SphinxDirective):
if url_re.match(ref) or ref == 'self':
toctree['entries'].append((title, ref))
elif docname not in self.env.found_docs:
ret.append(self.state.document.reporter.warning(
'toctree contains reference to nonexisting '
'document %r' % docname, line=self.lineno))
if excluded(self.env.doc2path(docname, None)):
message = 'toctree contains reference to excluded document %r'
else:
message = 'toctree contains reference to nonexisting document %r'
ret.append(self.state.document.reporter.warning(message % docname,
line=self.lineno))
self.env.note_reread()
else:
all_docnames.discard(docname)

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -10,25 +10,21 @@
"""
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 __
from sphinx.transforms import SphinxTransformer
from sphinx.util import get_matching_docs, FilenameUniqDict
from sphinx.util import get_matching_docs, DownloadFiles, FilenameUniqDict
from sphinx.util import logging
from sphinx.util.docutils import LoggingReporter
from sphinx.util.i18n import find_catalog_files
@ -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 = 53 + (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.
@ -139,7 +130,8 @@ class BuildEnvironment(object):
self.dependencies = defaultdict(set) # type: Dict[unicode, Set[unicode]]
# docname -> set of dependent file
# names, relative to documentation root
self.included = set() # type: Set[unicode]
self.included = defaultdict(set) # type: Dict[unicode, Set[unicode]]
# docname -> set of included file
# docnames included from other documents
self.reread_always = set() # type: Set[unicode]
# docnames to re-read unconditionally on
@ -189,7 +181,8 @@ class BuildEnvironment(object):
# these map absolute path -> (docnames, unique filename)
self.images = FilenameUniqDict() # type: FilenameUniqDict
self.dlfiles = FilenameUniqDict() # type: FilenameUniqDict
self.dlfiles = DownloadFiles() # type: DownloadFiles
# filename -> (set of docnames, destination)
# the original URI for images
self.original_image_uri = {} # type: Dict[unicode, unicode]
@ -271,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.
@ -295,28 +283,13 @@ 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."""
if docname in self.all_docs:
self.all_docs.pop(docname, None)
self.included.pop(docname, None)
self.reread_always.discard(docname)
self.included.discard(docname)
for domain in self.domains.values():
domain.clear_doc(docname)
@ -331,10 +304,13 @@ class BuildEnvironment(object):
docnames = set(docnames) # type: ignore
for docname in docnames:
self.all_docs[docname] = other.all_docs[docname]
self.included[docname] = other.included[docname]
if docname in other.reread_always:
self.reread_always.add(docname)
if docname in other.included:
self.included.add(docname)
for version, changes in other.versionchanges.items():
self.versionchanges.setdefault(version, []).extend(
change for change in changes if change[1] in docnames)
for domainname, domain in self.domains.items():
domain.merge_domaindata(docnames, other.domaindata[domainname])
@ -362,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
@ -461,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
@ -551,7 +534,7 @@ class BuildEnvironment(object):
*filename* should be absolute or relative to the source directory.
"""
self.included.add(self.path2doc(filename))
self.included[self.docname].add(self.path2doc(filename))
def note_reread(self):
# type: () -> None
@ -560,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.
@ -602,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))
@ -673,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()
@ -720,12 +667,13 @@ class BuildEnvironment(object):
def check_consistency(self):
# type: () -> None
"""Do consistency checks."""
included = set().union(*self.included.values()) # type: ignore
for docname in sorted(self.all_docs):
if docname not in self.files_to_rebuild:
if docname == self.config.master_doc:
# the master file is not included anywhere ;)
continue
if docname in self.included:
if docname in included:
# the document is included from other documents
continue
if 'orphan' in self.metadata[docname]:
@ -798,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)

View File

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

View File

@ -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}'):

View File

@ -10,11 +10,11 @@
"""
from docutils import nodes
from six import iteritems
from sphinx import addnodes
from sphinx.locale import __
from sphinx.util import url_re, logging
from sphinx.util.matching import Matcher
from sphinx.util.nodes import clean_astext, process_only_nodes
if False:
@ -26,7 +26,7 @@ if False:
logger = logging.getLogger(__name__)
class TocTree(object):
class TocTree:
def __init__(self, env):
# type: (BuildEnvironment) -> None
self.env = env
@ -83,6 +83,7 @@ class TocTree(object):
# interactions between marking and pruning the tree (see bug #1046).
toctree_ancestors = self.get_toctree_ancestors(docname)
excluded = Matcher(self.env.config.exclude_patterns)
def _toctree_add_classes(node, depth):
# type: (nodes.Node, int) -> None
@ -172,8 +173,12 @@ class TocTree(object):
ref, location=toctreenode)
except KeyError:
# this is raised if the included file does not exist
logger.warning(__('toctree contains reference to nonexisting document %r'),
ref, location=toctreenode)
if excluded(self.env.doc2path(ref, None)):
message = __('toctree contains reference to excluded document %r')
else:
message = __('toctree contains reference to nonexisting document %r')
logger.warning(message, ref, location=toctreenode)
else:
# if titles_only is given, only keep the main title and
# sub-toctrees
@ -255,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]

View File

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

View File

@ -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
@ -128,13 +127,16 @@ class DownloadFileCollector(EnvironmentCollector):
"""Process downloadable file paths. """
for node in doctree.traverse(addnodes.download_reference):
targetname = node['reftarget']
rel_filename, filename = app.env.relfn2path(targetname, app.env.docname)
app.env.dependencies[app.env.docname].add(rel_filename)
if not os.access(filename, os.R_OK):
logger.warning(__('download file not readable: %s') % filename,
location=node, type='download', subtype='not_readable')
continue
node['filename'] = app.env.dlfiles.add_file(app.env.docname, filename)
if '://' in targetname:
node['refuri'] = targetname
else:
rel_filename, filename = app.env.relfn2path(targetname, app.env.docname)
app.env.dependencies[app.env.docname].add(rel_filename)
if not os.access(filename, os.R_OK):
logger.warning(__('download file not readable: %s') % filename,
location=node, type='download', subtype='not_readable')
continue
node['filename'] = app.env.dlfiles.add_file(app.env.docname, filename)
def setup(app):

View File

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

View File

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

View File

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

View File

@ -55,6 +55,7 @@ class ExtensionError(SphinxError):
def __init__(self, message, orig_exc=None):
# type: (unicode, Exception) -> None
SphinxError.__init__(self, message)
self.message = message
self.orig_exc = orig_exc
def __repr__(self):

View File

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

View File

@ -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
@ -340,7 +340,9 @@ Note: By default this script will not overwrite already created files."""))
parser.add_argument('-P', '--private', action='store_true',
dest='includeprivate',
help=__('include "_private" modules'))
parser.add_argument('-T', '--no-toc', action='store_true', dest='notoc',
parser.add_argument('--tocfile', action='store', dest='tocfile', default='modules',
help=__("don't create a table of contents file"))
parser.add_argument('-T', '--no-toc', action='store_false', dest='tocfile',
help=__("don't create a table of contents file"))
parser.add_argument('-E', '--no-headings', action='store_true',
dest='noheadings',
@ -453,8 +455,8 @@ def main(argv=sys.argv[1:]):
if not args.dryrun:
qs.generate(d, silent=True, overwrite=args.force)
elif not args.notoc:
create_modules_toc_file(modules, args)
elif args.tocfile:
create_modules_toc_file(modules, args, args.tocfile)
return 0

View File

@ -15,16 +15,15 @@ import inspect
import re
import sys
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
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
@ -32,7 +31,7 @@ from sphinx.util import rpartition, force_decode
from sphinx.util.docstrings import prepare_docstring
from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \
safe_getattr, object_description, is_builtin_class_method, \
isenumattribute, isclassmethod, isstaticmethod, getdoc
isenumattribute, isclassmethod, isstaticmethod, isfunction, isbuiltin, ispartial, getdoc
if False:
# For type annotation
@ -41,6 +40,7 @@ if False:
from docutils import nodes # NOQA
from docutils.utils import Reporter # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc.directive import DocumenterBridge # NOQA
@ -108,56 +108,18 @@ def bool_option(arg):
return True
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)
def merge_special_members_option(options):
# type: (Dict) -> None
"""Merge :special-members: option to :members: option."""
if 'special-members' in options and options['special-members'] is not ALL:
if options.get('members') is ALL:
pass
elif options.get('members'):
for member in options['special-members']:
if member not in options['members']:
options['members'].append(member)
else:
options['members'] = options['special-members']
# Some useful event listener factories for autodoc-process-docstring.
@ -239,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
@ -340,7 +302,8 @@ class Documenter(object):
explicit_modname, path, base, args, retann = \
py_ext_sig_re.match(self.name).groups() # type: ignore
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 ::
@ -377,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
@ -399,7 +362,9 @@ class Documenter(object):
return True
modname = self.get_attr(self.object, '__module__', None)
if modname and modname != self.modname:
if ispartial(self.object) and modname == '_functools': # for pypy
return True
elif modname and modname != self.modname:
return False
return True
@ -438,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
@ -473,9 +438,8 @@ class Documenter(object):
def get_doc(self, encoding=None, ignore=1):
# type: (unicode, int) -> List[List[unicode]]
"""Decode and return lines of the docstring(s) for the object."""
docstring = self.get_attr(self.object, '__doc__', None)
if docstring is None and self.env.config.autodoc_inherit_docstrings:
docstring = getdoc(self.object)
docstring = getdoc(self.object, self.get_attr,
self.env.config.autodoc_inherit_docstrings)
# make sure we have Unicode docstrings, then sanitize and split
# into lines
if isinstance(docstring, text_type):
@ -561,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):
@ -599,9 +563,7 @@ class Documenter(object):
# if isattr is True, the member is documented as an attribute
isattr = False
doc = self.get_attr(member, '__doc__', None)
if doc is None and self.env.config.autodoc_inherit_docstrings:
doc = getdoc(member)
doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings)
# if the member __doc__ is the same as self's __doc__, it's just
# inherited and therefore not the member's doc
@ -652,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:
@ -679,13 +641,18 @@ class Documenter(object):
# remove members given by exclude-members
if self.options.exclude_members:
members = [(membername, member) for (membername, member) in members
if membername not in self.options.exclude_members]
members = [
(membername, member) for (membername, member) in members
if (
self.options.exclude_members is ALL or
membername not in self.options.exclude_members
)
]
# 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
@ -740,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
@ -817,6 +784,11 @@ class ModuleDocumenter(Documenter):
'imported-members': bool_option, 'ignore-module-all': bool_option
} # type: Dict[unicode, Callable]
def __init__(self, *args):
# type: (Any) -> None
super(ModuleDocumenter, self).__init__(*args)
merge_special_members_option(self.options)
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
# type: (Any, unicode, bool, Any) -> bool
@ -826,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):
@ -834,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):
@ -869,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:
@ -882,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
@ -940,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.
@ -1022,16 +1000,21 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # typ
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
# type: (Any, unicode, bool, Any) -> bool
return inspect.isfunction(member) or inspect.isbuiltin(member)
return isfunction(member) or isbuiltin(member)
def format_args(self):
# type: () -> unicode
if inspect.isbuiltin(self.object) or \
inspect.ismethoddescriptor(self.object):
if isbuiltin(self.object) or inspect.ismethoddescriptor(self.object):
# cannot introspect arguments of a C function or method
return None
try:
args = Signature(self.object).format_args()
if (not isfunction(self.object) and
not isbuiltin(self.object) and
not inspect.isclass(self.object) and
hasattr(self.object, '__call__')):
args = Signature(self.object.__call__).format_args()
else:
args = Signature(self.object).format_args()
except TypeError:
if (is_builtin_class_method(self.object, '__new__') and
is_builtin_class_method(self.object, '__init__')):
@ -1070,10 +1053,15 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
'private-members': bool_option, 'special-members': members_option,
} # type: Dict[unicode, Callable]
def __init__(self, *args):
# type: (Any) -> None
super(ClassDocumenter, self).__init__(*args)
merge_special_members_option(self.options)
@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
@ -1095,7 +1083,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
# __init__ written in C?
if initmeth is None or \
is_builtin_class_method(self.object, '__init__') or \
not(inspect.ismethod(initmeth) or inspect.isfunction(initmeth)):
not(inspect.ismethod(initmeth) or isfunction(initmeth)):
return None
try:
return Signature(initmeth, bound_method=True, has_retval=False).format_args()
@ -1225,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):
@ -1310,8 +1297,7 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): # type:
def format_args(self):
# type: () -> unicode
if inspect.isbuiltin(self.object) or \
inspect.ismethoddescriptor(self.object):
if isbuiltin(self.object) or inspect.ismethoddescriptor(self.object):
# can never get arguments of a C function or method
return None
if isstaticmethod(self.object, cls=self.parent, name=self.object_name):
@ -1343,7 +1329,7 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter):
@staticmethod
def is_function_or_method(obj):
# type: (Any) -> bool
return inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj)
return isfunction(obj) or isbuiltin(obj) or inspect.ismethod(obj)
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
@ -1358,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
@ -1441,93 +1427,46 @@ 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)
return safe_getattr(obj, name, *defargs)
def merge_autodoc_default_flags(app, config):
# type: (Sphinx, Config) -> None
"""This merges the autodoc_default_flags to autodoc_default_options."""
if not config.autodoc_default_flags:
return
# Note: this option will be removed in Sphinx-4.0. But I marked this as
# RemovedInSphinx *30* Warning because we have to emit warnings for users
# who will be still in use with Sphinx-3.x. So we should replace this by
# logger.warning() on 3.0.0 release.
warnings.warn('autodoc_default_flags is now deprecated. '
'Please use autodoc_default_options instead.',
RemovedInSphinx30Warning)
for option in config.autodoc_default_flags:
if isinstance(option, string_types):
config.autodoc_default_options[option] = None
else:
logger.warning(
__("Ignoring invalid option in autodoc_default_flags: %r"),
option, type='autodoc'
)
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.add_autodocumenter(ModuleDocumenter)
@ -1542,6 +1481,7 @@ def setup(app):
app.add_config_value('autoclass_content', 'class', True)
app.add_config_value('autodoc_member_order', 'alphabetic', True)
app.add_config_value('autodoc_default_flags', [], True)
app.add_config_value('autodoc_default_options', {}, True)
app.add_config_value('autodoc_docstring_signature', True, True)
app.add_config_value('autodoc_mock_imports', [], True)
app.add_config_value('autodoc_warningiserror', True, True)
@ -1550,4 +1490,6 @@ def setup(app):
app.add_event('autodoc-process-signature')
app.add_event('autodoc-skip-member')
app.connect('config-inited', merge_autodoc_default_flags)
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}

View File

@ -31,10 +31,10 @@ logger = logging.getLogger(__name__)
# common option names for autodoc directives
AUTODOC_DEFAULT_OPTIONS = ['members', 'undoc-members', 'inherited-members',
'show-inheritance', 'private-members', 'special-members',
'ignore-module-all']
'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):
@ -67,8 +67,8 @@ def process_documenter_options(documenter, config, options):
continue
else:
negated = options.pop('no-' + name, True) is None
if name in config.autodoc_default_flags and not negated:
options[name] = None
if name in config.autodoc_default_options and not negated:
options[name] = config.autodoc_default_options[name]
return Options(assemble_option_dict(options.items(), documenter.option_spec))

View File

@ -16,8 +16,6 @@ import warnings
from collections import namedtuple
from types import FunctionType, MethodType, ModuleType
from six import PY2
from sphinx.util import logging
from sphinx.util.inspect import isenumclass, safe_getattr
@ -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
@ -168,13 +166,15 @@ def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warning
try:
module = None
exc_on_importing = None
objpath = list(objpath)
while module is None:
try:
module = import_module(modname, warningiserror=warningiserror)
logger.debug('[autodoc] import %s => %r', modname, module)
except ImportError:
except ImportError as exc:
logger.debug('[autodoc] import %s => failed', modname)
exc_on_importing = exc
if '.' in modname:
# retry with parent module
modname, name = modname.rsplit('.', 1)
@ -193,6 +193,10 @@ def import_object(modname, objpath, objtype='', attrgetter=safe_getattr, warning
object_name = attrname
return [module, parent, object_name, obj]
except (AttributeError, ImportError) as exc:
if isinstance(exc, AttributeError) and exc_on_importing:
# restore ImportError
exc = exc_on_importing
if objpath:
errmsg = ('autodoc: failed to import %s %r from module %r' %
(objtype, '.'.join(objpath), modname))
@ -213,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)
@ -228,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
@ -242,6 +238,11 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
if name not in members:
members[name] = Attribute(name, True, value)
superclass = subject.__mro__[1]
for name, value in obj_dict.items():
if name not in superclass.__dict__:
members[name] = Attribute(name, True, value)
# other members
for name in dir(subject):
try:

View File

@ -1,184 +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
introspected_hints = (typing.get_type_hints(function) # type: ignore
if typing and hasattr(function, '__code__') else {})
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()

View File

@ -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
@ -81,6 +79,7 @@ from sphinx.util import import_object, rst, logging
from sphinx.util.docutils import (
NullReporter, SphinxDirective, new_document, switch_source_input
)
from sphinx.util.matching import Matcher
if False:
# For type annotation
@ -175,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.
@ -185,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
@ -261,12 +250,17 @@ class Autosummary(SphinxDirective):
tree_prefix = self.options['toctree'].strip()
docnames = []
excluded = Matcher(self.config.exclude_patterns)
for name, sig, summary, real_name in items:
docname = posixpath.join(tree_prefix, real_name)
docname = posixpath.normpath(posixpath.join(dirname, docname))
if docname not in self.env.found_docs:
self.warn('toctree references unknown document %r'
% docname)
if excluded(self.env.doc2path(docname, None)):
self.warn('toctree references excluded document %r'
% docname)
else:
self.warn('toctree references unknown document %r'
% docname)
docnames.append(docname)
tocnode = addnodes.toctree()

View File

@ -20,7 +20,6 @@
from __future__ import print_function
import argparse
import codecs
import locale
import os
import pydoc
@ -43,14 +42,15 @@ from sphinx.util.rst import escape as rst_escape
if False:
# For type annotation
from typing import Any, Callable, Dict, Tuple, List # NOQA
from typing import Any, Callable, Dict, List, Tuple, Type # NOQA
from jinja2 import BaseLoader # NOQA
from sphinx import addnodes # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.ext.autodoc import Documenter # NOQA
class DummyApplication(object):
class DummyApplication:
"""Dummy Application class for sphinx-autogen command."""
def __init__(self):
@ -69,7 +69,7 @@ def setup_documenters(app):
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
FunctionDocumenter, MethodDocumenter, AttributeDocumenter,
InstanceAttributeDocumenter
]
] # type: List[Type[Documenter]]
for documenter in documenters:
app.registry.add_documenter(documenter.objtype, documenter)
@ -248,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

View File

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

View File

@ -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):
@ -90,6 +85,16 @@ class TestDirective(SphinxDirective):
def run(self):
# type: () -> List[nodes.Node]
if 'skipif' in self.options:
condition = self.options['skipif']
context = {} # type: Dict[str, Any]
if self.config.doctest_global_setup:
exec(self.config.doctest_global_setup, context)
should_skip = eval(condition, context)
if self.config.doctest_global_cleanup:
exec(self.config.doctest_global_cleanup, context)
if should_skip:
return []
# use ordinary docutils nodes for test code: they get special attributes
# so that our builder recognizes them, and the other builders are happy.
code = '\n'.join(self.content)
@ -143,7 +148,7 @@ class TestDirective(SphinxDirective):
if self.name == 'doctest' and 'pyversion' in self.options:
try:
spec = self.options['pyversion']
python_version = '.'.join(str(v) for v in sys.version_info[:3])
python_version = '.'.join([str(v) for v in sys.version_info[:3]])
if not is_allowed_version(spec, python_version):
flag = doctest.OPTIONFLAGS_BY_NAME['SKIP']
node['options'][flag] = True # Skip the test
@ -155,11 +160,11 @@ class TestDirective(SphinxDirective):
class TestsetupDirective(TestDirective):
option_spec = {} # type: Dict
option_spec = {'skipif': directives.unchanged_required} # type: Dict
class TestcleanupDirective(TestDirective):
option_spec = {} # type: Dict
option_spec = {'skipif': directives.unchanged_required} # type: Dict
class DoctestDirective(TestDirective):
@ -167,6 +172,7 @@ class DoctestDirective(TestDirective):
'hide': directives.flag,
'options': directives.unchanged,
'pyversion': directives.unchanged_required,
'skipif': directives.unchanged_required,
}
@ -174,6 +180,7 @@ class TestcodeDirective(TestDirective):
option_spec = {
'hide': directives.flag,
'pyversion': directives.unchanged_required,
'skipif': directives.unchanged_required,
}
@ -182,6 +189,7 @@ class TestoutputDirective(TestDirective):
'hide': directives.flag,
'options': directives.unchanged,
'pyversion': directives.unchanged_required,
'skipif': directives.unchanged_required,
}
@ -190,7 +198,7 @@ parser = doctest.DocTestParser()
# helper classes
class TestGroup(object):
class TestGroup:
def __init__(self, name):
# type: (unicode) -> None
self.name = name
@ -223,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
@ -305,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)))
@ -369,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:
@ -377,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
@ -431,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'])
@ -443,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)
@ -488,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
@ -515,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))
@ -542,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

View File

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

View File

@ -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(
@ -156,9 +155,7 @@ class Graphviz(SphinxDirective):
line=self.lineno)]
node = graphviz()
node['code'] = dotcode
node['options'] = {
'docname': path.splitext(self.state.document.current_source)[0],
}
node['options'] = {'docname': self.env.docname}
if 'graphviz_dot' in self.options:
node['options']['graphviz_dot'] = self.options['graphviz_dot']
@ -311,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

View File

@ -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
@ -318,8 +317,7 @@ def html_visit_displaymath(self, node):
if node['nowrap']:
latex = node.astext()
else:
latex = wrap_displaymath(node.astext(), None,
self.builder.config.math_number_all)
latex = wrap_displaymath(node.astext(), None, False)
try:
fname, depth = render_math(self, latex)
except MathExtError as exc:

View File

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

View File

@ -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()
@ -410,18 +396,23 @@ def inspect_main(argv):
# type: (unicode) -> None
print(msg, file=sys.stderr)
filename = argv[0]
invdata = fetch_inventory(MockApp(), '', filename) # type: ignore
for key in sorted(invdata or {}):
print(key)
for entry, einfo in sorted(invdata[key].items()):
print('\t%-40s %s%s' % (entry,
einfo[3] != '-' and '%-40s: ' % einfo[3] or '',
einfo[2]))
try:
filename = argv[0]
invdata = fetch_inventory(MockApp(), '', filename) # type: ignore
for key in sorted(invdata or {}):
print(key)
for entry, einfo in sorted(invdata[key].items()):
print('\t%-40s %s%s' % (entry,
einfo[3] != '-' and '%-40s: ' % einfo[3] or '',
einfo[2]))
except ValueError as exc:
print(exc.args[0] % exc.args[1:])
except Exception as exc:
print('Unknown error: %r' % exc)
if __name__ == '__main__':
import logging # type: ignore
logging.basicConfig()
logging.basicConfig() # type: ignore
inspect_main(argv=sys.argv[1:]) # type: ignore

View File

@ -12,10 +12,12 @@
import warnings
from docutils import nodes
from docutils.parsers.rst.roles import math_role as math_role_base
from sphinx.addnodes import math, math_block as displaymath # NOQA # to keep compatibility
from sphinx.builders.latex.nodes import math_reference as eqref # NOQA # to keep compatibility
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.directives.patches import MathDirective as MathDirectiveBase
from sphinx.domains.math import MathDomain # NOQA # to keep compatibility
from sphinx.domains.math import MathReferenceRole as EqXRefRole # NOQA # to keep compatibility
@ -26,6 +28,21 @@ if False:
from sphinx.application import Sphinx # NOQA
class MathDirective(MathDirectiveBase):
def run(self):
warnings.warn('sphinx.ext.mathbase.MathDirective is moved to '
'sphinx.directives.patches package.',
RemovedInSphinx30Warning)
return super(MathDirective, self).run()
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
warnings.warn('sphinx.ext.mathbase.math_role() is deprecated. '
'Please use docutils.parsers.rst.roles.math_role() instead.',
RemovedInSphinx30Warning)
return math_role_base(role, rawtext, text, lineno, inliner, options, content)
def get_node_equation_number(writer, node):
# type: (Writer, nodes.Node) -> unicode
warnings.warn('sphinx.ext.mathbase.get_node_equation_number() is moved to '

View File

@ -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
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
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__')

View File

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

View File

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

View File

@ -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
@ -104,7 +104,12 @@ def doctree_read(app, doctree):
fullname = signode.get('fullname')
refname = modname
if env.config.viewcode_follow_imported_members:
modname = _get_full_modname(app, modname, fullname)
new_modname = app.emit_firstresult(
'viewcode-follow-imported', modname, fullname,
)
if not new_modname:
new_modname = _get_full_modname(app, modname, fullname)
modname = new_modname
if not modname:
continue
fullname = signode.get('fullname')
@ -158,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]):
@ -183,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] = (
@ -262,6 +267,7 @@ def setup(app):
# app.add_config_value('viewcode_include_modules', [], 'env')
# app.add_config_value('viewcode_exclude_modules', [], 'env')
app.add_event('viewcode-find-source')
app.add_event('viewcode-follow-imported')
return {
'version': sphinx.__display_version__,
'env_version': 1,

View File

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

View File

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

View File

@ -10,6 +10,7 @@
"""
import codecs
import re
import warnings
from docutils.core import Publisher
from docutils.io import FileInput, NullOutput
@ -17,9 +18,10 @@ 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
from sphinx.locale import __
from sphinx.transforms import (
ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
@ -116,7 +118,6 @@ class SphinxI18nReader(SphinxBaseReader):
Because the translated texts are partial and they don't have correct line numbers.
"""
lineno = None # type: int
transforms = [ApplySourceWorkaround, ExtraTranslatableNodes, CitationReferences,
DefaultSubstitutions, MoveModuleTargets, HandleCodeBlocks,
AutoNumbering, SortIds, RemoveTranslatableInline,
@ -127,22 +128,15 @@ class SphinxI18nReader(SphinxBaseReader):
def set_lineno_for_reporter(self, lineno):
# type: (int) -> None
"""Stores the source line number of original text."""
self.lineno = lineno
warnings.warn('SphinxI18nReader.set_lineno_for_reporter() is deprecated.',
RemovedInSphinx30Warning)
def new_document(self):
# type: () -> nodes.document
"""Creates a new document object which having a special reporter object for
translation.
"""
document = SphinxBaseReader.new_document(self)
reporter = document.reporter
def get_source_and_line(lineno=None):
# type: (int) -> Tuple[unicode, int]
return reporter.source, self.lineno
reporter.get_source_and_line = get_source_and_line
return document
@property
def line(self):
# type: () -> int
warnings.warn('SphinxI18nReader.line is deprecated.',
RemovedInSphinx30Warning)
return 0
class SphinxDummyWriter(UnfilteredWriter):
@ -288,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'

View File

@ -98,7 +98,7 @@ def accesskey(context, key):
return ''
class idgen(object):
class idgen:
def __init__(self):
# type: () -> None
self.id = 0

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