mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch 'master' into patch-1
This commit is contained in:
commit
fe6d95e429
11
.github/workflows/main.yml
vendored
11
.github/workflows/main.yml
vendored
@ -4,16 +4,12 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-18.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
name: [py35, py36, py37, py38, py39]
|
||||
os: [ubuntu-16.04]
|
||||
name: [py36, py37, py38, py39, py310-dev]
|
||||
include:
|
||||
- name: py35
|
||||
python: 3.5
|
||||
docutils: du12
|
||||
- name: py36
|
||||
python: 3.6
|
||||
docutils: du13
|
||||
@ -29,8 +25,7 @@ jobs:
|
||||
coverage: "--cov ./ --cov-append --cov-config setup.cfg"
|
||||
- name: py310-dev
|
||||
python: 3.10-dev
|
||||
docutils: du17
|
||||
os: ubuntu-latest # required
|
||||
docutils: du16
|
||||
env:
|
||||
PYTEST_ADDOPTS: ${{ matrix.coverage }}
|
||||
|
||||
|
141
CHANGES
141
CHANGES
@ -1,3 +1,139 @@
|
||||
Release 4.0.0 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* Drop python 3.5 support
|
||||
* Drop docutils 0.12 and 0.13 support
|
||||
* LaTeX: add ``tex-gyre`` font dependency
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
* #8539: autodoc: info-field-list is generated into the class description when
|
||||
``autodoc_typehints='description'`` and ``autoclass_content='class'`` set
|
||||
* domain: The ``Index`` class becomes subclasses of ``abc.ABC`` to indicate
|
||||
methods that must be overrided in the concrete classes
|
||||
* #4826: py domain: The structure of python objects is changed. A boolean value
|
||||
is added to indicate that the python object is canonical one
|
||||
* #7425: MathJax: The MathJax was changed from 2 to 3. Users using a custom
|
||||
MathJax configuration may have to set the old MathJax path or update their
|
||||
configuration for version 3. See :mod:`sphinx.ext.mathjax`.
|
||||
* #7784: i18n: The msgid for alt text of image is changed
|
||||
* #5560: napoleon: :confval:`napoleon_use_param` also affect "other parameters"
|
||||
section
|
||||
* #7996: manpage: Make a section directory on build manpage by default (see
|
||||
:confval:`man_make_section_directory`)
|
||||
* #7849: html: Change the default setting of
|
||||
:confval:`html_codeblock_linenos_style` to ``'inline'``
|
||||
* #8380: html search: search results are wrapped with ``<p>`` instead of
|
||||
``<div>``
|
||||
* html theme: Move a script tag for documentation_options.js in
|
||||
basic/layout.html to ``script_files`` variable
|
||||
* html theme: Move CSS tags in basic/layout.html to ``css_files`` variable
|
||||
* #8915: html theme: Emit a warning for sphinx_rtd_theme-0.2.4 or older
|
||||
* #8508: LaTeX: uplatex becomes a default setting of latex_engine for Japanese
|
||||
documents
|
||||
* #5977: py domain: ``:var:``, ``:cvar:`` and ``:ivar:`` fields do not create
|
||||
cross-references
|
||||
* #4550: The ``align`` attribute of ``figure`` and ``table`` nodes becomes
|
||||
``None`` by default instead of ``'default'``
|
||||
* #8769: LaTeX refactoring: split sphinx.sty into multiple files and rename
|
||||
some auxiliary files created in ``latex`` build output repertory
|
||||
* #8937: Use explicit title instead of <no title>
|
||||
* #8487: The :file: option for csv-table directive now recognizes an absolute
|
||||
path as a relative path from source directory
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
|
||||
* :confval:`html_codeblock_linenos_style`
|
||||
* ``favicon`` and ``logo`` variable in HTML templates
|
||||
* ``sphinx.directives.patches.CSVTable``
|
||||
* ``sphinx.directives.patches.ListTable``
|
||||
* ``sphinx.directives.patches.RSTTable``
|
||||
* ``sphinx.ext.autodoc.directive.DocumenterBridge.filename_set``
|
||||
* ``sphinx.ext.autodoc.directive.DocumenterBridge.warn()``
|
||||
* ``sphinx.registry.SphinxComponentRegistry.get_source_input()``
|
||||
* ``sphinx.registry.SphinxComponentRegistry.source_inputs``
|
||||
* ``sphinx.transforms.FigureAligner``
|
||||
* ``sphinx.util.pycompat.convert_with_2to3()``
|
||||
* ``sphinx.util.pycompat.execfile_()``
|
||||
* ``sphinx.util.smartypants``
|
||||
* ``sphinx.util.typing.DirectiveOption``
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #8924: autodoc: Support ``bound`` argument for TypeVar
|
||||
* #7383: autodoc: Support typehints for properties
|
||||
* #5603: autodoc: Allow to refer to a python class using its canonical name
|
||||
when the class has two different names; a canonical name and an alias name
|
||||
* #8539: autodoc: Add :confval:`autodoc_typehints_description_target` to control
|
||||
the behavior of ``autodoc_typehints=description``
|
||||
* #8841: autodoc: :confval:`autodoc_docstring_signature` will continue to look
|
||||
for multiple signature lines without backslash character
|
||||
* #7549: autosummary: Enable :confval:`autosummary_generate` by default
|
||||
* #4826: py domain: Add ``:canonical:`` option to python directives to describe
|
||||
the location where the object is defined
|
||||
* #7199: py domain: Add :confval:`python_use_unqualified_type_names` to suppress
|
||||
the module name of the python reference if it can be resolved (experimental)
|
||||
* #7068: py domain: Add :rst:dir:`py:property` directive to describe a property
|
||||
* #7784: i18n: The alt text for image is translated by default (without
|
||||
:confval:`gettext_additional_targets` setting)
|
||||
* #2018: html: :confval:`html_favicon` and :confval:`html_logo` now accept URL
|
||||
for the image
|
||||
* #8070: html search: Support searching for 2characters word
|
||||
* #9036: html theme: Allow to inherite the search page
|
||||
* #8938: imgconverter: Show the error of the command availability check
|
||||
* #7830: Add debug logs for change detection of sources and templates
|
||||
* #8201: Emit a warning if toctree contains duplicated entries
|
||||
* #8326: ``master_doc`` is now renamed to :confval:`root_doc`
|
||||
* #8942: C++, add support for the C++20 spaceship operator, ``<=>``.
|
||||
* #7199: A new node, ``sphinx.addnodes.pending_xref_condition`` has been added.
|
||||
It can be used to choose appropriate content of the reference by conditions.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #8917: autodoc: Raises a warning if function has wrong __globals__ value
|
||||
* #8415: autodoc: a TypeVar imported from other module is not resolved (in
|
||||
Python 3.7 or above)
|
||||
* #8992: autodoc: Failed to resolve types.TracebackType type annotation
|
||||
* #8905: html: html_add_permalinks=None and html_add_permalinks="" are ignored
|
||||
* #8380: html search: Paragraphs in search results are not identified as ``<p>``
|
||||
* #8915: html theme: The translation of sphinx_rtd_theme does not work
|
||||
* #8342: Emit a warning if a unknown domain is given for directive or role (ex.
|
||||
``:unknown:doc:``)
|
||||
* #7241: LaTeX: No wrapping for ``cpp:enumerator``
|
||||
* #8711: LaTeX: backticks in code-blocks trigger latexpdf build warning (and font
|
||||
change) with late TeXLive 2019
|
||||
* #8253: LaTeX: Figures with no size defined get overscaled (compared to images
|
||||
with size explicitly set in pixels) (fixed for ``'pdflatex'/'lualatex'`` only)
|
||||
* #8881: LaTeX: The depth of bookmarks panel in PDF is not enough for navigation
|
||||
* #8874: LaTeX: the fix to two minor Pygments LaTeXFormatter output issues ignore
|
||||
Pygments style
|
||||
* #8925: LaTeX: 3.5.0 ``verbatimmaxunderfull`` setting does not work as
|
||||
expected
|
||||
* #8980: LaTeX: missing line break in ``\pysigline``
|
||||
* #8995: LaTeX: legacy ``\pysiglinewithargsret`` does not compute correctly
|
||||
available horizontal space and should use a ragged right style
|
||||
* #9009: LaTeX: "release" value with underscore leads to invalid LaTeX
|
||||
* #8911: C++: remove the longest matching prefix in
|
||||
:confval:`cpp_index_common_prefix` instead of the first that matches.
|
||||
* C, properly reject function declarations when a keyword is used
|
||||
as parameter name.
|
||||
* #8933: viewcode: Failed to create back-links on parallel build
|
||||
* #8960: C and C++, fix rendering of (member) function pointer types in
|
||||
function parameter lists.
|
||||
* C++, fix linking of names in array declarators, pointer to member
|
||||
(function) declarators, and in the argument to ``sizeof...``.
|
||||
* C, fix linking of names in array declarators.
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 3.5.4 (in development)
|
||||
==============================
|
||||
|
||||
@ -16,6 +152,8 @@ Features added
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #8870: The style of toctree captions has been changed with docutils-0.17
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
@ -100,6 +238,9 @@ Features added
|
||||
* #8775: autodoc: Support type union operator (PEP-604) in Python 3.10 or above
|
||||
* #8297: autodoc: Allow to extend :confval:`autodoc_default_options` via
|
||||
directive options
|
||||
* #759: autodoc: Add a new configuration :confval:`autodoc_preserve_defaults` as
|
||||
an experimental feature. It preserves the default argument values of
|
||||
functions in source code and keep them not evaluated for readability.
|
||||
* #8619: html: kbd role generates customizable HTML tags for compound keys
|
||||
* #8634: html: Allow to change the order of JS/CSS via ``priority`` parameter
|
||||
for :meth:`Sphinx.add_js_file()` and :meth:`Sphinx.add_css_file()`
|
||||
|
22
EXAMPLES
22
EXAMPLES
@ -12,19 +12,20 @@ interesting examples.
|
||||
Documentation using the alabaster theme
|
||||
---------------------------------------
|
||||
|
||||
* `AIOHTTP <https://docs.aiohttp.org/>`__
|
||||
* `Alabaster <https://alabaster.readthedocs.io/>`__
|
||||
* `Blinker <https://pythonhosted.org/blinker/>`__
|
||||
* `Calibre <https://manual.calibre-ebook.com/>`__
|
||||
* `Click <http://click.pocoo.org/>`__ (customized)
|
||||
* `Click <https://click.palletsprojects.com/>`__ (customized)
|
||||
* `coala <https://docs.coala.io/>`__ (customized)
|
||||
* `CodePy <https://documen.tician.de/codepy/>`__
|
||||
* `Eve <https://docs.python-eve.org/>`__ (Python REST API framework)
|
||||
* `Fabric <https://docs.fabfile.org/>`__
|
||||
* `Fityk <https://fityk.nieto.pl/>`__
|
||||
* `Flask <http://flask.pocoo.org/docs/>`__
|
||||
* `Flask <https://flask.palletsprojects.com/>`__
|
||||
* `Flask-OpenID <https://pythonhosted.org/Flask-OpenID/>`__
|
||||
* `Invoke <https://docs.pyinvoke.org/>`__
|
||||
* `Jinja <http://jinja.pocoo.org/docs/>`__
|
||||
* `Jinja <https://jinja.palletsprojects.com/>`__
|
||||
* `Lino <http://www.lino-framework.org/>`__ (customized)
|
||||
* `marbl <https://getmarbl.readthedocs.io/>`__
|
||||
* `MDAnalysis <https://www.mdanalysis.org/docs/>`__ (customized)
|
||||
@ -41,7 +42,8 @@ Documentation using the alabaster theme
|
||||
* `Spyder <https://docs.spyder-ide.org/>`__ (customized)
|
||||
* `Tablib <http://docs.python-tablib.org/>`__
|
||||
* `urllib3 <https://urllib3.readthedocs.io/>`__ (customized)
|
||||
* `Werkzeug <http://werkzeug.pocoo.org/docs/>`__ (customized)
|
||||
* `Werkzeug <https://werkzeug.palletsprojects.com/>`__
|
||||
* `Write the Docs <https://writethedocs-www.readthedocs.io/>`__
|
||||
|
||||
Documentation using the classic theme
|
||||
-------------------------------------
|
||||
@ -132,7 +134,7 @@ Documentation using the sphinxdoc theme
|
||||
Documentation using the nature theme
|
||||
------------------------------------
|
||||
|
||||
* `Alembic <http://alembic.zzzcomputing.com/>`__
|
||||
* `Alembic <https://alembic.sqlalchemy.org/>`__
|
||||
* `Cython <http://docs.cython.org/>`__
|
||||
* `easybuild <https://easybuild.readthedocs.io/>`__
|
||||
* `jsFiddle <http://doc.jsfiddle.net/>`__
|
||||
@ -141,6 +143,7 @@ Documentation using the nature theme
|
||||
* `MapServer <https://mapserver.org/>`__ (customized)
|
||||
* `Pandas <https://pandas.pydata.org/pandas-docs/stable/>`__
|
||||
* `pyglet <https://pyglet.readthedocs.io/>`__ (customized)
|
||||
* `PyWavelets <https://pywavelets.readthedocs.io/>`__
|
||||
* `Setuptools <https://setuptools.readthedocs.io/>`__
|
||||
* `Spring Python <https://docs.spring.io/spring-python/1.2.x/sphinx/html/>`__
|
||||
* `StatsModels <https://www.statsmodels.org/>`__ (customized)
|
||||
@ -156,6 +159,7 @@ Documentation using another builtin theme
|
||||
* `PyPubSub <https://pypubsub.readthedocs.io/>`__ (bizstyle)
|
||||
* `Pylons <https://docs.pylonsproject.org/projects/pylons-webframework/>`__ (pyramid)
|
||||
* `Pyramid web framework <https://docs.pylonsproject.org/projects/pyramid/>`__ (pyramid)
|
||||
* `RxDock <https://www.rxdock.org/documentation/html/devel/>`__
|
||||
* `Sphinx <http://www.sphinx-doc.org/>`__ (sphinx13) :-)
|
||||
* `Valence <https://docs.valence.desire2learn.com/>`__ (haiku, customized)
|
||||
|
||||
@ -219,6 +223,7 @@ Documentation using sphinx_rtd_theme
|
||||
* `Mailman <http://docs.list.org/>`__
|
||||
* `MathJax <https://docs.mathjax.org/>`__
|
||||
* `MDTraj <http://mdtraj.org/latest/>`__ (customized)
|
||||
* `Mesa 3D <https://docs.mesa3d.org/>`__
|
||||
* `micca - MICrobial Community Analysis <https://micca.readthedocs.io/>`__
|
||||
* `MicroPython <https://docs.micropython.org/>`__
|
||||
* `Minds <https://www.minds.org/docs/>`__ (customized)
|
||||
@ -227,6 +232,7 @@ Documentation using sphinx_rtd_theme
|
||||
* `mod_wsgi <https://modwsgi.readthedocs.io/>`__
|
||||
* `MoinMoin <https://moin-20.readthedocs.io/>`__
|
||||
* `Mopidy <https://docs.mopidy.com/>`__
|
||||
* `mpi4py <https://mpi4py.readthedocs.io/>`__
|
||||
* `MyHDL <http://docs.myhdl.org/>`__
|
||||
* `Nextflow <https://www.nextflow.io/docs/latest/index.html>`__
|
||||
* `NICOS <https://forge.frm2.tum.de/nicos/doc/nicos-master/>`__ (customized)
|
||||
@ -247,6 +253,7 @@ Documentation using sphinx_rtd_theme
|
||||
* `PyVISA <https://pyvisa.readthedocs.io/>`__
|
||||
* `pyvista <https://docs.pyvista.org/>`__
|
||||
* `Read The Docs <https://docs.readthedocs.io/>`__
|
||||
* `ROCm Platform <https://rocm-documentation.readthedocs.io/>`__
|
||||
* `Free your information from their silos (French) <http://redaction-technique.org/>`__ (customized)
|
||||
* `Releases Sphinx extension <https://releases.readthedocs.io/>`__
|
||||
* `Qtile <http://docs.qtile.org/>`__
|
||||
@ -254,7 +261,7 @@ Documentation using sphinx_rtd_theme
|
||||
* `QuTiP <http://qutip.org/docs/latest/>`__
|
||||
* `Satchmo <http://docs.satchmoproject.com/>`__
|
||||
* `Scapy <https://scapy.readthedocs.io/>`__
|
||||
* `SimGrid <http://simgrid.gforge.inria.fr/simgrid/latest/doc/>`__
|
||||
* `SimGrid <https://simgrid.org/doc/latest/>`__
|
||||
* `SimPy <https://simpy.readthedocs.io/>`__
|
||||
* `six <https://six.readthedocs.io/>`__
|
||||
* `SlamData <https://newdocs.slamdata.com>`__
|
||||
@ -283,7 +290,6 @@ Documentation using sphinx_rtd_theme
|
||||
* `Web Application Attack and Audit Framework (w3af) <http://docs.w3af.org/>`__
|
||||
* `Weblate <https://docs.weblate.org/>`__
|
||||
* `x265 <https://x265.readthedocs.io/>`__
|
||||
* `ZeroNet <https://zeronet.readthedocs.io/>`__
|
||||
* `Zulip <https://zulip.readthedocs.io/>`__
|
||||
|
||||
Documentation using sphinx_bootstrap_theme
|
||||
@ -319,6 +325,7 @@ Documentation using a custom theme or integrated in a website
|
||||
* `Doctrine <https://www.doctrine-project.org/>`__
|
||||
* `Enterprise Toolkit for Acrobat products <https://www.adobe.com/devnet-docs/acrobatetk/>`__
|
||||
* `FreeFEM <https://doc.freefem.org/introduction/>`__
|
||||
* `fmt <https://fmt.dev/>`__
|
||||
* `Gameduino <http://excamera.com/sphinx/gameduino/>`__
|
||||
* `gensim <https://radimrehurek.com/gensim/>`__
|
||||
* `GeoServer <http://docs.geoserver.org/>`__
|
||||
@ -328,6 +335,7 @@ Documentation using a custom theme or integrated in a website
|
||||
* `H2O.ai <http://docs.h2o.ai/>`__
|
||||
* `Heka <https://hekad.readthedocs.io/>`__
|
||||
* `Istihza (Turkish Python documentation project) <https://belgeler.yazbel.com/python-istihza/>`__
|
||||
* `JupyterHub <https://jupyterhub.readthedocs.io/>`__
|
||||
* `Kombu <http://docs.kombu.me/>`__
|
||||
* `Lasso <http://lassoguide.com/>`__
|
||||
* `Mako <http://docs.makotemplates.org/>`__
|
||||
|
@ -15,6 +15,7 @@ include sphinx-quickstart.py
|
||||
include sphinx-apidoc.py
|
||||
include tox.ini
|
||||
include sphinx/locale/.tx/config
|
||||
include sphinx/py.typed
|
||||
|
||||
recursive-include sphinx/templates *
|
||||
recursive-include sphinx/texinputs *
|
||||
|
@ -12,10 +12,12 @@ texlive-luatex85 [platform:rpm]
|
||||
texlive-anyfontsize [platform:rpm]
|
||||
texlive-ctablestack [platform:rpm]
|
||||
texlive-gnu-freefont [platform:rpm]
|
||||
texlive-tex-gyre [platform:rpm]
|
||||
latexmk [platform:rpm]
|
||||
|
||||
texlive-latex-recommended [platform:dpkg]
|
||||
texlive-fonts-recommended [platform:dpkg]
|
||||
tex-gyre [platform:dpkg]
|
||||
texlive-latex-extra [platform:dpkg]
|
||||
texlive-luatex [platform:dpkg]
|
||||
latexmk [platform:dpkg]
|
||||
|
8
doc/_static/conf.py.txt
vendored
8
doc/_static/conf.py.txt
vendored
@ -43,7 +43,7 @@ source_suffix = '.rst'
|
||||
# source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
root_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'test'
|
||||
@ -252,7 +252,7 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'test.tex', u'test Documentation',
|
||||
(root_doc, 'test.tex', u'test Documentation',
|
||||
u'test', 'manual'),
|
||||
]
|
||||
|
||||
@ -283,7 +283,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'test', u'test Documentation',
|
||||
(root_doc, 'test', u'test Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
@ -298,7 +298,7 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'test', u'test Documentation',
|
||||
(root_doc, 'test', u'test Documentation',
|
||||
author, 'test', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
@ -10,7 +10,6 @@ Changelog
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\hypersetup{bookmarksdepth=1}% pdf bookmarks
|
||||
\addtocontents{toc}{\protect\setcounter{tocdepth}{1}}%
|
||||
|
||||
.. include:: ../CHANGES
|
||||
|
18
doc/conf.py
18
doc/conf.py
@ -9,7 +9,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.viewcode', 'sphinx.ext.inheritance_diagram']
|
||||
|
||||
master_doc = 'contents'
|
||||
root_doc = 'contents'
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
@ -59,27 +59,14 @@ latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
|
||||
latex_logo = '_static/sphinx.png'
|
||||
latex_elements = {
|
||||
'fontenc': r'\usepackage[LGR,X2,T1]{fontenc}',
|
||||
'fontpkg': r'''
|
||||
\usepackage[sc]{mathpazo}
|
||||
\usepackage[scaled]{helvet}
|
||||
\usepackage{courier}
|
||||
\substitutefont{LGR}{\rmdefault}{cmr}
|
||||
\substitutefont{LGR}{\sfdefault}{cmss}
|
||||
\substitutefont{LGR}{\ttdefault}{cmtt}
|
||||
\substitutefont{X2}{\rmdefault}{cmr}
|
||||
\substitutefont{X2}{\sfdefault}{cmss}
|
||||
\substitutefont{X2}{\ttdefault}{cmtt}
|
||||
''',
|
||||
'passoptionstopackages': r'''
|
||||
\PassOptionsToPackage{svgnames}{xcolor}
|
||||
\PassOptionsToPackage{bookmarksdepth=3}{hyperref}% depth of pdf bookmarks
|
||||
''',
|
||||
'preamble': r'''
|
||||
\DeclareUnicodeCharacter{229E}{\ensuremath{\boxplus}}
|
||||
\setcounter{tocdepth}{3}% depth of what is kept from toc file
|
||||
\setcounter{tocdepth}{3}% depth of what main TOC shows (3=subsubsection)
|
||||
\setcounter{secnumdepth}{1}% depth of section numbering
|
||||
''',
|
||||
'fvset': '\\fvset{fontsize=auto}',
|
||||
# fix missing index entry due to RTD doing only once pdflatex after makeindex
|
||||
'printindex': r'''
|
||||
\IfFileExists{\jobname.ind}
|
||||
@ -91,6 +78,7 @@ latex_show_urls = 'footnote'
|
||||
latex_use_xindy = True
|
||||
|
||||
autodoc_member_order = 'groupwise'
|
||||
autosummary_generate = False
|
||||
todo_include_todos = True
|
||||
extlinks = {'duref': ('http://docutils.sourceforge.net/docs/ref/rst/'
|
||||
'restructuredtext.html#%s', ''),
|
||||
|
142
doc/development/tutorials/autodoc_ext.rst
Normal file
142
doc/development/tutorials/autodoc_ext.rst
Normal file
@ -0,0 +1,142 @@
|
||||
.. _autodoc_ext_tutorial:
|
||||
|
||||
Developing autodoc extension for IntEnum
|
||||
========================================
|
||||
|
||||
The objective of this tutorial is to create an extension that adds
|
||||
support for new type for autodoc. This autodoc extension will format
|
||||
the ``IntEnum`` class from Python standard library. (module ``enum``)
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
We want the extension that will create auto-documentation for IntEnum.
|
||||
``IntEnum`` is the integer enum class from standard library ``enum`` module.
|
||||
|
||||
Currently this class has no special auto documentation behavior.
|
||||
|
||||
We want to add following to autodoc:
|
||||
|
||||
* A new ``autointenum`` directive that will document the ``IntEnum`` class.
|
||||
* The generated documentation will have all the enum possible values
|
||||
with names.
|
||||
* The ``autointenum`` directive will have an option ``:hex:`` which will
|
||||
cause the integers be printed in hexadecimal form.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
We need the same setup as in :doc:`the previous extensions <todo>`. This time,
|
||||
we will be putting out extension in a file called :file:`autodoc_intenum.py`.
|
||||
The :file:`my_enums.py` will contain the sample enums we will document.
|
||||
|
||||
Here is an example of the folder structure you might obtain:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
└── source
|
||||
├── _ext
|
||||
│ └── autodoc_intenum.py
|
||||
├── conf.py
|
||||
├── index.rst
|
||||
└── my_enums.py
|
||||
|
||||
|
||||
Writing the extension
|
||||
---------------------
|
||||
|
||||
Start with ``setup`` function for the extension.
|
||||
|
||||
.. literalinclude:: examples/autodoc_intenum.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:pyobject: setup
|
||||
|
||||
|
||||
The :meth:`~Sphinx.setup_extension` method will pull the autodoc extension
|
||||
because our new extension depends on autodoc. :meth:`~Sphinx.add_autodocumenter`
|
||||
is the method that registers our new auto documenter class.
|
||||
|
||||
We want to import certain objects from the autodoc extension:
|
||||
|
||||
.. literalinclude:: examples/autodoc_intenum.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 1-7
|
||||
|
||||
|
||||
There are several different documenter classes such as ``MethodDocumenter``
|
||||
or ``AttributeDocumenter`` available in the autodoc extension but
|
||||
our new class is the subclass of ``ClassDocumenter`` which a
|
||||
documenter class used by autodoc to document classes.
|
||||
|
||||
This is the definition of our new the auto-documenter class:
|
||||
|
||||
.. literalinclude:: examples/autodoc_intenum.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:pyobject: IntEnumDocumenter
|
||||
|
||||
|
||||
Important attributes of the new class:
|
||||
|
||||
**objtype**
|
||||
This attribute determines the ``auto`` directive name. In
|
||||
this case the auto directive will be ``autointenum``.
|
||||
|
||||
**directivetype**
|
||||
This attribute sets the generated directive name. In
|
||||
this example the generated directive will be ``.. :py:class::``.
|
||||
|
||||
**priority**
|
||||
the larger the number the higher is the priority. We want our
|
||||
documenter be higher priority than the parent.
|
||||
|
||||
**option_spec**
|
||||
option specifications. We copy the parent class options and
|
||||
add a new option *hex*.
|
||||
|
||||
|
||||
Overridden members:
|
||||
|
||||
**can_document_member**
|
||||
This member is important to override. It should
|
||||
return *True* when the passed object can be documented by this class.
|
||||
|
||||
**add_directive_header**
|
||||
This method generates the directive header. We add
|
||||
**:final:** directive option. Remember to call **super** or no directive
|
||||
will be generated.
|
||||
|
||||
**add_content**
|
||||
This method generates the body of the class documentation.
|
||||
After calling the super method we generate lines for enum description.
|
||||
|
||||
|
||||
Using the extension
|
||||
-------------------
|
||||
|
||||
You can now use the new autodoc directive to document any ``IntEnum``.
|
||||
|
||||
For example, you have the following ``IntEnum``:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: my_enums.py
|
||||
|
||||
class Colors(IntEnum):
|
||||
"""Colors enumerator"""
|
||||
NONE = 0
|
||||
RED = 1
|
||||
GREEN = 2
|
||||
BLUE = 3
|
||||
|
||||
|
||||
This will be the documentation file with auto-documentation directive:
|
||||
|
||||
.. code-block:: rst
|
||||
:caption: index.rst
|
||||
|
||||
.. autointenum:: my_enums.Colors
|
||||
|
||||
|
52
doc/development/tutorials/examples/autodoc_intenum.py
Normal file
52
doc/development/tutorials/examples/autodoc_intenum.py
Normal file
@ -0,0 +1,52 @@
|
||||
from enum import IntEnum
|
||||
from typing import Any, Optional
|
||||
|
||||
from docutils.statemachine import StringList
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.ext.autodoc import ClassDocumenter, bool_option
|
||||
|
||||
|
||||
class IntEnumDocumenter(ClassDocumenter):
|
||||
objtype = 'intenum'
|
||||
directivetype = 'class'
|
||||
priority = 10 + ClassDocumenter.priority
|
||||
option_spec = dict(ClassDocumenter.option_spec)
|
||||
option_spec['hex'] = bool_option
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls,
|
||||
member: Any, membername: str,
|
||||
isattr: bool, parent: Any) -> bool:
|
||||
return isinstance(member, IntEnum)
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
super().add_directive_header(sig)
|
||||
self.add_line(' :final:', self.get_sourcename())
|
||||
|
||||
def add_content(self,
|
||||
more_content: Optional[StringList],
|
||||
no_docstring: bool = False
|
||||
) -> None:
|
||||
|
||||
super().add_content(more_content, no_docstring)
|
||||
|
||||
source_name = self.get_sourcename()
|
||||
enum_object: IntEnum = self.object
|
||||
use_hex = self.options.hex
|
||||
self.add_line('', source_name)
|
||||
|
||||
for enum_value in enum_object:
|
||||
the_value_name = enum_value.name
|
||||
the_value_value = enum_value.value
|
||||
if use_hex:
|
||||
the_value_value = hex(the_value_value)
|
||||
|
||||
self.add_line(
|
||||
f"**{the_value_name}**: {the_value_value}", source_name)
|
||||
self.add_line('', source_name)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> None:
|
||||
app.setup_extension('sphinx.ext.autodoc') # Require autodoc extension
|
||||
app.add_autodocumenter(IntEnumDocumenter)
|
@ -13,3 +13,5 @@ Refer to the following tutorials to get started with extension development.
|
||||
helloworld
|
||||
todo
|
||||
recipe
|
||||
autodoc_ext
|
||||
|
||||
|
@ -167,26 +167,33 @@ type for that event::
|
||||
4. event.env-before-read-docs(app, env, docnames)
|
||||
|
||||
for docname in docnames:
|
||||
5. event.env-purge-doc(app, env, docname)
|
||||
5. event.env-purge-doc(app, env, docname)
|
||||
|
||||
if doc changed and not removed:
|
||||
6. source-read(app, docname, source)
|
||||
7. run source parsers: text -> docutils.document (parsers can be added with the app.add_source_parser() API)
|
||||
8. apply transforms (by priority): docutils.document -> docutils.document
|
||||
- event.doctree-read(app, doctree) is called in the middly of transforms,
|
||||
7. run source parsers: text -> docutils.document
|
||||
- parsers can be added with the app.add_source_parser() API
|
||||
8. apply transforms based on priority: docutils.document -> docutils.document
|
||||
- event.doctree-read(app, doctree) is called in the middle of transforms,
|
||||
transforms come before/after this event depending on their priority.
|
||||
9. (if running in parallel mode, for each process) event.env-merged-info(app, env, docnames, other)
|
||||
|
||||
9. event.env-merge-info(app, env, docnames, other)
|
||||
- if running in parallel mode, this event will be emitted for each process
|
||||
|
||||
10. event.env-updated(app, env)
|
||||
11. event.env-get-updated(app, env)
|
||||
12. event.env-check-consistency(app, env)
|
||||
|
||||
# The updated-docs list can be builder dependent, but generally includes all new/changed documents,
|
||||
# plus any output from `env-get-updated`, and then all "parent" documents in the ToC tree
|
||||
# For builders that output a single page, they are first joined into a single doctree before post-transforms/doctree-resolved
|
||||
# For builders that output a single page, they are first joined into a single doctree before post-transforms
|
||||
# or the doctree-resolved event is emitted
|
||||
for docname in updated-docs:
|
||||
13. apply post-transforms (by priority): docutils.document -> docutils.document
|
||||
14. event.doctree-resolved(app, doctree, docname)
|
||||
- (for any reference node that fails to resolve) event.missing-reference(env, node, contnode)
|
||||
- (for any reference node that fails to resolve) event.warn-missing-reference(domain, node)
|
||||
- In the event that any reference nodes fail to resolve, the following may emit:
|
||||
- event.missing-reference(env, node, contnode)
|
||||
- event.warn-missing-reference(domain, node)
|
||||
|
||||
15. Generate output files
|
||||
16. event.build-finished(app, exception)
|
||||
|
@ -22,6 +22,71 @@ The following is a list of deprecated interfaces.
|
||||
- (will be) Removed
|
||||
- Alternatives
|
||||
|
||||
* - ``favicon`` variable in HTML templates
|
||||
- 4.0
|
||||
- TBD
|
||||
- ``favicon_url``
|
||||
|
||||
* - ``logo`` variable in HTML templates
|
||||
- 4.0
|
||||
- TBD
|
||||
- ``logo_url``
|
||||
|
||||
* - ``sphinx.directives.patches.ListTable``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- ``docutils.parsers.rst.diretives.tables.ListSVTable``
|
||||
|
||||
* - ``sphinx.directives.patches.RSTTable``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- ``docutils.parsers.rst.diretives.tables.RSTTable``
|
||||
|
||||
* - ``sphinx.ext.autodoc.directive.DocumenterBridge.filename_set``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- ``sphinx.ext.autodoc.directive.DocumenterBridge.record_dependencies``
|
||||
|
||||
* - ``sphinx.ext.autodoc.directive.DocumenterBridge.warn()``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- :ref:`logging-api`
|
||||
|
||||
* - ``sphinx.registry.SphinxComponentRegistry.get_source_input()``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.registry.SphinxComponentRegistry.source_inputs``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.transforms.FigureAligner``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.util.pycompat.convert_with_2to3()``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.util.pycompat.execfile_()``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.util.smartypants``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- ``docutils.utils.smartyquotes``
|
||||
|
||||
* - ``sphinx.util.typing.DirectiveOption``
|
||||
- 4.0
|
||||
- 6.0
|
||||
- N/A
|
||||
|
||||
* - pending_xref node for viewcode extension
|
||||
- 3.5
|
||||
- 5.0
|
||||
|
@ -37,8 +37,8 @@ New inline nodes
|
||||
|
||||
.. autoclass:: index
|
||||
.. autoclass:: pending_xref
|
||||
.. autoclass:: pending_xref_condition
|
||||
.. autoclass:: literal_emphasis
|
||||
.. autoclass:: abbreviation
|
||||
.. autoclass:: download_reference
|
||||
|
||||
Special nodes
|
||||
|
202
doc/latex.rst
202
doc/latex.rst
@ -139,57 +139,33 @@ Keys that you may want to override include:
|
||||
``babel``, not ``polyglossia``.
|
||||
|
||||
``'fontpkg'``
|
||||
Font package inclusion. The default of ``'\\usepackage{times}'`` uses Times
|
||||
for text, Helvetica for sans serif and Courier for monospace.
|
||||
Font package inclusion. The default is::
|
||||
|
||||
In order to support occasional Cyrillic (физика частиц) or Greek
|
||||
letters (Σωματιδιακή φυσική) in a document whose language is
|
||||
English or a Latin European one, the default set-up is enhanced (only for
|
||||
``'pdflatex'`` engine) to do:
|
||||
r"""\usepackage{tgtermes}
|
||||
\usepackage{tgheros}
|
||||
\renewcommand\ttdefault{txtt}
|
||||
"""
|
||||
|
||||
.. code-block:: latex
|
||||
|
||||
\substitutefont{LGR}{\rmdefault}{cmr}
|
||||
\substitutefont{LGR}{\sfdefault}{cmss}
|
||||
\substitutefont{LGR}{\ttdefault}{cmtt}
|
||||
\substitutefont{X2}{\rmdefault}{cmr}
|
||||
\substitutefont{X2}{\sfdefault}{cmss}
|
||||
\substitutefont{X2}{\ttdefault}{cmtt}
|
||||
|
||||
This is activated only under the condition that the ``'fontenc'`` key is
|
||||
configured to load the ``LGR`` (Greek) and/or ``X2`` (Cyrillic)
|
||||
pdflatex-font encodings (if the :confval:`language` is set to a Cyrillic
|
||||
language, this ``'fontpkg'`` key must be used as "times" package has no
|
||||
direct support for it; then keep only ``LGR`` lines from the above, if
|
||||
support is needed for Greek in the text).
|
||||
|
||||
The ``\substitutefont`` command is from the eponymous LaTeX package, which
|
||||
is loaded by Sphinx if needed (on Ubuntu Xenial it is part of
|
||||
``texlive-latex-extra`` which is a Sphinx requirement).
|
||||
|
||||
Only if the document actually does contain Unicode Greek letters (in text)
|
||||
or Cyrillic letters, will the above default set-up cause additional
|
||||
requirements for the PDF build. On Ubuntu Xenial, these are the
|
||||
``texlive-lang-greek``, ``texlive-lang-cyrillic``, and (with the above
|
||||
choice of fonts) the ``cm-super`` (or ``cm-super-minimal``) packages.
|
||||
|
||||
For ``'xelatex'`` and ``'lualatex'``, the default is to use the FreeFont
|
||||
family: this OpenType font family supports both Cyrillic and Greek scripts
|
||||
and is available as separate Ubuntu Xenial package ``fonts-freefont-otf``.
|
||||
It is not necessary to install the much larger ``texlive-fonts-extra``
|
||||
package.
|
||||
|
||||
``'platex'`` (Japanese documents) engine supports individual Cyrillic and
|
||||
Greek letters with no need of extra user set-up.
|
||||
|
||||
Default: ``'\\usepackage{times}'`` (or ``''`` when using a Cyrillic script)
|
||||
For ``'xelatex'`` and ``'lualatex'`` however the default is to use
|
||||
the GNU FreeFont.
|
||||
|
||||
.. versionchanged:: 1.2
|
||||
Defaults to ``''`` when the :confval:`language` uses the Cyrillic
|
||||
script.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
Added support for individual Greek and Cyrillic letters:
|
||||
Incorporates some font substitution commands to help support occasional
|
||||
Greek or Cyrillic in a document using ``'pdflatex'`` engine.
|
||||
|
||||
.. versionchanged:: 4.0.0
|
||||
- The font substitution commands added at ``2.0`` have been moved
|
||||
to the ``'fontsubstitution'`` key, as their presence here made
|
||||
it complicated for user to customize the value of ``'fontpkg'``.
|
||||
- The default font setting has changed: it still uses Times and
|
||||
Helvetica clones for serif and sans serif, but via better, more
|
||||
complete TeX fonts and associated LaTeX packages. The
|
||||
monospace font has been changed to better match the Times clone.
|
||||
|
||||
|
||||
``'fncychap'``
|
||||
Inclusion of the "fncychap" package (which makes fancy chapter titles),
|
||||
@ -320,37 +296,28 @@ Keys that don't need to be overridden unless in special cases are:
|
||||
.. versionadded:: 1.2
|
||||
|
||||
``'fontenc'``
|
||||
"fontenc" package inclusion.
|
||||
Customize this from its default ``'\\usepackage[T1]{fontenc}'`` to:
|
||||
|
||||
If ``'pdflatex'`` is the :confval:`latex_engine`, one can add ``LGR``
|
||||
for support of Greek letters in the document, and also ``X2`` (or
|
||||
``T2A``) for Cyrillic letters, like this:
|
||||
- ``'\\usepackage[X2,T1]{fontenc}'`` if you need occasional
|
||||
Cyrillic letters (физика частиц),
|
||||
|
||||
.. code-block:: latex
|
||||
- ``'\\usepackage[LGR,T1]{fontenc}'`` if you need occasional
|
||||
Greek letters (Σωματιδιακή φυσική).
|
||||
|
||||
r'\usepackage[LGR,X2,T1]{fontenc}'
|
||||
Use ``[LGR,X2,T1]`` rather if both are needed.
|
||||
|
||||
.. attention::
|
||||
|
||||
If Greek is main language, do not use this key. Since Sphinx 2.2.1,
|
||||
``xelatex`` will be used automatically as :confval:`latex_engine`.
|
||||
Formerly, Sphinx did not support producing PDF via LaTeX with Greek as
|
||||
main language.
|
||||
- Do not use this key for a :confval:`latex_engine` other than
|
||||
``'pdflatex'``.
|
||||
|
||||
Prior to 2.0, Unicode Greek letters were escaped to use LaTeX math
|
||||
mark-up. This is not the case anymore, and the above must be used
|
||||
(only in case of ``'pdflatex'`` engine) if the source contains such
|
||||
Unicode Greek.
|
||||
- If Greek is main language, do not use this key. Since Sphinx 2.2.1,
|
||||
``xelatex`` will be used automatically as :confval:`latex_engine`.
|
||||
|
||||
On Ubuntu xenial, packages ``texlive-lang-greek`` and ``cm-super``
|
||||
(for the latter, only if the ``'fontpkg'`` setting is left to its
|
||||
default) are needed for ``LGR`` to work. In place of ``cm-super``
|
||||
one can install smaller ``cm-super-minimal``, but it requires the
|
||||
LaTeX document to execute ``\usepackage[10pt]{type1ec}`` before
|
||||
loading ``fontenc``. Thus, use this key with this extra at its
|
||||
start if needed.
|
||||
|
||||
Default: ``'\\usepackage[T1]{fontenc}'``
|
||||
- The TeX installation may need some extra packages. For example,
|
||||
on Ubuntu xenial, packages ``texlive-lang-greek`` and ``cm-super``
|
||||
are needed for ``LGR`` to work. And ``texlive-lang-cyrillic`` and
|
||||
``cm-super`` are needed for support of Cyrillic.
|
||||
|
||||
.. versionchanged:: 1.5
|
||||
Defaults to ``'\\usepackage{fontspec}'`` when
|
||||
@ -367,32 +334,37 @@ Keys that don't need to be overridden unless in special cases are:
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
Detection of ``LGR``, ``T2A``, ``X2`` to trigger support of
|
||||
occasional Greek or Cyrillic (``'pdflatex'`` only, as this support
|
||||
is provided natively by ``'platex'`` and only requires suitable
|
||||
font with ``'xelatex'/'lualatex'``).
|
||||
occasional Greek or Cyrillic letters (``'pdflatex'``).
|
||||
|
||||
.. versionchanged:: 2.3.0
|
||||
``'xelatex'`` also executes
|
||||
``'xelatex'`` executes
|
||||
``\defaultfontfeatures[\rmfamily,\sffamily]{}`` in order to avoid
|
||||
contractions of ``--`` into en-dash or transforms of straight quotes
|
||||
into curly ones in PDF (in non-literal text paragraphs) despite
|
||||
:confval:`smartquotes` being set to ``False``.
|
||||
|
||||
``'fontsubstitution'``
|
||||
Ignored if ``'fontenc'`` was not configured to use ``LGR`` or ``X2`` (or
|
||||
``T2A``). In case ``'fontpkg'`` key is configured for usage with some
|
||||
TeX fonts known to be available in the ``LGR`` or ``X2`` encodings, set
|
||||
this one to be the empty string. Else leave to its default.
|
||||
|
||||
Ignored with :confval:`latex_engine` other than ``'pdflatex'``.
|
||||
|
||||
.. versionadded:: 4.0.0
|
||||
|
||||
``'textgreek'``
|
||||
This is needed for ``pdflatex`` to support Unicode input of Greek
|
||||
letters such as φύσις. Expert users may want to load the ``textalpha``
|
||||
package with its option ``normalize-symbols``.
|
||||
For the support of occasional Greek letters.
|
||||
|
||||
.. hint::
|
||||
It is ignored with ``'platex'``, ``'xelatex'`` or ``'lualatex'`` as
|
||||
:confval:`latex_engine` and defaults to either the empty string or
|
||||
to ``'\\usepackage{textalpha}'`` for ``'pdflatex'`` depending on
|
||||
whether the ``'fontenc'`` key was used with ``LGR`` or not. Only
|
||||
expert LaTeX users may want to customize this key.
|
||||
|
||||
Unicode Greek (but no further Unicode symbols) in :rst:dir:`math`
|
||||
can be supported by ``'pdflatex'`` from setting this key to
|
||||
``r'\usepackage{textalpha,alphabeta}'``. Then ``:math:`α``` (U+03B1)
|
||||
will render as :math:`\alpha`. For wider Unicode support in math
|
||||
input, see the discussion of :confval:`latex_engine`.
|
||||
|
||||
With ``'platex'`` (Japanese), ``'xelatex'`` or ``'lualatex'``, this
|
||||
key is ignored.
|
||||
It can also be used as ``r'\usepackage{textalpha,alphabeta}'`` to let
|
||||
``'pdflatex'`` support Greek Unicode input in :rst:dir:`math` context.
|
||||
For example ``:math:`α``` (U+03B1) will render as :math:`\alpha`.
|
||||
|
||||
Default: ``'\\usepackage{textalpha}'`` or ``''`` if ``fontenc`` does not
|
||||
include the ``LGR`` option.
|
||||
@ -517,19 +489,25 @@ Keys that don't need to be overridden unless in special cases are:
|
||||
Default: ``'\\printindex'``
|
||||
|
||||
``'fvset'``
|
||||
Customization of ``fancyvrb`` LaTeX package. The default value of
|
||||
``'\\fvset{fontsize=\\small}'`` is used to adjust for the large character
|
||||
width of the monospace font, used in code-blocks. You may need to modify
|
||||
this if you use custom fonts.
|
||||
Customization of ``fancyvrb`` LaTeX package.
|
||||
|
||||
Default: ``'\\fvset{fontsize=\\small}'``
|
||||
The default value is ``'\\fvset{fontsize=auto}'`` which means that the
|
||||
font size will adjust correctly if a code-block ends up in a footnote.
|
||||
You may need to modify this if you use custom fonts:
|
||||
``'\\fvset{fontsize=\\small}'`` if the monospace font is Courier-like.
|
||||
|
||||
Default: ``'\\fvset{fontsize=auto}'``
|
||||
|
||||
.. versionadded:: 1.8
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
Due to new default font choice for ``'xelatex'`` and ``'lualatex'``
|
||||
(FreeFont), Sphinx does ``\\fvset{fontsize=\\small}`` also with these
|
||||
engines (and not ``\\fvset{fontsize=auto}``).
|
||||
For ``'xelatex'`` and ``'lualatex'`` defaults to
|
||||
``'\\fvset{fontsize=\\small}'`` as this
|
||||
is adapted to the relative widths of the FreeFont family.
|
||||
|
||||
.. versionchanged:: 4.0.0
|
||||
Changed default for ``'pdflatex'``. Previously it was using
|
||||
``'\\fvset{fontsize=\\small}'``.
|
||||
|
||||
Keys that are set by other options and therefore should not be overridden are:
|
||||
|
||||
@ -600,6 +578,17 @@ e.g ``'sphinxsetup': "verbatimwrapslines=false"``. If setting the
|
||||
boolean key to ``true``, ``=true`` is optional.
|
||||
Spaces around the commas and equal signs are ignored, spaces inside LaTeX
|
||||
macros may be significant.
|
||||
Do not use quotes to enclose values, whether numerical or strings.
|
||||
|
||||
``bookmarksdepth``
|
||||
Controls the depth of the collapsable bookmarks panel in the PDF.
|
||||
May be either a number (e.g. ``3``) or a LaTeX sectioning name (e.g.
|
||||
``subsubsection``, i.e. without backslash).
|
||||
For details, refer to the ``hyperref`` LaTeX docs.
|
||||
|
||||
Default: ``5``
|
||||
|
||||
.. versionadded:: 4.0.0
|
||||
|
||||
.. _latexsphinxsetuphmargin:
|
||||
|
||||
@ -917,9 +906,36 @@ macros may be significant.
|
||||
LaTeX macros and environments
|
||||
-----------------------------
|
||||
|
||||
Here are some macros from the package file :file:`sphinx.sty` and class files
|
||||
:file:`sphinxhowto.cls`, :file:`sphinxmanual.cls`, which have public names
|
||||
thus allowing redefinitions. Check the respective files for the defaults.
|
||||
The "LaTeX package" file :file:`sphinx.sty` loads various components
|
||||
providing support macros (aka commands), and environments, which are used in
|
||||
the mark-up produced on output from the ``latex`` builder, before conversion
|
||||
to ``pdf`` via the LaTeX toolchain. Also the "LaTeX class" files
|
||||
:file:`sphinxhowto.cls` and :file:`sphinxmanual.cls` define or customize some
|
||||
environments. All of these files can be found in the latex build repertory.
|
||||
|
||||
Some of these provide facilities not available from pre-existing LaTeX
|
||||
packages and work around LaTeX limitations with lists, table cells, verbatim
|
||||
rendering, footnotes, etc...
|
||||
|
||||
Others simply define macros with public names to make overwriting their
|
||||
defaults easy via user-added contents to the preamble. We will survey most of
|
||||
those public names here, but defaults have to be looked at in their respective
|
||||
definition files.
|
||||
|
||||
.. hint::
|
||||
|
||||
Sphinx LaTeX support code is split across multiple smaller-sized files.
|
||||
Rather than adding code to the preamble via
|
||||
`latex_elements <latex_elements_confval_>`_\ [``'preamble'``] it is
|
||||
also possible to replace entirely one of the component files of Sphinx
|
||||
LaTeX code with a custom version, simply by including a modified copy in
|
||||
the project source and adding the filename to the
|
||||
:confval:`latex_additional_files` list. Check the LaTeX build repertory
|
||||
for the filenames and contents.
|
||||
|
||||
.. versionchanged:: 4.0.0
|
||||
split of :file:`sphinx.sty` into multiple smaller units, to facilitate
|
||||
customization of many aspects simultaneously.
|
||||
|
||||
.. _latex-macros:
|
||||
|
||||
|
@ -145,7 +145,7 @@ These options are used when :option:`--full` is specified:
|
||||
* ``module.rst_t``
|
||||
* ``package.rst_t``
|
||||
* ``toc.rst_t``
|
||||
* ``master_doc.rst_t``
|
||||
* ``root_doc.rst_t``
|
||||
* ``conf.py_t``
|
||||
* ``Makefile_t``
|
||||
* ``Makefile.new_t``
|
||||
|
@ -19,13 +19,12 @@ files, including ``conf.py``.
|
||||
:program:`sphinx-build` can create documentation in different formats. A
|
||||
format is selected by specifying the builder name on the command line; it
|
||||
defaults to HTML. Builders can also perform other tasks related to
|
||||
documentation processing.
|
||||
documentation processing. For a list of available builders, refer to
|
||||
:option:`sphinx-build -b`.
|
||||
|
||||
By default, everything that is outdated is built. Output only for selected
|
||||
files can be built by specifying individual filenames.
|
||||
|
||||
For a list of available options, refer to :option:`sphinx-build -b`.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
|
@ -72,7 +72,7 @@ Options
|
||||
|
||||
.. option:: --master=MASTER
|
||||
|
||||
Master document name. (see :confval:`master_doc`).
|
||||
Master document name. (see :confval:`root_doc`).
|
||||
|
||||
.. rubric:: Extension Options
|
||||
|
||||
@ -149,7 +149,7 @@ Options
|
||||
sphinx project files generated by quickstart. Following Jinja2 template
|
||||
files are allowed:
|
||||
|
||||
* ``master_doc.rst_t``
|
||||
* ``root_doc.rst_t``
|
||||
* ``conf.py_t``
|
||||
* ``Makefile_t``
|
||||
* ``Makefile.new_t``
|
||||
|
@ -274,7 +274,19 @@ in the future.
|
||||
|
||||
.. data:: favicon
|
||||
|
||||
The path to the HTML favicon in the static path, or ``''``.
|
||||
The path to the HTML favicon in the static path, or URL to the favicon, or
|
||||
``''``.
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
Recommend to use ``favicon_url`` instead.
|
||||
|
||||
.. data:: favicon_url
|
||||
|
||||
The relative path to the HTML favicon image from the current document, or
|
||||
URL to the favicon, or ``''``.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. data:: file_suffix
|
||||
|
||||
@ -297,11 +309,35 @@ in the future.
|
||||
|
||||
.. data:: logo
|
||||
|
||||
The path to the HTML logo image in the static path, or ``''``.
|
||||
The path to the HTML logo image in the static path, or URL to the logo, or
|
||||
``''``.
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
Recommend to use ``logo_url`` instead.
|
||||
|
||||
.. data:: logo_url
|
||||
|
||||
The relative path to the HTML logo image from the current document, or URL
|
||||
to the logo, or ``''``.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. data:: master_doc
|
||||
|
||||
The value of :confval:`master_doc`, for usage with :func:`pathto`.
|
||||
Same as :data:`root_doc`.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
Renamed to ``root_doc``.
|
||||
|
||||
.. data:: root_doc
|
||||
|
||||
The value of :confval:`root_doc`, for usage with :func:`pathto`.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
Renamed from ``master_doc``.
|
||||
|
||||
.. data:: pagename
|
||||
|
||||
|
@ -306,7 +306,7 @@ Contributing to Sphinx reference translation
|
||||
The recommended way for new contributors to translate Sphinx reference is to
|
||||
join the translation team on Transifex.
|
||||
|
||||
There is `sphinx translation page`_ for Sphinx (master) documentation.
|
||||
There is a `sphinx translation page`_ for Sphinx (master) documentation.
|
||||
|
||||
1. Login to transifex_ service.
|
||||
2. Go to `sphinx translation page`_.
|
||||
@ -314,6 +314,8 @@ There is `sphinx translation page`_ for Sphinx (master) documentation.
|
||||
4. Wait acceptance by transifex sphinx translation maintainers.
|
||||
5. (After acceptance) Translate on transifex.
|
||||
|
||||
Detail is here: https://docs.transifex.com/getting-started-1/translators
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [1] See the `GNU gettext utilities
|
||||
|
@ -179,6 +179,7 @@ The builder's "name" must be given to the **-b** command-line option of
|
||||
|
||||
* ``texlive-latex-recommended``
|
||||
* ``texlive-fonts-recommended``
|
||||
* ``tex-gyre`` (if :confval:`latex_engine` is ``'pdflatex'``)
|
||||
* ``texlive-latex-extra``
|
||||
* ``latexmk`` (this is a Sphinx requirement on GNU/Linux and MacOS X
|
||||
for functioning of ``make latexpdf``)
|
||||
@ -186,17 +187,14 @@ The builder's "name" must be given to the **-b** command-line option of
|
||||
Additional packages are needed in some circumstances (see the discussion of
|
||||
the ``'fontpkg'`` key of :confval:`latex_elements` for more information):
|
||||
|
||||
* to support occasional Cyrillic letters or words, and a fortiori if
|
||||
:confval:`language` is set to a Cyrillic language, the package
|
||||
``texlive-lang-cyrillic`` is required, and, with unmodified ``'fontpkg'``,
|
||||
also ``cm-super`` or ``cm-super-minimal``,
|
||||
* to support occasional Greek letters or words (in text, not in
|
||||
:rst:dir:`math` directive contents), ``texlive-lang-greek`` is required,
|
||||
and, with unmodified ``'fontpkg'``, also ``cm-super`` or
|
||||
``cm-super-minimal``,
|
||||
* for ``'xelatex'`` or ``'lualatex'`` (see :confval:`latex_engine`),
|
||||
``texlive-xetex`` resp. ``texlive-luatex``, and, if leaving unchanged
|
||||
``'fontpkg'``, ``fonts-freefont-otf``.
|
||||
* ``texlive-lang-cyrillic`` for Cyrillic (even individual letters), and,
|
||||
``cm-super`` or ``cm-super-minimal`` (if default fonts),
|
||||
* ``texlive-lang-greek`` for Greek (even individual letters), and,
|
||||
``cm-super`` or ``cm-super-minimal`` (if default fonts),
|
||||
* ``texlive-xetex`` if :confval:`latex_engine` is ``'xelatex'``,
|
||||
* ``texlive-luatex`` if :confval:`latex_engine` is ``'lualatex'``,
|
||||
* ``fonts-freefont-otf`` if :confval:`latex_engine` is ``'xelatex'``
|
||||
or ``'lualatex'``.
|
||||
|
||||
The testing of Sphinx LaTeX is done on Ubuntu xenial whose TeX distribution
|
||||
is based on a TeXLive 2015 snapshot dated March 2016.
|
||||
@ -207,6 +205,9 @@ The builder's "name" must be given to the **-b** command-line option of
|
||||
.. versionchanged:: 2.0
|
||||
Formerly, testing had been done on Ubuntu trusty (TeXLive 2013).
|
||||
|
||||
.. versionchanged:: 4.0.0
|
||||
TeX Gyre fonts dependency for the default LaTeX font configuration.
|
||||
|
||||
.. note::
|
||||
|
||||
Since 1.6, ``make latexpdf`` uses ``latexmk`` (not on Windows). This
|
||||
|
@ -183,11 +183,20 @@ General configuration
|
||||
|
||||
.. confval:: master_doc
|
||||
|
||||
The document name of the "master" document, that is, the document that
|
||||
Same as :confval:`root_doc`.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
Renamed ``master_doc`` to ``master_doc``.
|
||||
|
||||
.. confval:: root_doc
|
||||
|
||||
The document name of the "root" document, that is, the document that
|
||||
contains the root :rst:dir:`toctree` directive. Default is ``'index'``.
|
||||
|
||||
.. versionchanged:: 2.0
|
||||
The default is changed to ``'index'`` from ``'contents'``.
|
||||
.. versionchanged:: 4.0
|
||||
Renamed ``master_doc`` from ``master_doc``.
|
||||
|
||||
.. confval:: exclude_patterns
|
||||
|
||||
@ -479,11 +488,10 @@ General configuration
|
||||
|
||||
.. confval:: smartquotes_action
|
||||
|
||||
This string, for use with Docutils ``0.14`` or later, customizes the Smart
|
||||
Quotes transform. See the file :file:`smartquotes.py` at the `Docutils
|
||||
repository`__ for details. The default ``'qDe'`` educates normal **q**\
|
||||
uote characters ``"``, ``'``, em- and en-**D**\ ashes ``---``, ``--``, and
|
||||
**e**\ llipses ``...``.
|
||||
This string customizes the Smart Quotes transform. See the file
|
||||
:file:`smartquotes.py` at the `Docutils repository`__ for details. The
|
||||
default ``'qDe'`` educates normal **q**\ uote characters ``"``, ``'``,
|
||||
em- and en-**D**\ ashes ``---``, ``--``, and **e**\ llipses ``...``.
|
||||
|
||||
.. versionadded:: 1.6.6
|
||||
|
||||
@ -834,13 +842,16 @@ documentation on :ref:`intl` for details.
|
||||
:literal-block: literal blocks (``::`` annotation and ``code-block`` directive)
|
||||
:doctest-block: doctest block
|
||||
:raw: raw content
|
||||
:image: image/figure uri and alt
|
||||
:image: image/figure uri
|
||||
|
||||
For example: ``gettext_additional_targets = ['literal-block', 'image']``.
|
||||
|
||||
The default is ``[]``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
The alt text for image is translated by default.
|
||||
|
||||
.. confval:: figure_language_filename
|
||||
|
||||
@ -970,10 +981,15 @@ that use Sphinx's HTMLWriter class.
|
||||
|
||||
The style of line numbers for code-blocks.
|
||||
|
||||
* ``'table'`` -- display line numbers using ``<table>`` tag (default)
|
||||
* ``'inline'`` -- display line numbers using ``<span>`` tag
|
||||
* ``'table'`` -- display line numbers using ``<table>`` tag
|
||||
* ``'inline'`` -- display line numbers using ``<span>`` tag (default)
|
||||
|
||||
.. versionadded:: 3.2
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
It defaults to ``'inline'``.
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
.. confval:: html_context
|
||||
|
||||
@ -986,26 +1002,32 @@ that use Sphinx's HTMLWriter class.
|
||||
.. confval:: html_logo
|
||||
|
||||
If given, this must be the name of an image file (path relative to the
|
||||
:term:`configuration directory`) that is the logo of the docs. It is placed
|
||||
at the top of the sidebar; its width should therefore not exceed 200 pixels.
|
||||
Default: ``None``.
|
||||
:term:`configuration directory`) that is the logo of the docs, or URL that
|
||||
points an image file for the logo. It is placed at the top of the sidebar;
|
||||
its width should therefore not exceed 200 pixels. Default: ``None``.
|
||||
|
||||
.. versionadded:: 0.4.1
|
||||
The image file will be copied to the ``_static`` directory of the output
|
||||
HTML, but only if the file does not already exist there.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
Also accepts the URL for the logo file.
|
||||
|
||||
.. confval:: html_favicon
|
||||
|
||||
If given, this must be the name of an image file (path relative to the
|
||||
:term:`configuration directory`) that is the favicon of the docs. Modern
|
||||
browsers use this as the icon for tabs, windows and bookmarks. It should
|
||||
be a Windows-style icon file (``.ico``), which is 16x16 or 32x32
|
||||
pixels large. Default: ``None``.
|
||||
:term:`configuration directory`) that is the favicon of the docs, or URL that
|
||||
points an image file for the favicon. Modern browsers use this as the icon
|
||||
for tabs, windows and bookmarks. It should be a Windows-style icon file
|
||||
(``.ico``), which is 16x16 or 32x32 pixels large. Default: ``None``.
|
||||
|
||||
.. versionadded:: 0.4
|
||||
The image file will be copied to the ``_static`` directory of the output
|
||||
HTML, but only if the file does not already exist there.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
Also accepts the URL for the favicon.
|
||||
|
||||
.. confval:: html_css_files
|
||||
|
||||
A list of CSS files. The entry must be a *filename* string or a tuple
|
||||
@ -1479,8 +1501,7 @@ that use Sphinx's HTMLWriter class.
|
||||
|
||||
.. confval:: html_experimental_html5_writer
|
||||
|
||||
Output is processed with HTML5 writer. This feature needs docutils 0.13 or
|
||||
newer. Default is ``False``.
|
||||
Output is processed with HTML5 writer. Default is ``False``.
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
@ -1957,8 +1978,8 @@ These options influence LaTeX output.
|
||||
* ``'pdflatex'`` -- PDFLaTeX (default)
|
||||
* ``'xelatex'`` -- XeLaTeX
|
||||
* ``'lualatex'`` -- LuaLaTeX
|
||||
* ``'platex'`` -- pLaTeX (default if :confval:`language` is ``'ja'``)
|
||||
* ``'uplatex'`` -- upLaTeX (experimental)
|
||||
* ``'platex'`` -- pLaTeX
|
||||
* ``'uplatex'`` -- upLaTeX (default if :confval:`language` is ``'ja'``)
|
||||
|
||||
``'pdflatex'``\ 's support for Unicode characters is limited.
|
||||
|
||||
@ -1988,6 +2009,10 @@ These options influence LaTeX output.
|
||||
|
||||
Add ``uplatex`` support.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
``uplatex`` becomes the default setting of Japanese documents.
|
||||
|
||||
Contrarily to :ref:`MathJaX math rendering in HTML output <math-support>`,
|
||||
LaTeX requires some extra configuration to support Unicode literals in
|
||||
:rst:dir:`math`: the only comprehensive solution (as far as we know) is to
|
||||
@ -2007,8 +2032,8 @@ These options influence LaTeX output.
|
||||
*startdocname*
|
||||
String that specifies the :term:`document name` of the LaTeX file's master
|
||||
document. All documents referenced by the *startdoc* document in TOC trees
|
||||
will be included in the LaTeX file. (If you want to use the default master
|
||||
document for your LaTeX build, provide your :confval:`master_doc` here.)
|
||||
will be included in the LaTeX file. (If you want to use the default root
|
||||
document for your LaTeX build, provide your :confval:`root_doc` here.)
|
||||
|
||||
*targetname*
|
||||
File name of the LaTeX file in the output directory.
|
||||
@ -2277,7 +2302,7 @@ These options influence manual page output.
|
||||
String that specifies the :term:`document name` of the manual page's master
|
||||
document. All documents referenced by the *startdoc* document in TOC trees
|
||||
will be included in the manual file. (If you want to use the default
|
||||
master document for your manual pages build, use your :confval:`master_doc`
|
||||
root document for your manual pages build, use your :confval:`root_doc`
|
||||
here.)
|
||||
|
||||
*name*
|
||||
@ -2307,10 +2332,12 @@ These options influence manual page output.
|
||||
|
||||
.. confval:: man_make_section_directory
|
||||
|
||||
If true, make a section directory on build man page. Default is False.
|
||||
If true, make a section directory on build man page. Default is True.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
The default is changed to ``False`` from ``True``.
|
||||
|
||||
.. _texinfo-options:
|
||||
|
||||
@ -2331,7 +2358,7 @@ These options influence Texinfo output.
|
||||
master document. All documents referenced by the *startdoc* document in
|
||||
TOC trees will be included in the Texinfo file. (If you want to use the
|
||||
default master document for your Texinfo build, provide your
|
||||
:confval:`master_doc` here.)
|
||||
:confval:`root_doc` here.)
|
||||
|
||||
*targetname*
|
||||
File name (no extension) of the Texinfo file in the output directory.
|
||||
@ -2687,6 +2714,17 @@ Options for the C++ domain
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
||||
Options for the Python domain
|
||||
-----------------------------
|
||||
|
||||
.. confval:: python_use_unqualified_type_names
|
||||
|
||||
If true, suppress the module name of the python reference if it can be
|
||||
resolved. The default is ``False``.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. note:: This configuration is still in experimental
|
||||
|
||||
Example of configuration file
|
||||
=============================
|
||||
|
@ -89,33 +89,96 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
|
||||
Boil the noodle *time* minutes.
|
||||
|
||||
**Options and advanced usage**
|
||||
.. rubric:: Options
|
||||
|
||||
* If you want to automatically document members, there's a ``members``
|
||||
option::
|
||||
.. rst:directive:option:: members
|
||||
:type: no value or comma separated list
|
||||
|
||||
If set, autodoc will generate document for the members of the target
|
||||
module, class or exception.
|
||||
|
||||
For example::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
|
||||
will document all module members (recursively), and ::
|
||||
will document all module members (recursively), and ::
|
||||
|
||||
.. autoclass:: Noodle
|
||||
:members:
|
||||
|
||||
will document all non-private member functions and properties (that is,
|
||||
those whose name doesn't start with ``_``).
|
||||
will document all class member methods and properties.
|
||||
|
||||
For modules, ``__all__`` will be respected when looking for members unless
|
||||
you give the ``ignore-module-all`` flag option. Without
|
||||
``ignore-module-all``, the order of the members will also be the order in
|
||||
``__all__``.
|
||||
By default, autodoc will not generate document for the members that are
|
||||
private, not having docstrings, inherited from super class, or special
|
||||
members.
|
||||
|
||||
You can also give an explicit list of members; only these will then be
|
||||
documented::
|
||||
For modules, ``__all__`` will be respected when looking for members unless
|
||||
you give the ``ignore-module-all`` flag option. Without
|
||||
``ignore-module-all``, the order of the members will also be the order in
|
||||
``__all__``.
|
||||
|
||||
You can also give an explicit list of members; only these will then be
|
||||
documented::
|
||||
|
||||
.. autoclass:: Noodle
|
||||
:members: eat, slurp
|
||||
|
||||
.. rst:directive:option:: undoc-members
|
||||
:type: no value
|
||||
|
||||
If set, autodoc will also generate document for the members not having
|
||||
docstrings::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. rst:directive:option:: private-members
|
||||
:type: no value or comma separated list
|
||||
|
||||
If set, autodoc will also generate document for the private members
|
||||
(that is, those named like ``_private`` or ``__private``)::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
:private-members:
|
||||
|
||||
It can also take an explicit list of member names to be documented as
|
||||
arguments::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
:private-members: _spicy, _garlickly
|
||||
|
||||
.. versionadded:: 1.1
|
||||
.. versionchanged:: 3.2
|
||||
The option can now take arguments.
|
||||
|
||||
.. rst:directive:option:: special-members
|
||||
:type: no value or comma separated list
|
||||
|
||||
If set, autodoc will also generate document for the special members
|
||||
(that is, those named like ``__special__``)::
|
||||
|
||||
.. autoclass:: my.Class
|
||||
:members:
|
||||
:special-members:
|
||||
|
||||
It can also take an explicit list of member names to be documented as
|
||||
arguments::
|
||||
|
||||
.. autoclass:: my.Class
|
||||
:members:
|
||||
:special-members: __init__, __name__
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. versionchanged:: 1.2
|
||||
The option can now take arguments
|
||||
|
||||
**Options and advanced usage**
|
||||
|
||||
* If you want to make the ``members`` option (or other options described
|
||||
below) the default, see :confval:`autodoc_default_options`.
|
||||
|
||||
@ -139,31 +202,6 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
.. versionchanged:: 3.5
|
||||
The default options can be overridden or extended temporarily.
|
||||
|
||||
* Members without docstrings will be left out, unless you give the
|
||||
``undoc-members`` flag option::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
* "Private" members (that is, those named like ``_private`` or ``__private``)
|
||||
will be included if the ``private-members`` flag option is given::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
:private-members:
|
||||
|
||||
It can also take an explicit list of member names to be documented as
|
||||
arguments::
|
||||
|
||||
.. automodule:: noodle
|
||||
:members:
|
||||
:private-members: _spicy, _garlickly
|
||||
|
||||
.. versionadded:: 1.1
|
||||
.. versionchanged:: 3.2
|
||||
The option can now take arguments.
|
||||
|
||||
* autodoc considers a member private if its docstring contains
|
||||
``:meta private:`` in its :ref:`info-field-lists`.
|
||||
For example:
|
||||
@ -203,21 +241,6 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
* Python "special" members (that is, those named like ``__special__``) will
|
||||
be included if the ``special-members`` flag option is given::
|
||||
|
||||
.. autoclass:: my.Class
|
||||
:members:
|
||||
:private-members:
|
||||
:special-members:
|
||||
|
||||
would document both "private" and "special" members of the class.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. versionchanged:: 1.2
|
||||
The option can now take arguments, i.e. the special members to document.
|
||||
|
||||
* For classes and exceptions, members inherited from base classes will be
|
||||
left out when documenting all members, unless you give the
|
||||
``inherited-members`` option, in addition to ``members``::
|
||||
@ -506,15 +529,19 @@ There are also config values that you can set:
|
||||
looks like a signature, use the line as the signature and remove it from the
|
||||
docstring content.
|
||||
|
||||
If the signature line ends with backslash, autodoc considers the function has
|
||||
multiple signatures and look at the next line of the docstring. It is useful
|
||||
for overloaded function.
|
||||
autodoc will continue to look for multiple signature lines,
|
||||
stopping at the first line that does not look like a signature.
|
||||
This is useful for declaring overloaded function signatures.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
.. versionchanged:: 3.1
|
||||
|
||||
Support overloaded signatures
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
Overloaded signatures do not need to be separated by a backslash
|
||||
|
||||
.. confval:: autodoc_mock_imports
|
||||
|
||||
This value contains a list of modules to be mocked up. This is useful when
|
||||
@ -548,6 +575,19 @@ There are also config values that you can set:
|
||||
|
||||
New option ``'description'`` is added.
|
||||
|
||||
.. confval:: autodoc_typehints_description_target
|
||||
|
||||
This value controls whether the types of undocumented parameters and return
|
||||
values are documented when ``autodoc_typehints`` is set to ``description``.
|
||||
|
||||
The default value is ``"all"``, meaning that types are documented for all
|
||||
parameters and return values, whether they are documented or not.
|
||||
|
||||
When set to ``"documented"``, types will only be documented for a parameter
|
||||
or a return value that is already documented by the docstring.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. confval:: autodoc_type_aliases
|
||||
|
||||
A dictionary for users defined `type aliases`__ that maps a type name to the
|
||||
@ -586,6 +626,16 @@ There are also config values that you can set:
|
||||
.. __: https://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. confval:: autodoc_preserve_defaults
|
||||
|
||||
If True, the default argument values of functions will be not evaluated on
|
||||
generating document. It preserves them as is in the source code.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
Added as an experimental feature. This will be integrated into autodoc core
|
||||
in the future.
|
||||
|
||||
.. confval:: autodoc_warningiserror
|
||||
|
||||
This value controls the behavior of :option:`sphinx-build -W` during
|
||||
@ -597,7 +647,7 @@ There are also config values that you can set:
|
||||
|
||||
This value controls the docstrings inheritance.
|
||||
If set to True the docstring for classes or methods, if not explicitly set,
|
||||
is inherited form parents.
|
||||
is inherited from parents.
|
||||
|
||||
The default is ``True``.
|
||||
|
||||
|
@ -19,11 +19,13 @@ The :mod:`sphinx.ext.autosummary` extension does this in two parts:
|
||||
that contain links to the documented items, and short summary blurbs
|
||||
extracted from their docstrings.
|
||||
|
||||
2. Optionally, the convenience script :program:`sphinx-autogen` or the new
|
||||
:confval:`autosummary_generate` config value can be used to generate short
|
||||
"stub" files for the entries listed in the :rst:dir:`autosummary` directives.
|
||||
These files by default contain only the corresponding
|
||||
:mod:`sphinx.ext.autodoc` directive, but can be customized with templates.
|
||||
2. A :rst:dir:`autosummary` directive also generates short "stub" files for the
|
||||
entries listed in its content. These files by default contain only the
|
||||
corresponding :mod:`sphinx.ext.autodoc` directive, but can be customized with
|
||||
templates.
|
||||
|
||||
The :program:`sphinx-autogen` script is also able to generate "stub" files
|
||||
from command line.
|
||||
|
||||
.. rst:directive:: autosummary
|
||||
|
||||
@ -161,7 +163,7 @@ also use these config values:
|
||||
.. confval:: autosummary_generate
|
||||
|
||||
Boolean indicating whether to scan all found documents for autosummary
|
||||
directives, and to generate stub pages for each. It is disabled by default.
|
||||
directives, and to generate stub pages for each. It is enabled by default.
|
||||
|
||||
Can also be a list of documents for which stub pages should be generated.
|
||||
|
||||
@ -173,6 +175,10 @@ also use these config values:
|
||||
Emits :event:`autodoc-skip-member` event as :mod:`~sphinx.ext.autodoc`
|
||||
does.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
Enabled by default.
|
||||
|
||||
.. confval:: autosummary_generate_overwrite
|
||||
|
||||
If true, autosummary overwrites existing files by generated stub pages.
|
||||
|
@ -140,6 +140,12 @@ are built:
|
||||
.. module:: sphinx.ext.mathjax
|
||||
:synopsis: Render math using JavaScript via MathJax.
|
||||
|
||||
.. warning::
|
||||
Version 4.0 changes the version of MathJax used to version 3. You may need to
|
||||
override ``mathjax_path`` to
|
||||
``https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML``
|
||||
or update your configuration options for version 3.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
This extension puts math as-is into the HTML files. The JavaScript package
|
||||
@ -161,14 +167,14 @@ Sphinx but is set to automatically include it from a third-party site.
|
||||
MathJax.
|
||||
|
||||
The default is the ``https://`` URL that loads the JS files from the
|
||||
`cdnjs`__ Content Delivery Network. See the `MathJax Getting Started
|
||||
`jsdelivr`__ Content Delivery Network. See the `MathJax Getting Started
|
||||
page`__ for details. If you want MathJax to be available offline or
|
||||
without including resources from a third-party site, you have to
|
||||
download it and set this value to a different path.
|
||||
|
||||
__ https://cdnjs.com
|
||||
__ https://www.jsdelivr.com/
|
||||
|
||||
__ https://docs.mathjax.org/en/latest/start.html
|
||||
__ https://www.mathjax.org/#gettingstarted
|
||||
|
||||
The path can be absolute or relative; if it is relative, it is relative to
|
||||
the ``_static`` directory of the built docs.
|
||||
|
@ -12,7 +12,7 @@ Installing Sphinx
|
||||
Overview
|
||||
--------
|
||||
|
||||
Sphinx is written in `Python`__ and supports Python 3.5+. It builds upon the
|
||||
Sphinx is written in `Python`__ and supports Python 3.6+. It builds upon the
|
||||
shoulders of many third-party libraries such as `Docutils`__ and `Jinja`__,
|
||||
which are installed when Sphinx is installed.
|
||||
|
||||
@ -107,7 +107,30 @@ Anaconda
|
||||
Windows
|
||||
-------
|
||||
|
||||
.. todo:: Could we start packaging this?
|
||||
Sphinx can be install using `Chocolatey`__ or
|
||||
:ref:`installed manually <windows-other-method>`.
|
||||
|
||||
__ https://chocolatey.org/
|
||||
|
||||
Chocolatey
|
||||
~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
$ choco install sphinx
|
||||
|
||||
You would need to `install Chocolatey
|
||||
<https://chocolatey.org/install/>`_
|
||||
before running this.
|
||||
|
||||
For more information, refer to the `chocolatey page`__.
|
||||
|
||||
__ https://chocolatey.org/packages/sphinx/
|
||||
|
||||
.. _windows-other-method:
|
||||
|
||||
Other Methods
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Most Windows users do not have Python installed by default, so we begin with
|
||||
the installation of Python itself. To check if you already have Python
|
||||
@ -183,7 +206,7 @@ Please choose one for your purpose.
|
||||
When using docker images, please use ``docker run`` command to invoke sphinx commands. For example,
|
||||
you can use following command to create a Sphinx project::
|
||||
|
||||
$ docker run --rm -v /path/to/document:/docs sphinxdoc/sphinx sphinx-quickstart
|
||||
$ docker run -it --rm -v /path/to/document:/docs sphinxdoc/sphinx sphinx-quickstart
|
||||
|
||||
And you can following command this to build HTML document::
|
||||
|
||||
|
@ -13,7 +13,7 @@ Sphinx focuses on documentation, in particular handwritten documentation,
|
||||
however, Sphinx can also be used to generate blogs, homepages and even books.
|
||||
Much of Sphinx's power comes from the richness of its default plain-text markup
|
||||
format, :doc:`reStructuredText </usage/restructuredtext/index>`, along with
|
||||
it's :doc:`significant extensibility capabilities </development/index>`.
|
||||
its :doc:`significant extensibility capabilities </development/index>`.
|
||||
|
||||
The goal of this document is to give you a quick taste of what Sphinx is and
|
||||
how you might use it. When you're done here, you can check out the
|
||||
|
@ -288,7 +288,7 @@ Roles
|
||||
-----
|
||||
|
||||
A role or "custom interpreted text role" (:duref:`ref <roles>`) is an inline
|
||||
piece of explicit markup. It signifies that that the enclosed text should be
|
||||
piece of explicit markup. It signifies that the enclosed text should be
|
||||
interpreted in a specific way. Sphinx uses this to provide semantic markup and
|
||||
cross-referencing of identifiers, as described in the appropriate section. The
|
||||
general syntax is ``:rolename:`content```.
|
||||
|
@ -197,9 +197,9 @@ tables of contents. The ``toctree`` directive is the central element.
|
||||
<metadata>` to let a document be built, but notify Sphinx that it is not
|
||||
reachable via a toctree.
|
||||
|
||||
The "master document" (selected by :confval:`master_doc`) is the "root" of
|
||||
the TOC tree hierarchy. It can be used as the documentation's main page, or
|
||||
as a "full table of contents" if you don't give a ``maxdepth`` option.
|
||||
The "root document" (selected by :confval:`root_doc`) is the "root" of the TOC
|
||||
tree hierarchy. It can be used as the documentation's main page, or as a
|
||||
"full table of contents" if you don't give a ``maxdepth`` option.
|
||||
|
||||
.. versionchanged:: 0.3
|
||||
Added "globbing" option.
|
||||
@ -404,10 +404,15 @@ Showing code examples
|
||||
single: sourcecode
|
||||
|
||||
There are multiple ways to show syntax-highlighted literal code blocks in
|
||||
Sphinx: using :ref:`reST doctest blocks <rst-doctest-blocks>`; using :ref:`reST
|
||||
literal blocks <rst-literal-blocks>`, optionally in combination with the
|
||||
:rst:dir:`highlight` directive; using the :rst:dir:`code-block` directive; and
|
||||
using the :rst:dir:`literalinclude` directive. Doctest blocks can only be used
|
||||
Sphinx:
|
||||
|
||||
* using :ref:`reST doctest blocks <rst-doctest-blocks>`;
|
||||
* using :ref:`reST literal blocks <rst-literal-blocks>`, optionally in
|
||||
combination with the :rst:dir:`highlight` directive;
|
||||
* using the :rst:dir:`code-block` directive;
|
||||
* and using the :rst:dir:`literalinclude` directive.
|
||||
|
||||
Doctest blocks can only be used
|
||||
to show interactive Python sessions, while the remaining three can be used for
|
||||
other languages. Of these three, literal blocks are useful when an entire
|
||||
document, or at least large sections of it, use code blocks with the same
|
||||
|
@ -202,6 +202,14 @@ The following directives are provided for module and class contents:
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
.. rst:directive:option:: canonical
|
||||
:type: full qualified name including module name
|
||||
|
||||
Describe the location where the object is defined if the object is
|
||||
imported from other modules
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. rst:directive:: .. py:data:: name
|
||||
|
||||
Describes global data in a module, including both variables and values used
|
||||
@ -220,6 +228,14 @@ The following directives are provided for module and class contents:
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
.. rst:directive:option:: canonical
|
||||
:type: full qualified name including module name
|
||||
|
||||
Describe the location where the object is defined if the object is
|
||||
imported from other modules
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. rst:directive:: .. py:exception:: name
|
||||
|
||||
Describes an exception class. The signature can, but need not include
|
||||
@ -259,6 +275,14 @@ The following directives are provided for module and class contents:
|
||||
|
||||
.. rubric:: options
|
||||
|
||||
.. rst:directive:option:: canonical
|
||||
:type: full qualified name including module name
|
||||
|
||||
Describe the location where the object is defined if the object is
|
||||
imported from other modules
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. rst:directive:option:: final
|
||||
:type: no value
|
||||
|
||||
@ -284,6 +308,30 @@ The following directives are provided for module and class contents:
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
.. rst:directive:option:: canonical
|
||||
:type: full qualified name including module name
|
||||
|
||||
Describe the location where the object is defined if the object is
|
||||
imported from other modules
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. rst:directive:: .. py:property:: name
|
||||
|
||||
Describes an object property.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. rubric:: options
|
||||
|
||||
.. rst:directive:option:: abstractmethod
|
||||
:type: no value
|
||||
|
||||
Indicate the property is abstract.
|
||||
|
||||
.. rst:directive:option:: type: type of the property
|
||||
:type: text
|
||||
|
||||
.. rst:directive:: .. py:method:: name(parameters)
|
||||
|
||||
Describes an object method. The parameters should not include the ``self``
|
||||
@ -307,6 +355,14 @@ The following directives are provided for module and class contents:
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
.. rst:directive:option:: canonical
|
||||
:type: full qualified name including module name
|
||||
|
||||
Describe the location where the object is defined if the object is
|
||||
imported from other modules
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
.. rst:directive:option:: classmethod
|
||||
:type: no value
|
||||
|
||||
@ -328,6 +384,10 @@ The following directives are provided for module and class contents:
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
Use :rst:dir:`py:property` instead.
|
||||
|
||||
.. rst:directive:option:: staticmethod
|
||||
:type: no value
|
||||
|
||||
@ -544,6 +604,8 @@ a matching identifier is found:
|
||||
|
||||
Reference a data attribute of an object.
|
||||
|
||||
.. note:: The role is also able to refer to property.
|
||||
|
||||
.. rst:role:: py:exc
|
||||
|
||||
Reference an exception. A dotted name may be used.
|
||||
@ -1848,7 +1910,7 @@ currently Ada_, CoffeeScript_, Erlang_, HTTP_, Lasso_, MATLAB_, PHP_, and Ruby_
|
||||
domains. Also available are domains for `Chapel`_, `Common Lisp`_, dqn_, Go_,
|
||||
Jinja_, Operation_, and Scala_.
|
||||
|
||||
.. _sphinx-contrib: https://bitbucket.org/birkenfeld/sphinx-contrib/
|
||||
.. _sphinx-contrib: https://github.com/sphinx-contrib
|
||||
|
||||
.. _Ada: https://pypi.org/project/sphinxcontrib-adadomain/
|
||||
.. _Chapel: https://pypi.org/project/sphinxcontrib-chapeldomain/
|
||||
|
@ -334,38 +334,15 @@ These themes are:
|
||||
Third Party Themes
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. cssclass:: longtable
|
||||
There are many third-party themes available for Sphinx. Some of these are for
|
||||
general use, while others are specific to an individual project.
|
||||
|
||||
+--------------------+--------------------+
|
||||
| **Theme overview** | |
|
||||
+--------------------+--------------------+
|
||||
| |sphinx_rtd_theme| | |
|
||||
| | |
|
||||
| *sphinx_rtd_theme* | |
|
||||
+--------------------+--------------------+
|
||||
sphinx-themes.org__ is a gallery that showcases various themes for Sphinx,
|
||||
with demo documentation rendered under each theme. Themes can also be found
|
||||
on PyPI__ (using the classifier ``Framework :: Sphinx :: Theme``), GitHub__
|
||||
and GitLab__.
|
||||
|
||||
.. |sphinx_rtd_theme| image:: /_static/themes/sphinx_rtd_theme.png
|
||||
|
||||
There are many third-party themes available. Some of these are general use,
|
||||
while others are specific to an individual project. A section of third-party
|
||||
themes is listed below. Many more can be found on PyPI__, GitHub__, GitLab__ and
|
||||
sphinx-themes.org__.
|
||||
|
||||
.. cssclass:: clear
|
||||
|
||||
**sphinx_rtd_theme**
|
||||
`Read the Docs Sphinx Theme`_.
|
||||
This is a mobile-friendly sphinx theme that was made for readthedocs.org.
|
||||
View a working demo over on readthedocs.org. You can get install and options
|
||||
information at `Read the Docs Sphinx Theme`_ page.
|
||||
|
||||
.. _Read the Docs Sphinx Theme: https://pypi.org/project/sphinx_rtd_theme/
|
||||
|
||||
.. versionchanged:: 1.4
|
||||
**sphinx_rtd_theme** has become optional.
|
||||
|
||||
|
||||
.. __: https://pypi.org/search/?q=&o=&c=Framework+%3A%3A+Sphinx+%3A%3A+Theme
|
||||
.. __: https://github.com/search?utf8=%E2%9C%93&q=sphinx+theme&type=
|
||||
.. __: https://gitlab.com/explore?name=sphinx+theme
|
||||
.. __: https://sphinx-themes.org/
|
||||
.. __: https://pypi.org/search/?q=&o=&c=Framework+%3A%3A+Sphinx+%3A%3A+Theme
|
||||
.. __: https://github.com/search?utf8=%E2%9C%93&q=sphinx+theme
|
||||
.. __: https://gitlab.com/explore?name=sphinx+theme
|
||||
|
@ -45,7 +45,7 @@ paths =
|
||||
line_length = 95
|
||||
|
||||
[mypy]
|
||||
python_version = 3.5
|
||||
python_version = 3.6
|
||||
disallow_incomplete_defs = True
|
||||
show_column_numbers = True
|
||||
show_error_context = True
|
||||
@ -61,7 +61,6 @@ filterwarnings =
|
||||
ignore::DeprecationWarning:docutils.io
|
||||
ignore::DeprecationWarning:pyximport.pyximport
|
||||
ignore::ImportWarning:importlib._bootstrap
|
||||
ignore::PendingDeprecationWarning:sphinx.util.pycompat
|
||||
markers =
|
||||
apidoc
|
||||
setup_command
|
||||
|
9
setup.py
9
setup.py
@ -10,8 +10,8 @@ import sphinx
|
||||
with open('README.rst') as f:
|
||||
long_desc = f.read()
|
||||
|
||||
if sys.version_info < (3, 5):
|
||||
print('ERROR: Sphinx requires at least Python 3.5 to run.')
|
||||
if sys.version_info < (3, 6):
|
||||
print('ERROR: Sphinx requires at least Python 3.6 to run.')
|
||||
sys.exit(1)
|
||||
|
||||
install_requires = [
|
||||
@ -23,7 +23,7 @@ install_requires = [
|
||||
'sphinxcontrib-qthelp',
|
||||
'Jinja2>=2.3',
|
||||
'Pygments>=2.0',
|
||||
'docutils>=0.12',
|
||||
'docutils>=0.14',
|
||||
'snowballstemmer>=1.1',
|
||||
'babel>=1.3',
|
||||
'alabaster>=0.7,<0.8',
|
||||
@ -200,7 +200,6 @@ setup(
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
@ -242,7 +241,7 @@ setup(
|
||||
'build_sphinx = sphinx.setup_command:BuildDoc',
|
||||
],
|
||||
},
|
||||
python_requires=">=3.5",
|
||||
python_requires=">=3.6",
|
||||
install_requires=install_requires,
|
||||
extras_require=extras_require,
|
||||
cmdclass=cmdclass,
|
||||
|
@ -19,11 +19,6 @@ from subprocess import PIPE
|
||||
|
||||
from .deprecation import RemovedInNextVersionWarning
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Any # NOQA
|
||||
|
||||
|
||||
# by default, all DeprecationWarning under sphinx package will be emit.
|
||||
# Users can avoid this by using environment variable: PYTHONWARNINGS=
|
||||
if 'PYTHONWARNINGS' not in os.environ:
|
||||
@ -32,8 +27,8 @@ if 'PYTHONWARNINGS' not in os.environ:
|
||||
warnings.filterwarnings('ignore', "'U' mode is deprecated",
|
||||
DeprecationWarning, module='docutils.io')
|
||||
|
||||
__version__ = '3.5.4+'
|
||||
__released__ = '3.5.4' # used when Sphinx builds its own docs
|
||||
__version__ = '4.0.0+'
|
||||
__released__ = '4.0.0' # used when Sphinx builds its own docs
|
||||
|
||||
#: Version info for better programmatic use.
|
||||
#:
|
||||
@ -43,7 +38,7 @@ __released__ = '3.5.4' # used when Sphinx builds its own docs
|
||||
#:
|
||||
#: .. versionadded:: 1.2
|
||||
#: Before version 1.2, check the string ``sphinx.__version__``.
|
||||
version_info = (3, 5, 4, 'beta', 0)
|
||||
version_info = (4, 0, 0, 'beta', 0)
|
||||
|
||||
package_dir = path.abspath(path.dirname(__file__))
|
||||
|
||||
@ -57,8 +52,8 @@ if __version__.endswith('+'):
|
||||
try:
|
||||
ret = subprocess.run(['git', 'show', '-s', '--pretty=format:%h'],
|
||||
cwd=package_dir,
|
||||
stdout=PIPE, stderr=PIPE)
|
||||
stdout=PIPE, stderr=PIPE, encoding='ascii')
|
||||
if ret.stdout:
|
||||
__display_version__ += '/' + ret.stdout.decode('ascii').strip()
|
||||
__display_version__ += '/' + ret.stdout.strip()
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -8,16 +8,12 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict, List, Sequence
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Sequence
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
from docutils.nodes import Element
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -108,7 +104,7 @@ class toctree(nodes.General, nodes.Element, translatable):
|
||||
self['caption'] = translated_message
|
||||
|
||||
def extract_original_messages(self) -> List[str]:
|
||||
messages = [] # type: List[str]
|
||||
messages: List[str] = []
|
||||
|
||||
# toctree entries
|
||||
messages.extend(self.get('rawentries', []))
|
||||
@ -213,7 +209,7 @@ class desc_content(nodes.General, nodes.Element):
|
||||
|
||||
class desc_sig_element(nodes.inline):
|
||||
"""Common parent class of nodes for inline text of a signature."""
|
||||
classes = [] # type: List[str]
|
||||
classes: List[str] = []
|
||||
|
||||
def __init__(self, rawsource: str = '', text: str = '',
|
||||
*children: Element, **attributes: Any) -> None:
|
||||
@ -342,6 +338,54 @@ class pending_xref(nodes.Inline, nodes.Element):
|
||||
"""
|
||||
|
||||
|
||||
class pending_xref_condition(nodes.Inline, nodes.TextElement):
|
||||
"""Node for cross-references that are used to choose appropriate
|
||||
content of the reference by conditions on the resolving phase.
|
||||
|
||||
When the :py:class:`pending_xref` node contains one or more
|
||||
**pending_xref_condition** nodes, the cross-reference resolver
|
||||
should choose the content of the reference using defined conditions
|
||||
in ``condition`` attribute of each pending_xref_condition nodes::
|
||||
|
||||
<pending_xref refdomain="py" reftarget="io.StringIO ...>
|
||||
<pending_xref_condition condition="resolved">
|
||||
<literal>
|
||||
StringIO
|
||||
<pending_xref_condition condition="*">
|
||||
<literal>
|
||||
io.StringIO
|
||||
|
||||
After the processing of cross-reference resolver, one of the content node
|
||||
under pending_xref_condition node is chosen by its condition and to be
|
||||
removed all of pending_xref_condition nodes::
|
||||
|
||||
# When resolved the cross-reference successfully
|
||||
<reference>
|
||||
<literal>
|
||||
StringIO
|
||||
|
||||
# When resolution is failed
|
||||
<reference>
|
||||
<literal>
|
||||
io.StringIO
|
||||
|
||||
.. note:: This node is only allowed to be placed under pending_xref node.
|
||||
It is not allows to place it under other nodes. In addition,
|
||||
pending_xref node must contain only pending_xref_condition
|
||||
nodes if it contains one or more pending_xref_condition nodes.
|
||||
|
||||
The pending_xref_condition node should have **condition** attribute.
|
||||
Domains can be store their individual conditions into the attribute to
|
||||
filter contents on resolving phase. As a reserved condition name,
|
||||
``condition="*"`` is used for the fallback of resolution failure.
|
||||
Additionally, as a recommended condition name, ``condition="resolved"``
|
||||
is used for the representation of resolstion success in the intersphinx
|
||||
module.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
"""
|
||||
|
||||
|
||||
class number_reference(nodes.reference):
|
||||
"""Node for number references, similar to pending_xref."""
|
||||
|
||||
@ -362,20 +406,6 @@ class literal_strong(nodes.strong, not_smartquotable):
|
||||
"""
|
||||
|
||||
|
||||
class abbreviation(nodes.abbreviation):
|
||||
"""Node for abbreviations with explanations.
|
||||
|
||||
.. deprecated:: 2.0
|
||||
"""
|
||||
|
||||
def __init__(self, rawsource: str = '', text: str = '',
|
||||
*children: Node, **attributes: Any) -> None:
|
||||
warnings.warn("abbrevition node for Sphinx was replaced by docutils'.",
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
super().__init__(rawsource, text, *children, **attributes)
|
||||
|
||||
|
||||
class manpage(nodes.Inline, nodes.FixedTextElement):
|
||||
"""Node for references to manpages."""
|
||||
|
||||
|
@ -14,11 +14,10 @@ import os
|
||||
import pickle
|
||||
import platform
|
||||
import sys
|
||||
import warnings
|
||||
from collections import deque
|
||||
from io import StringIO
|
||||
from os import path
|
||||
from typing import IO, Any, Callable, Dict, List, Optional, Tuple, Union
|
||||
from typing import IO, TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Type, Union
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, TextElement
|
||||
@ -30,14 +29,13 @@ from pygments.lexer import Lexer
|
||||
import sphinx
|
||||
from sphinx import locale, package_dir
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.domains import Domain, Index
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment.collectors import EnvironmentCollector
|
||||
from sphinx.errors import ApplicationError, ConfigError, VersionRequirementError
|
||||
from sphinx.events import EventManager
|
||||
from sphinx.extension import Extension
|
||||
from sphinx.highlighting import lexer_classes, lexers
|
||||
from sphinx.highlighting import lexer_classes
|
||||
from sphinx.locale import __
|
||||
from sphinx.project import Project
|
||||
from sphinx.registry import SphinxComponentRegistry
|
||||
@ -52,10 +50,7 @@ from sphinx.util.osutil import abspath, ensuredir, relpath
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.typing import RoleFunction, TitleGetter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from docutils.nodes import Node # NOQA
|
||||
|
||||
from sphinx.builders import Builder
|
||||
@ -135,6 +130,9 @@ class Sphinx:
|
||||
:ivar outdir: Directory for storing build documents.
|
||||
"""
|
||||
|
||||
warningiserror: bool
|
||||
_warncount: int
|
||||
|
||||
def __init__(self, srcdir: str, confdir: Optional[str], outdir: str, doctreedir: str,
|
||||
buildername: str, confoverrides: Dict = None,
|
||||
status: IO = sys.stdout, warning: IO = sys.stderr,
|
||||
@ -142,12 +140,12 @@ class Sphinx:
|
||||
verbosity: int = 0, parallel: int = 0, keep_going: bool = False) -> None:
|
||||
self.phase = BuildPhase.INITIALIZATION
|
||||
self.verbosity = verbosity
|
||||
self.extensions = {} # type: Dict[str, Extension]
|
||||
self.builder = None # type: Builder
|
||||
self.env = None # type: BuildEnvironment
|
||||
self.project = None # type: Project
|
||||
self.extensions: Dict[str, Extension] = {}
|
||||
self.builder: Builder = None
|
||||
self.env: BuildEnvironment = None
|
||||
self.project: Project = None
|
||||
self.registry = SphinxComponentRegistry()
|
||||
self.html_themes = {} # type: Dict[str, str]
|
||||
self.html_themes: Dict[str, str] = {}
|
||||
|
||||
# validate provided directories
|
||||
self.srcdir = abspath(srcdir)
|
||||
@ -175,14 +173,14 @@ class Sphinx:
|
||||
self.parallel = parallel
|
||||
|
||||
if status is None:
|
||||
self._status = StringIO() # type: IO
|
||||
self._status: IO = StringIO()
|
||||
self.quiet = True
|
||||
else:
|
||||
self._status = status
|
||||
self.quiet = False
|
||||
|
||||
if warning is None:
|
||||
self._warning = StringIO() # type: IO
|
||||
self._warning: IO = StringIO()
|
||||
else:
|
||||
self._warning = warning
|
||||
self._warncount = 0
|
||||
@ -197,7 +195,7 @@ class Sphinx:
|
||||
|
||||
# keep last few messages for traceback
|
||||
# This will be filled by sphinx.util.logging.LastMessagesWriter
|
||||
self.messagelog = deque(maxlen=10) # type: deque
|
||||
self.messagelog: deque = deque(maxlen=10)
|
||||
|
||||
# say hello to the world
|
||||
logger.info(bold(__('Running Sphinx v%s') % sphinx.__display_version__))
|
||||
@ -294,7 +292,7 @@ class Sphinx:
|
||||
if catalog.domain == 'sphinx' and catalog.is_outdated():
|
||||
catalog.write_mo(self.config.language)
|
||||
|
||||
locale_dirs = list(repo.locale_dirs) # type: List[Optional[str]]
|
||||
locale_dirs: List[Optional[str]] = list(repo.locale_dirs)
|
||||
locale_dirs += [None]
|
||||
locale_dirs += [path.join(package_dir, 'locale')]
|
||||
|
||||
@ -445,7 +443,7 @@ class Sphinx:
|
||||
self.events.disconnect(listener_id)
|
||||
|
||||
def emit(self, event: str, *args: Any,
|
||||
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List:
|
||||
allowed_exceptions: Tuple[Type[Exception], ...] = ()) -> List:
|
||||
"""Emit *event* and pass *arguments* to the callback functions.
|
||||
|
||||
Return the return values of all callbacks as a list. Do not emit core
|
||||
@ -462,7 +460,7 @@ class Sphinx:
|
||||
return self.events.emit(event, *args, allowed_exceptions=allowed_exceptions)
|
||||
|
||||
def emit_firstresult(self, event: str, *args: Any,
|
||||
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any:
|
||||
allowed_exceptions: Tuple[Type[Exception], ...] = ()) -> Any:
|
||||
"""Emit *event* and pass *arguments* to the callback functions.
|
||||
|
||||
Return the result of the first callback that doesn't return ``None``.
|
||||
@ -481,7 +479,7 @@ class Sphinx:
|
||||
|
||||
# registering addon parts
|
||||
|
||||
def add_builder(self, builder: "Type[Builder]", override: bool = False) -> None:
|
||||
def add_builder(self, builder: Type["Builder"], override: bool = False) -> None:
|
||||
"""Register a new builder.
|
||||
|
||||
:param builder: A builder class
|
||||
@ -528,8 +526,7 @@ class Sphinx:
|
||||
``'env'``) to a string. However, booleans are still accepted and
|
||||
converted internally.
|
||||
"""
|
||||
logger.debug('[app] adding config value: %r',
|
||||
(name, default, rebuild) + ((types,) if types else ()))
|
||||
logger.debug('[app] adding config value: %r', (name, default, rebuild, types))
|
||||
if rebuild in (False, True):
|
||||
rebuild = 'env' if rebuild else ''
|
||||
self.config.add(name, default, rebuild, types)
|
||||
@ -544,7 +541,7 @@ class Sphinx:
|
||||
logger.debug('[app] adding event: %r', name)
|
||||
self.events.add(name)
|
||||
|
||||
def set_translator(self, name: str, translator_class: "Type[nodes.NodeVisitor]",
|
||||
def set_translator(self, name: str, translator_class: Type[nodes.NodeVisitor],
|
||||
override: bool = False) -> None:
|
||||
"""Register or override a Docutils translator class.
|
||||
|
||||
@ -563,7 +560,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_translator(name, translator_class, override=override)
|
||||
|
||||
def add_node(self, node: "Type[Element]", override: bool = False,
|
||||
def add_node(self, node: Type[Element], override: bool = False,
|
||||
**kwargs: Tuple[Callable, Optional[Callable]]) -> None:
|
||||
"""Register a Docutils node class.
|
||||
|
||||
@ -607,7 +604,7 @@ class Sphinx:
|
||||
docutils.register_node(node)
|
||||
self.registry.add_translation_handlers(node, **kwargs)
|
||||
|
||||
def add_enumerable_node(self, node: "Type[Element]", figtype: str,
|
||||
def add_enumerable_node(self, node: Type[Element], figtype: str,
|
||||
title_getter: TitleGetter = None, override: bool = False,
|
||||
**kwargs: Tuple[Callable, Callable]) -> None:
|
||||
"""Register a Docutils node class as a numfig target.
|
||||
@ -636,7 +633,7 @@ class Sphinx:
|
||||
self.registry.add_enumerable_node(node, figtype, title_getter, override=override)
|
||||
self.add_node(node, override=override, **kwargs)
|
||||
|
||||
def add_directive(self, name: str, cls: "Type[Directive]", override: bool = False) -> None:
|
||||
def add_directive(self, name: str, cls: Type[Directive], override: bool = False) -> None:
|
||||
"""Register a Docutils directive.
|
||||
|
||||
:param name: The name of directive
|
||||
@ -726,7 +723,7 @@ class Sphinx:
|
||||
role = roles.GenericRole(name, nodeclass)
|
||||
docutils.register_role(name, role)
|
||||
|
||||
def add_domain(self, domain: "Type[Domain]", override: bool = False) -> None:
|
||||
def add_domain(self, domain: Type[Domain], override: bool = False) -> None:
|
||||
"""Register a domain.
|
||||
|
||||
:param domain: A domain class
|
||||
@ -740,7 +737,7 @@ class Sphinx:
|
||||
self.registry.add_domain(domain, override=override)
|
||||
|
||||
def add_directive_to_domain(self, domain: str, name: str,
|
||||
cls: "Type[Directive]", override: bool = False) -> None:
|
||||
cls: Type[Directive], override: bool = False) -> None:
|
||||
"""Register a Docutils directive in a domain.
|
||||
|
||||
Like :meth:`add_directive`, but the directive is added to the domain
|
||||
@ -777,7 +774,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_role_to_domain(domain, name, role, override=override)
|
||||
|
||||
def add_index_to_domain(self, domain: str, index: "Type[Index]", override: bool = False
|
||||
def add_index_to_domain(self, domain: str, index: Type[Index], override: bool = False
|
||||
) -> None:
|
||||
"""Register a custom index for a domain.
|
||||
|
||||
@ -795,7 +792,7 @@ class Sphinx:
|
||||
self.registry.add_index_to_domain(domain, index)
|
||||
|
||||
def add_object_type(self, directivename: str, rolename: str, indextemplate: str = '',
|
||||
parse_node: Callable = None, ref_nodeclass: "Type[TextElement]" = None,
|
||||
parse_node: Callable = None, ref_nodeclass: Type[TextElement] = None,
|
||||
objname: str = '', doc_field_types: List = [], override: bool = False
|
||||
) -> None:
|
||||
"""Register a new object type.
|
||||
@ -862,7 +859,7 @@ class Sphinx:
|
||||
override=override)
|
||||
|
||||
def add_crossref_type(self, directivename: str, rolename: str, indextemplate: str = '',
|
||||
ref_nodeclass: "Type[TextElement]" = None, objname: str = '',
|
||||
ref_nodeclass: Type[TextElement] = None, objname: str = '',
|
||||
override: bool = False) -> None:
|
||||
"""Register a new crossref object type.
|
||||
|
||||
@ -900,7 +897,7 @@ class Sphinx:
|
||||
indextemplate, ref_nodeclass, objname,
|
||||
override=override)
|
||||
|
||||
def add_transform(self, transform: "Type[Transform]") -> None:
|
||||
def add_transform(self, transform: Type[Transform]) -> None:
|
||||
"""Register a Docutils transform to be applied after parsing.
|
||||
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to
|
||||
@ -935,7 +932,7 @@ class Sphinx:
|
||||
""" # NOQA
|
||||
self.registry.add_transform(transform)
|
||||
|
||||
def add_post_transform(self, transform: "Type[Transform]") -> None:
|
||||
def add_post_transform(self, transform: Type[Transform]) -> None:
|
||||
"""Register a Docutils transform to be applied before writing.
|
||||
|
||||
Add the standard docutils :class:`Transform` subclass *transform* to
|
||||
@ -946,13 +943,6 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_post_transform(transform)
|
||||
|
||||
def add_javascript(self, filename: str, **kwargs: Any) -> None:
|
||||
"""An alias of :meth:`add_js_file`."""
|
||||
warnings.warn('The app.add_javascript() is deprecated. '
|
||||
'Please use app.add_js_file() instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
self.add_js_file(filename, **kwargs)
|
||||
|
||||
def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None:
|
||||
"""Register a JavaScript file to include in the HTML output.
|
||||
|
||||
@ -1032,6 +1022,8 @@ class Sphinx:
|
||||
|
||||
* - Priority
|
||||
- Main purpose in Sphinx
|
||||
* - 200
|
||||
- default priority for built-in CSS files
|
||||
* - 500
|
||||
- default priority for extensions
|
||||
* - 800
|
||||
@ -1061,24 +1053,6 @@ class Sphinx:
|
||||
if hasattr(self.builder, 'add_css_file'):
|
||||
self.builder.add_css_file(filename, priority=priority, **kwargs) # type: ignore
|
||||
|
||||
def add_stylesheet(self, filename: str, alternate: bool = False, title: str = None
|
||||
) -> None:
|
||||
"""An alias of :meth:`add_css_file`."""
|
||||
warnings.warn('The app.add_stylesheet() is deprecated. '
|
||||
'Please use app.add_css_file() instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
attributes = {} # type: Dict[str, Any]
|
||||
if alternate:
|
||||
attributes['rel'] = 'alternate stylesheet'
|
||||
else:
|
||||
attributes['rel'] = 'stylesheet'
|
||||
|
||||
if title:
|
||||
attributes['title'] = title
|
||||
|
||||
self.add_css_file(filename, **attributes)
|
||||
|
||||
def add_latex_package(self, packagename: str, options: str = None,
|
||||
after_hyperref: bool = False) -> None:
|
||||
r"""Register a package to include in the LaTeX source code.
|
||||
@ -1102,7 +1076,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_latex_package(packagename, options, after_hyperref)
|
||||
|
||||
def add_lexer(self, alias: str, lexer: Union[Lexer, "Type[Lexer]"]) -> None:
|
||||
def add_lexer(self, alias: str, lexer: Type[Lexer]) -> None:
|
||||
"""Register a new lexer for source code.
|
||||
|
||||
Use *lexer* to highlight code blocks with the given language *alias*.
|
||||
@ -1113,13 +1087,7 @@ class Sphinx:
|
||||
still supported until Sphinx-3.x.
|
||||
"""
|
||||
logger.debug('[app] adding lexer: %r', (alias, lexer))
|
||||
if isinstance(lexer, Lexer):
|
||||
warnings.warn('app.add_lexer() API changed; '
|
||||
'Please give lexer class instead of instance',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
lexers[alias] = lexer
|
||||
else:
|
||||
lexer_classes[alias] = lexer
|
||||
lexer_classes[alias] = lexer
|
||||
|
||||
def add_autodocumenter(self, cls: Any, override: bool = False) -> None:
|
||||
"""Register a new documenter class for the autodoc extension.
|
||||
@ -1133,7 +1101,7 @@ class Sphinx:
|
||||
If *override* is True, the given *cls* is forcedly installed even if
|
||||
a documenter having the same name is already installed.
|
||||
|
||||
.. todo:: Add real docs for Documenter and subclassing
|
||||
See :ref:`autodoc_ext_tutorial`.
|
||||
|
||||
.. versionadded:: 0.6
|
||||
.. versionchanged:: 2.2
|
||||
@ -1144,7 +1112,7 @@ class Sphinx:
|
||||
self.registry.add_documenter(cls.objtype, cls)
|
||||
self.add_directive('auto' + cls.objtype, AutodocDirective, override=override)
|
||||
|
||||
def add_autodoc_attrgetter(self, typ: "Type", getter: Callable[[Any, str, Any], Any]
|
||||
def add_autodoc_attrgetter(self, typ: Type, getter: Callable[[Any, str, Any], Any]
|
||||
) -> None:
|
||||
"""Register a new ``getattr``-like function for the autodoc extension.
|
||||
|
||||
@ -1188,7 +1156,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_source_suffix(suffix, filetype, override=override)
|
||||
|
||||
def add_source_parser(self, parser: "Type[Parser]", override: bool = False) -> None:
|
||||
def add_source_parser(self, parser: Type[Parser], override: bool = False) -> None:
|
||||
"""Register a parser class.
|
||||
|
||||
If *override* is True, the given *parser* is forcedly installed even if
|
||||
@ -1203,7 +1171,7 @@ class Sphinx:
|
||||
"""
|
||||
self.registry.add_source_parser(parser, override=override)
|
||||
|
||||
def add_env_collector(self, collector: "Type[EnvironmentCollector]") -> None:
|
||||
def add_env_collector(self, collector: Type[EnvironmentCollector]) -> None:
|
||||
"""Register an environment collector class.
|
||||
|
||||
Refer to :ref:`collector-api`.
|
||||
|
@ -11,7 +11,7 @@
|
||||
import pickle
|
||||
import time
|
||||
from os import path
|
||||
from typing import Any, Dict, Iterable, List, Sequence, Set, Tuple, Union
|
||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Sequence, Set, Tuple, Type, Union
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
@ -40,10 +40,7 @@ try:
|
||||
except ImportError:
|
||||
multiprocessing = None
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -66,7 +63,7 @@ class Builder:
|
||||
|
||||
#: default translator class for the builder. This can be overridden by
|
||||
#: :py:meth:`app.set_translator()`.
|
||||
default_translator_class = None # type: Type[nodes.NodeVisitor]
|
||||
default_translator_class: Type[nodes.NodeVisitor] = None
|
||||
# doctree versioning method
|
||||
versioning_method = 'none'
|
||||
versioning_compare = False
|
||||
@ -77,7 +74,7 @@ class Builder:
|
||||
|
||||
#: The list of MIME types of image formats supported by the builder.
|
||||
#: Image files are searched in the order in which they appear here.
|
||||
supported_image_types = [] # type: List[str]
|
||||
supported_image_types: List[str] = []
|
||||
#: The builder supports remote images or not.
|
||||
supported_remote_images = False
|
||||
#: The builder supports data URIs or not.
|
||||
@ -90,18 +87,18 @@ class Builder:
|
||||
self.doctreedir = app.doctreedir
|
||||
ensuredir(self.doctreedir)
|
||||
|
||||
self.app = app # type: Sphinx
|
||||
self.env = None # type: BuildEnvironment
|
||||
self.events = app.events # type: EventManager
|
||||
self.config = app.config # type: Config
|
||||
self.tags = app.tags # type: Tags
|
||||
self.app: Sphinx = app
|
||||
self.env: BuildEnvironment = None
|
||||
self.events: EventManager = app.events
|
||||
self.config: Config = app.config
|
||||
self.tags: Tags = app.tags
|
||||
self.tags.add(self.format)
|
||||
self.tags.add(self.name)
|
||||
self.tags.add("format_%s" % self.format)
|
||||
self.tags.add("builder_%s" % self.name)
|
||||
|
||||
# images that need to be copied over (source -> dest)
|
||||
self.images = {} # type: Dict[str, str]
|
||||
self.images: Dict[str, str] = {}
|
||||
# basename of images directory
|
||||
self.imagedir = ""
|
||||
# relative path to image directory from current docname (used at writing docs)
|
||||
@ -109,7 +106,7 @@ class Builder:
|
||||
|
||||
# these get set later
|
||||
self.parallel_ok = False
|
||||
self.finish_tasks = None # type: Any
|
||||
self.finish_tasks: Any = None
|
||||
|
||||
def set_environment(self, env: BuildEnvironment) -> None:
|
||||
"""Store BuildEnvironment object."""
|
||||
@ -117,7 +114,7 @@ class Builder:
|
||||
self.env.set_versioning_method(self.versioning_method,
|
||||
self.versioning_compare)
|
||||
|
||||
def get_translator_class(self, *args: Any) -> "Type[nodes.NodeVisitor]":
|
||||
def get_translator_class(self, *args: Any) -> Type[nodes.NodeVisitor]:
|
||||
"""Return a class of translator."""
|
||||
return self.app.registry.get_translator_class(self)
|
||||
|
||||
@ -264,8 +261,7 @@ class Builder:
|
||||
# relative to the source directory and without source_suffix.
|
||||
dirlen = len(self.srcdir) + 1
|
||||
to_write = []
|
||||
suffixes = None # type: Tuple[str]
|
||||
suffixes = tuple(self.config.source_suffix) # type: ignore
|
||||
suffixes: Tuple[str] = tuple(self.config.source_suffix) # type: ignore
|
||||
for filename in filenames:
|
||||
filename = path.normpath(path.abspath(filename))
|
||||
if not filename.startswith(self.srcdir):
|
||||
@ -416,9 +412,9 @@ class Builder:
|
||||
else:
|
||||
self._read_serial(docnames)
|
||||
|
||||
if self.config.master_doc not in self.env.all_docs:
|
||||
raise SphinxError('master file %s not found' %
|
||||
self.env.doc2path(self.config.master_doc))
|
||||
if self.config.root_doc not in self.env.all_docs:
|
||||
raise SphinxError('root file %s not found' %
|
||||
self.env.doc2path(self.config.root_doc))
|
||||
|
||||
for retval in self.events.emit('env-updated', self.env):
|
||||
if retval is not None:
|
||||
@ -520,7 +516,7 @@ class Builder:
|
||||
for tocdocname in self.env.files_to_rebuild.get(docname, set()):
|
||||
if tocdocname in self.env.found_docs:
|
||||
docnames.add(tocdocname)
|
||||
docnames.add(self.config.master_doc)
|
||||
docnames.add(self.config.root_doc)
|
||||
|
||||
with progress_message(__('preparing documents')):
|
||||
self.prepare_writing(docnames)
|
||||
|
@ -11,10 +11,8 @@
|
||||
import html
|
||||
import os
|
||||
import re
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
from os import path
|
||||
from typing import Any, Dict, List, Set, Tuple
|
||||
from typing import Any, Dict, List, NamedTuple, Set, Tuple
|
||||
from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
|
||||
|
||||
from docutils import nodes
|
||||
@ -23,7 +21,6 @@ from docutils.utils import smartquotes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.builders.html import BuildInfo, StandaloneHTMLBuilder
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging, status_iterator
|
||||
from sphinx.util.fileutil import copy_asset_file
|
||||
@ -84,10 +81,30 @@ VECTOR_GRAPHICS_EXTENSIONS = ('.svg',)
|
||||
REFURI_RE = re.compile("([^#:]*#)(.*)")
|
||||
|
||||
|
||||
ManifestItem = namedtuple('ManifestItem', ['href', 'id', 'media_type'])
|
||||
Spine = namedtuple('Spine', ['idref', 'linear'])
|
||||
Guide = namedtuple('Guide', ['type', 'title', 'uri'])
|
||||
NavPoint = namedtuple('NavPoint', ['navpoint', 'playorder', 'text', 'refuri', 'children'])
|
||||
class ManifestItem(NamedTuple):
|
||||
href: str
|
||||
id: str
|
||||
media_type: str
|
||||
|
||||
|
||||
class Spine(NamedTuple):
|
||||
idref: str
|
||||
linear: bool
|
||||
|
||||
|
||||
class Guide(NamedTuple):
|
||||
type: str
|
||||
title: str
|
||||
uri: str
|
||||
|
||||
|
||||
class NavPoint(NamedTuple):
|
||||
navpoint: str
|
||||
playorder: int
|
||||
text: str
|
||||
refuri: str
|
||||
children: List[Any] # mypy does not support recursive types
|
||||
# https://github.com/python/mypy/issues/7069
|
||||
|
||||
|
||||
def sphinx_smarty_pants(t: str, language: str = 'en') -> str:
|
||||
@ -148,9 +165,9 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
self.link_suffix = '.xhtml'
|
||||
self.playorder = 0
|
||||
self.tocid = 0
|
||||
self.id_cache = {} # type: Dict[str, str]
|
||||
self.id_cache: Dict[str, str] = {}
|
||||
self.use_index = self.get_builder_config('use_index', 'epub')
|
||||
self.refnodes = [] # type: List[Dict[str, Any]]
|
||||
self.refnodes: List[Dict[str, Any]] = []
|
||||
|
||||
def create_build_info(self) -> BuildInfo:
|
||||
return BuildInfo(self.config, self.tags, ['html', 'epub'])
|
||||
@ -168,18 +185,6 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
self.id_cache[name] = id
|
||||
return id
|
||||
|
||||
def esc(self, name: str) -> str:
|
||||
"""Replace all characters not allowed in text an attribute values."""
|
||||
warnings.warn(
|
||||
'%s.esc() is deprecated. Use html.escape() instead.' % self.__class__.__name__,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
name = name.replace('&', '&')
|
||||
name = name.replace('<', '<')
|
||||
name = name.replace('>', '>')
|
||||
name = name.replace('"', '"')
|
||||
name = name.replace('\'', ''')
|
||||
return name
|
||||
|
||||
def get_refnodes(self, doctree: Node, result: List[Dict[str, Any]]) -> List[Dict[str, Any]]: # NOQA
|
||||
"""Collect section titles, their depth in the toc and the refuri."""
|
||||
# XXX: is there a better way than checking the attribute
|
||||
@ -204,7 +209,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
return result
|
||||
|
||||
def check_refnodes(self, nodes: List[Dict[str, Any]]) -> None:
|
||||
appeared = set() # type: Set[str]
|
||||
appeared: Set[str] = set()
|
||||
for node in nodes:
|
||||
if node['refuri'] in appeared:
|
||||
logger.warning(
|
||||
@ -217,14 +222,14 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
appeared.add(node['refuri'])
|
||||
|
||||
def get_toc(self) -> None:
|
||||
"""Get the total table of contents, containing the master_doc
|
||||
"""Get the total table of contents, containing the root_doc
|
||||
and pre and post files not managed by sphinx.
|
||||
"""
|
||||
doctree = self.env.get_and_resolve_doctree(self.config.master_doc,
|
||||
doctree = self.env.get_and_resolve_doctree(self.config.root_doc,
|
||||
self, prune_toctrees=False,
|
||||
includehidden=True)
|
||||
self.refnodes = self.get_refnodes(doctree, [])
|
||||
master_dir = path.dirname(self.config.master_doc)
|
||||
master_dir = path.dirname(self.config.root_doc)
|
||||
if master_dir:
|
||||
master_dir += '/' # XXX or os.sep?
|
||||
for item in self.refnodes:
|
||||
@ -232,13 +237,13 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
self.toc_add_files(self.refnodes)
|
||||
|
||||
def toc_add_files(self, refnodes: List[Dict[str, Any]]) -> None:
|
||||
"""Add the master_doc, pre and post files to a list of refnodes.
|
||||
"""Add the root_doc, pre and post files to a list of refnodes.
|
||||
"""
|
||||
refnodes.insert(0, {
|
||||
'level': 1,
|
||||
'refuri': html.escape(self.config.master_doc + self.out_suffix),
|
||||
'refuri': html.escape(self.config.root_doc + self.out_suffix),
|
||||
'text': ssp(html.escape(
|
||||
self.env.titles[self.config.master_doc].astext()))
|
||||
self.env.titles[self.config.root_doc].astext()))
|
||||
})
|
||||
for file, text in reversed(self.config.epub_pre_files):
|
||||
refnodes.insert(0, {
|
||||
@ -265,7 +270,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
"""
|
||||
def update_node_id(node: Element) -> None:
|
||||
"""Update IDs of given *node*."""
|
||||
new_ids = []
|
||||
new_ids: List[str] = []
|
||||
for node_id in node['ids']:
|
||||
new_id = self.fix_fragment('', node_id)
|
||||
if new_id not in new_ids:
|
||||
@ -283,7 +288,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
for target in tree.traverse(nodes.target):
|
||||
update_node_id(target)
|
||||
|
||||
next_node = target.next_node(ascend=True) # type: Node
|
||||
next_node: Node = target.next_node(ascend=True)
|
||||
if isinstance(next_node, nodes.Element):
|
||||
update_node_id(next_node)
|
||||
|
||||
@ -461,36 +466,23 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
addctx['doctype'] = self.doctype
|
||||
super().handle_page(pagename, addctx, templatename, outfilename, event_arg)
|
||||
|
||||
def build_mimetype(self, outdir: str = None, outname: str = 'mimetype') -> None:
|
||||
def build_mimetype(self) -> None:
|
||||
"""Write the metainfo file mimetype."""
|
||||
if outdir:
|
||||
warnings.warn('The arguments of EpubBuilder.build_mimetype() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
else:
|
||||
outdir = self.outdir
|
||||
logger.info(__('writing mimetype file...'))
|
||||
copy_asset_file(path.join(self.template_dir, 'mimetype'), self.outdir)
|
||||
|
||||
logger.info(__('writing %s file...'), outname)
|
||||
copy_asset_file(path.join(self.template_dir, 'mimetype'),
|
||||
path.join(outdir, outname))
|
||||
|
||||
def build_container(self, outdir: str = None, outname: str = 'META-INF/container.xml') -> None: # NOQA
|
||||
def build_container(self, outname: str = 'META-INF/container.xml') -> None: # NOQA
|
||||
"""Write the metainfo file META-INF/container.xml."""
|
||||
if outdir:
|
||||
warnings.warn('The arguments of EpubBuilder.build_container() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
else:
|
||||
outdir = self.outdir
|
||||
|
||||
logger.info(__('writing %s file...'), outname)
|
||||
filename = path.join(outdir, outname)
|
||||
ensuredir(path.dirname(filename))
|
||||
copy_asset_file(path.join(self.template_dir, 'container.xml'), filename)
|
||||
logger.info(__('writing META-INF/container.xml file...'))
|
||||
outdir = path.join(self.outdir, 'META-INF')
|
||||
ensuredir(outdir)
|
||||
copy_asset_file(path.join(self.template_dir, 'container.xml'), outdir)
|
||||
|
||||
def content_metadata(self) -> Dict[str, Any]:
|
||||
"""Create a dictionary with all metadata for the content.opf
|
||||
file properly escaped.
|
||||
"""
|
||||
metadata = {} # type: Dict[str, Any]
|
||||
metadata: Dict[str, Any] = {}
|
||||
metadata['title'] = html.escape(self.config.epub_title)
|
||||
metadata['author'] = html.escape(self.config.epub_author)
|
||||
metadata['uid'] = html.escape(self.config.epub_uid)
|
||||
@ -505,24 +497,18 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
metadata['guides'] = []
|
||||
return metadata
|
||||
|
||||
def build_content(self, outdir: str = None, outname: str = 'content.opf') -> None:
|
||||
def build_content(self) -> None:
|
||||
"""Write the metainfo file content.opf It contains bibliographic data,
|
||||
a file list and the spine (the reading order).
|
||||
"""
|
||||
if outdir:
|
||||
warnings.warn('The arguments of EpubBuilder.build_content() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
else:
|
||||
outdir = self.outdir
|
||||
|
||||
logger.info(__('writing %s file...'), outname)
|
||||
logger.info(__('writing content.opf file...'))
|
||||
metadata = self.content_metadata()
|
||||
|
||||
# files
|
||||
if not outdir.endswith(os.sep):
|
||||
outdir += os.sep
|
||||
olen = len(outdir)
|
||||
self.files = [] # type: List[str]
|
||||
if not self.outdir.endswith(os.sep):
|
||||
self.outdir += os.sep
|
||||
olen = len(self.outdir)
|
||||
self.files: List[str] = []
|
||||
self.ignored_files = ['.buildinfo', 'mimetype', 'content.opf',
|
||||
'toc.ncx', 'META-INF/container.xml',
|
||||
'Thumbs.db', 'ehthumbs.db', '.DS_Store',
|
||||
@ -530,7 +516,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
self.config.epub_exclude_files
|
||||
if not self.use_index:
|
||||
self.ignored_files.append('genindex' + self.out_suffix)
|
||||
for root, dirs, files in os.walk(outdir):
|
||||
for root, dirs, files in os.walk(self.outdir):
|
||||
dirs.sort()
|
||||
for fn in sorted(files):
|
||||
filename = path.join(root, fn)[olen:]
|
||||
@ -620,9 +606,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
html.escape(self.refnodes[0]['refuri'])))
|
||||
|
||||
# write the project file
|
||||
copy_asset_file(path.join(self.template_dir, 'content.opf_t'),
|
||||
path.join(outdir, outname),
|
||||
metadata)
|
||||
copy_asset_file(path.join(self.template_dir, 'content.opf_t'), self.outdir, metadata)
|
||||
|
||||
def new_navpoint(self, node: Dict[str, Any], level: int, incr: bool = True) -> NavPoint:
|
||||
"""Create a new entry in the toc from the node at given level."""
|
||||
@ -639,8 +623,8 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
Subelements of a node are nested inside the navpoint. For nested nodes
|
||||
the parent node is reinserted in the subnav.
|
||||
"""
|
||||
navstack = [] # type: List[NavPoint]
|
||||
navstack.append(NavPoint('dummy', '', '', '', []))
|
||||
navstack: List[NavPoint] = []
|
||||
navstack.append(NavPoint('dummy', 0, '', '', []))
|
||||
level = 0
|
||||
lastnode = None
|
||||
for node in nodes:
|
||||
@ -681,25 +665,19 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
"""Create a dictionary with all metadata for the toc.ncx file
|
||||
properly escaped.
|
||||
"""
|
||||
metadata = {} # type: Dict[str, Any]
|
||||
metadata: Dict[str, Any] = {}
|
||||
metadata['uid'] = self.config.epub_uid
|
||||
metadata['title'] = html.escape(self.config.epub_title)
|
||||
metadata['level'] = level
|
||||
metadata['navpoints'] = navpoints
|
||||
return metadata
|
||||
|
||||
def build_toc(self, outdir: str = None, outname: str = 'toc.ncx') -> None:
|
||||
def build_toc(self) -> None:
|
||||
"""Write the metainfo file toc.ncx."""
|
||||
if outdir:
|
||||
warnings.warn('The arguments of EpubBuilder.build_toc() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
else:
|
||||
outdir = self.outdir
|
||||
|
||||
logger.info(__('writing %s file...'), outname)
|
||||
logger.info(__('writing toc.ncx file...'))
|
||||
|
||||
if self.config.epub_tocscope == 'default':
|
||||
doctree = self.env.get_and_resolve_doctree(self.config.master_doc,
|
||||
doctree = self.env.get_and_resolve_doctree(self.config.root_doc,
|
||||
self, prune_toctrees=False,
|
||||
includehidden=False)
|
||||
refnodes = self.get_refnodes(doctree, [])
|
||||
@ -711,28 +689,21 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
navpoints = self.build_navpoints(refnodes)
|
||||
level = max(item['level'] for item in self.refnodes)
|
||||
level = min(level, self.config.epub_tocdepth)
|
||||
copy_asset_file(path.join(self.template_dir, 'toc.ncx_t'),
|
||||
path.join(outdir, outname),
|
||||
copy_asset_file(path.join(self.template_dir, 'toc.ncx_t'), self.outdir,
|
||||
self.toc_metadata(level, navpoints))
|
||||
|
||||
def build_epub(self, outdir: str = None, outname: str = None) -> None:
|
||||
def build_epub(self) -> None:
|
||||
"""Write the epub file.
|
||||
|
||||
It is a zip file with the mimetype file stored uncompressed as the first
|
||||
entry.
|
||||
"""
|
||||
if outdir:
|
||||
warnings.warn('The arguments of EpubBuilder.build_epub() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
else:
|
||||
outdir = self.outdir
|
||||
outname = self.config.epub_basename + '.epub'
|
||||
|
||||
outname = self.config.epub_basename + '.epub'
|
||||
logger.info(__('writing %s file...'), outname)
|
||||
epub_filename = path.join(outdir, outname)
|
||||
epub_filename = path.join(self.outdir, outname)
|
||||
with ZipFile(epub_filename, 'w', ZIP_DEFLATED) as epub:
|
||||
epub.write(path.join(outdir, 'mimetype'), 'mimetype', ZIP_STORED)
|
||||
epub.write(path.join(self.outdir, 'mimetype'), 'mimetype', ZIP_STORED)
|
||||
for filename in ['META-INF/container.xml', 'content.opf', 'toc.ncx']:
|
||||
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED)
|
||||
epub.write(path.join(self.outdir, filename), filename, ZIP_DEFLATED)
|
||||
for filename in self.files:
|
||||
epub.write(path.join(outdir, filename), filename, ZIP_DEFLATED)
|
||||
epub.write(path.join(self.outdir, filename), filename, ZIP_DEFLATED)
|
||||
|
@ -1,45 +0,0 @@
|
||||
"""
|
||||
sphinx.builders.applehelp
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Build Apple help books.
|
||||
|
||||
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinxcontrib.applehelp import (AppleHelpBuilder, AppleHelpCodeSigningFailed,
|
||||
AppleHelpIndexerFailed)
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
deprecated_alias('sphinx.builders.applehelp',
|
||||
{
|
||||
'AppleHelpCodeSigningFailed': AppleHelpCodeSigningFailed,
|
||||
'AppleHelpIndexerFailed': AppleHelpIndexerFailed,
|
||||
'AppleHelpBuilder': AppleHelpBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'AppleHelpCodeSigningFailed':
|
||||
'sphinxcontrib.applehelp.AppleHelpCodeSigningFailed',
|
||||
'AppleHelpIndexerFailed':
|
||||
'sphinxcontrib.applehelp.AppleHelpIndexerFailed',
|
||||
'AppleHelpBuilder': 'sphinxcontrib.applehelp.AppleHelpBuilder',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
warnings.warn('sphinx.builders.applehelp has been moved to sphinxcontrib-applehelp.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
app.setup_extension('sphinxcontrib.applehelp')
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
@ -51,9 +51,9 @@ class ChangesBuilder(Builder):
|
||||
def write(self, *ignored: Any) -> None:
|
||||
version = self.config.version
|
||||
domain = cast(ChangeSetDomain, self.env.get_domain('changeset'))
|
||||
libchanges = {} # type: Dict[str, List[Tuple[str, str, int]]]
|
||||
apichanges = [] # type: List[Tuple[str, str, int]]
|
||||
otherchanges = {} # type: Dict[Tuple[str, str], List[Tuple[str, str, int]]]
|
||||
libchanges: Dict[str, List[Tuple[str, str, int]]] = {}
|
||||
apichanges: List[Tuple[str, str, int]] = []
|
||||
otherchanges: Dict[Tuple[str, str], List[Tuple[str, str, int]]] = {}
|
||||
|
||||
changesets = domain.get_changesets_for(version)
|
||||
if not changesets:
|
||||
|
@ -1,40 +0,0 @@
|
||||
"""
|
||||
sphinx.builders.devhelp
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Build HTML documentation and Devhelp_ support files.
|
||||
|
||||
.. _Devhelp: https://wiki.gnome.org/Apps/Devhelp
|
||||
|
||||
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinxcontrib.devhelp import DevhelpBuilder
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
deprecated_alias('sphinx.builders.devhelp',
|
||||
{
|
||||
'DevhelpBuilder': DevhelpBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'DevhelpBuilder': 'sphinxcontrib.devhelp.DevhelpBuilder'
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
warnings.warn('sphinx.builders.devhelp has been moved to sphinxcontrib-devhelp.',
|
||||
RemovedInSphinx40Warning)
|
||||
app.setup_extension('sphinxcontrib.devhelp')
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
@ -10,16 +10,13 @@
|
||||
"""
|
||||
|
||||
import html
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
from os import path
|
||||
from typing import Any, Dict, List, Set, Tuple
|
||||
from typing import Any, Dict, List, NamedTuple, Set, Tuple
|
||||
|
||||
from sphinx import package_dir
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import _epub_base
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging, xmlname_checker
|
||||
from sphinx.util.fileutil import copy_asset_file
|
||||
@ -29,7 +26,12 @@ from sphinx.util.osutil import make_filename
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
NavPoint = namedtuple('NavPoint', ['text', 'refuri', 'children'])
|
||||
class NavPoint(NamedTuple):
|
||||
text: str
|
||||
refuri: str
|
||||
children: List[Any] # mypy does not support recursive types
|
||||
# https://github.com/python/mypy/issues/7069
|
||||
|
||||
|
||||
# writing modes
|
||||
PAGE_PROGRESSION_DIRECTIONS = {
|
||||
@ -81,10 +83,6 @@ class Epub3Builder(_epub_base.EpubBuilder):
|
||||
self.build_toc()
|
||||
self.build_epub()
|
||||
|
||||
def validate_config_value(self) -> None:
|
||||
warnings.warn('Epub3Builder.validate_config_value() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
def content_metadata(self) -> Dict:
|
||||
"""Create a dictionary with all metadata for the content.opf
|
||||
file properly escaped.
|
||||
@ -120,7 +118,7 @@ class Epub3Builder(_epub_base.EpubBuilder):
|
||||
The difference from build_navpoints method is templates which are used
|
||||
when generating navigation documents.
|
||||
"""
|
||||
navstack = [] # type: List[NavPoint]
|
||||
navstack: List[NavPoint] = []
|
||||
navstack.append(NavPoint('', '', []))
|
||||
level = 0
|
||||
for node in navnodes:
|
||||
@ -156,25 +154,19 @@ class Epub3Builder(_epub_base.EpubBuilder):
|
||||
"""Create a dictionary with all metadata for the nav.xhtml file
|
||||
properly escaped.
|
||||
"""
|
||||
metadata = {} # type: Dict
|
||||
metadata: Dict = {}
|
||||
metadata['lang'] = html.escape(self.config.epub_language)
|
||||
metadata['toc_locale'] = html.escape(self.guide_titles['toc'])
|
||||
metadata['navlist'] = navlist
|
||||
return metadata
|
||||
|
||||
def build_navigation_doc(self, outdir: str = None, outname: str = 'nav.xhtml') -> None:
|
||||
def build_navigation_doc(self) -> None:
|
||||
"""Write the metainfo file nav.xhtml."""
|
||||
if outdir:
|
||||
warnings.warn('The arguments of Epub3Builder.build_navigation_doc() '
|
||||
'is deprecated.', RemovedInSphinx40Warning, stacklevel=2)
|
||||
else:
|
||||
outdir = self.outdir
|
||||
|
||||
logger.info(__('writing %s file...'), outname)
|
||||
logger.info(__('writing nav.xhtml file...'))
|
||||
|
||||
if self.config.epub_tocscope == 'default':
|
||||
doctree = self.env.get_and_resolve_doctree(
|
||||
self.config.master_doc, self,
|
||||
self.config.root_doc, self,
|
||||
prune_toctrees=False, includehidden=False)
|
||||
refnodes = self.get_refnodes(doctree, [])
|
||||
self.toc_add_files(refnodes)
|
||||
@ -182,13 +174,12 @@ class Epub3Builder(_epub_base.EpubBuilder):
|
||||
# 'includehidden'
|
||||
refnodes = self.refnodes
|
||||
navlist = self.build_navlist(refnodes)
|
||||
copy_asset_file(path.join(self.template_dir, 'nav.xhtml_t'),
|
||||
path.join(outdir, outname),
|
||||
copy_asset_file(path.join(self.template_dir, 'nav.xhtml_t'), self.outdir,
|
||||
self.navigation_doc_metadata(navlist))
|
||||
|
||||
# Add nav.xhtml to epub file
|
||||
if outname not in self.files:
|
||||
self.files.append(outname)
|
||||
if 'nav.xhtml' not in self.files:
|
||||
self.files.append('nav.xhtml')
|
||||
|
||||
|
||||
def validate_config_values(app: Sphinx) -> None:
|
||||
@ -232,7 +223,7 @@ def validate_config_values(app: Sphinx) -> None:
|
||||
|
||||
def convert_epub_css_files(app: Sphinx, config: Config) -> None:
|
||||
"""This converts string styled epub_css_files to tuple styled one."""
|
||||
epub_css_files = [] # type: List[Tuple[str, Dict]]
|
||||
epub_css_files: List[Tuple[str, Dict]] = []
|
||||
for entry in config.epub_css_files:
|
||||
if isinstance(entry, str):
|
||||
epub_css_files.append((entry, {}))
|
||||
|
@ -13,7 +13,7 @@ from collections import OrderedDict, defaultdict
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from os import getenv, path, walk
|
||||
from time import time
|
||||
from typing import Any, Dict, Generator, Iterable, List, Set, Tuple, Union
|
||||
from typing import Any, DefaultDict, Dict, Generator, Iterable, List, Set, Tuple, Union
|
||||
from uuid import uuid4
|
||||
|
||||
from docutils import nodes
|
||||
@ -33,33 +33,8 @@ from sphinx.util.osutil import canon_path, ensuredir, relpath
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.template import SphinxRenderer
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import DefaultDict # for python3.5.1
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
POHEADER = r"""
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) %(copyright)s
|
||||
# This file is distributed under the same license as the %(project)s package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: %(project)s %(version)s\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: %(ctime)s\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
"""[1:] # RemovedInSphinx40Warning
|
||||
|
||||
|
||||
class Message:
|
||||
"""An entry of translatable message."""
|
||||
@ -73,10 +48,10 @@ class Catalog:
|
||||
"""Catalog of translatable messages."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.messages = [] # type: List[str]
|
||||
# retain insertion order, a la OrderedDict
|
||||
self.metadata = OrderedDict() # type: Dict[str, List[Tuple[str, int, str]]]
|
||||
# msgid -> file, line, uid
|
||||
self.messages: List[str] = [] # retain insertion order, a la OrderedDict
|
||||
|
||||
# msgid -> file, line, uid
|
||||
self.metadata: Dict[str, List[Tuple[str, int, str]]] = OrderedDict()
|
||||
|
||||
def add(self, msg: str, origin: Union[Element, "MsgOrigin"]) -> None:
|
||||
if not hasattr(origin, 'uid'):
|
||||
@ -146,8 +121,7 @@ class I18nBuilder(Builder):
|
||||
"""
|
||||
name = 'i18n'
|
||||
versioning_method = 'text'
|
||||
versioning_compare = None # type: bool
|
||||
# be set by `gettext_uuid`
|
||||
versioning_compare: bool = None # be set by `gettext_uuid`
|
||||
use_message_catalog = False
|
||||
|
||||
def init(self) -> None:
|
||||
@ -155,7 +129,7 @@ class I18nBuilder(Builder):
|
||||
self.env.set_versioning_method(self.versioning_method,
|
||||
self.env.config.gettext_uuid)
|
||||
self.tags = I18nTags()
|
||||
self.catalogs = defaultdict(Catalog) # type: DefaultDict[str, Catalog]
|
||||
self.catalogs: DefaultDict[str, Catalog] = defaultdict(Catalog)
|
||||
|
||||
def get_target_uri(self, docname: str, typ: str = None) -> str:
|
||||
return ''
|
||||
|
@ -13,9 +13,9 @@ import os
|
||||
import posixpath
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
from os import path
|
||||
from typing import IO, Any, Dict, Iterable, Iterator, List, Set, Tuple
|
||||
from typing import IO, Any, Dict, Iterable, Iterator, List, Set, Tuple, Type
|
||||
from urllib.parse import quote
|
||||
|
||||
from docutils import nodes
|
||||
@ -29,7 +29,6 @@ from sphinx import __display_version__, package_dir
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.domains import Domain, Index, IndexEntry
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.environment.adapters.indexentries import IndexEntries
|
||||
@ -39,7 +38,7 @@ from sphinx.highlighting import PygmentsBridge
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.search import js_index
|
||||
from sphinx.theming import HTMLThemeFactory
|
||||
from sphinx.util import logging, md5, progress_message, status_iterator
|
||||
from sphinx.util import isurl, logging, md5, progress_message, status_iterator
|
||||
from sphinx.util.docutils import is_html5_writer_available, new_document
|
||||
from sphinx.util.fileutil import copy_asset
|
||||
from sphinx.util.i18n import format_date
|
||||
@ -49,11 +48,6 @@ from sphinx.util.osutil import copyfile, ensuredir, os_path, relative_uri
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.writers.html import HTMLTranslator, HTMLWriter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
# HTML5 Writer is available or not
|
||||
if is_html5_writer_available():
|
||||
from sphinx.writers.html5 import HTML5Translator
|
||||
@ -88,9 +82,9 @@ class Stylesheet(str):
|
||||
its filename (str).
|
||||
"""
|
||||
|
||||
attributes = None # type: Dict[str, str]
|
||||
filename = None # type: str
|
||||
priority = None # type: int
|
||||
attributes: Dict[str, str] = None
|
||||
filename: str = None
|
||||
priority: int = None
|
||||
|
||||
def __new__(cls, filename: str, *args: str, priority: int = 500, **attributes: Any
|
||||
) -> "Stylesheet":
|
||||
@ -114,9 +108,9 @@ class JavaScript(str):
|
||||
its filename (str).
|
||||
"""
|
||||
|
||||
attributes = None # type: Dict[str, str]
|
||||
filename = None # type: str
|
||||
priority = None # type: int
|
||||
attributes: Dict[str, str] = None
|
||||
filename: str = None
|
||||
priority: int = None
|
||||
|
||||
def __new__(cls, filename: str, priority: int = 500, **attributes: str) -> "JavaScript":
|
||||
self = str.__new__(cls, filename)
|
||||
@ -185,7 +179,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
allow_parallel = True
|
||||
out_suffix = '.html'
|
||||
link_suffix = '.html' # defaults to matching out_suffix
|
||||
indexer_format = js_index # type: Any
|
||||
indexer_format: Any = js_index
|
||||
indexer_dumps_unicode = True
|
||||
# create links to original images from images [True/False]
|
||||
html_scaled_image_link = True
|
||||
@ -201,26 +195,26 @@ class StandaloneHTMLBuilder(Builder):
|
||||
use_index = False
|
||||
download_support = True # enable download role
|
||||
|
||||
imgpath = None # type: str
|
||||
domain_indices = [] # type: List[Tuple[str, Type[Index], List[Tuple[str, List[IndexEntry]]], bool]] # NOQA
|
||||
imgpath: str = None
|
||||
domain_indices: List[Tuple[str, Type[Index], List[Tuple[str, List[IndexEntry]]], bool]] = [] # NOQA
|
||||
|
||||
def __init__(self, app: Sphinx) -> None:
|
||||
super().__init__(app)
|
||||
|
||||
# CSS files
|
||||
self.css_files = [] # type: List[Dict[str, str]]
|
||||
self.css_files: List[Dict[str, str]] = []
|
||||
|
||||
# JS files
|
||||
self.script_files = [] # type: List[JavaScript]
|
||||
self.script_files: List[JavaScript] = []
|
||||
|
||||
def init(self) -> None:
|
||||
self.build_info = self.create_build_info()
|
||||
# basename of images directory
|
||||
self.imagedir = '_images'
|
||||
# section numbers for headings in the currently visited document
|
||||
self.secnumbers = {} # type: Dict[str, Tuple[int, ...]]
|
||||
self.secnumbers: Dict[str, Tuple[int, ...]] = {}
|
||||
# currently written docname
|
||||
self.current_docname = None # type: str
|
||||
self.current_docname: str = None
|
||||
|
||||
self.init_templates()
|
||||
self.init_highlighter()
|
||||
@ -256,6 +250,14 @@ class StandaloneHTMLBuilder(Builder):
|
||||
return jsfile
|
||||
return None
|
||||
|
||||
def _get_style_filename(self) -> str:
|
||||
if self.config.html_style is not None:
|
||||
return self.config.html_style
|
||||
elif self.theme:
|
||||
return self.theme.get_config('theme', 'stylesheet')
|
||||
else:
|
||||
return 'default.css'
|
||||
|
||||
def get_theme_config(self) -> Tuple[str, Dict]:
|
||||
return self.config.html_theme, self.config.html_theme_options
|
||||
|
||||
@ -291,6 +293,9 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.dark_highlighter = None
|
||||
|
||||
def init_css_files(self) -> None:
|
||||
self.add_css_file('pygments.css', priority=200)
|
||||
self.add_css_file(self._get_style_filename(), priority=200)
|
||||
|
||||
for filename, attrs in self.app.registry.css_files:
|
||||
self.add_css_file(filename, **attrs)
|
||||
|
||||
@ -305,6 +310,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.css_files.append(Stylesheet(filename, **kwargs)) # type: ignore
|
||||
|
||||
def init_js_files(self) -> None:
|
||||
self.add_js_file('documentation_options.js', id="documentation_options",
|
||||
data_url_root='', priority=200)
|
||||
self.add_js_file('jquery.js', priority=200)
|
||||
self.add_js_file('underscore.js', priority=200)
|
||||
self.add_js_file('doctools.js', priority=200)
|
||||
@ -326,7 +333,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.script_files.append(JavaScript(filename, **kwargs))
|
||||
|
||||
@property
|
||||
def default_translator_class(self) -> "Type[nodes.NodeVisitor]": # type: ignore
|
||||
def default_translator_class(self) -> Type[nodes.NodeVisitor]: # type: ignore
|
||||
if not html5_ready or self.config.html4_writer:
|
||||
return HTMLTranslator
|
||||
else:
|
||||
@ -358,6 +365,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
buildinfo = BuildInfo.load(fp)
|
||||
|
||||
if self.build_info != buildinfo:
|
||||
logger.debug('[build target] did not match: build_info ')
|
||||
yield from self.env.found_docs
|
||||
return
|
||||
except ValueError as exc:
|
||||
@ -372,6 +380,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
template_mtime = 0
|
||||
for docname in self.env.found_docs:
|
||||
if docname not in self.env.all_docs:
|
||||
logger.debug('[build target] did not in env: %r', docname)
|
||||
yield docname
|
||||
continue
|
||||
targetname = self.get_outfilename(docname)
|
||||
@ -383,6 +392,14 @@ class StandaloneHTMLBuilder(Builder):
|
||||
srcmtime = max(path.getmtime(self.env.doc2path(docname)),
|
||||
template_mtime)
|
||||
if srcmtime > targetmtime:
|
||||
logger.debug(
|
||||
'[build target] targetname %r(%s), template(%s), docname %r(%s)',
|
||||
targetname,
|
||||
datetime.utcfromtimestamp(targetmtime),
|
||||
datetime.utcfromtimestamp(template_mtime),
|
||||
docname,
|
||||
datetime.utcfromtimestamp(path.getmtime(self.env.doc2path(docname))),
|
||||
)
|
||||
yield docname
|
||||
except OSError:
|
||||
# source doesn't exist anymore
|
||||
@ -419,10 +436,10 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.load_indexer(docnames)
|
||||
|
||||
self.docwriter = HTMLWriter(self)
|
||||
self.docsettings = OptionParser(
|
||||
self.docsettings: Any = OptionParser(
|
||||
defaults=self.env.settings,
|
||||
components=(self.docwriter,),
|
||||
read_config_files=True).get_default_values() # type: Any
|
||||
read_config_files=True).get_default_values()
|
||||
self.docsettings.compact_lists = bool(self.config.html_compact_lists)
|
||||
|
||||
# determine the additional indices to include
|
||||
@ -431,8 +448,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
indices_config = self.config.html_domain_indices
|
||||
if indices_config:
|
||||
for domain_name in sorted(self.env.domains):
|
||||
domain = None # type: Domain
|
||||
domain = self.env.domains[domain_name]
|
||||
domain: Domain = self.env.domains[domain_name]
|
||||
for indexcls in domain.indices:
|
||||
indexname = '%s-%s' % (domain.name, indexcls.name)
|
||||
if isinstance(indices_config, list):
|
||||
@ -457,7 +473,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
self.relations = self.env.collect_relations()
|
||||
|
||||
rellinks = [] # type: List[Tuple[str, str, str, str]]
|
||||
rellinks: List[Tuple[str, str, str, str]] = []
|
||||
if self.use_index:
|
||||
rellinks.append(('genindex', _('General Index'), 'I', _('index')))
|
||||
for indexname, indexcls, content, collapse in self.domain_indices:
|
||||
@ -470,13 +486,6 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self._script_files = list(self.script_files)
|
||||
self._css_files = list(self.css_files)
|
||||
|
||||
if self.config.html_style is not None:
|
||||
stylename = self.config.html_style
|
||||
elif self.theme:
|
||||
stylename = self.theme.get_config('theme', 'stylesheet')
|
||||
else:
|
||||
stylename = 'default.css'
|
||||
|
||||
self.globalcontext = {
|
||||
'embedded': self.embedded,
|
||||
'project': self.config.project,
|
||||
@ -484,7 +493,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
'version': self.config.version,
|
||||
'last_updated': self.last_updated,
|
||||
'copyright': self.config.copyright,
|
||||
'master_doc': self.config.master_doc,
|
||||
'master_doc': self.config.root_doc,
|
||||
'root_doc': self.config.root_doc,
|
||||
'use_opensearch': self.config.html_use_opensearch,
|
||||
'docstitle': self.config.html_title,
|
||||
'shorttitle': self.config.html_short_title,
|
||||
@ -499,7 +509,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
'language': self.config.language,
|
||||
'css_files': self.css_files,
|
||||
'sphinx_version': __display_version__,
|
||||
'style': stylename,
|
||||
'style': self._get_style_filename(),
|
||||
'rellinks': rellinks,
|
||||
'builder': self.name,
|
||||
'parents': [],
|
||||
@ -786,12 +796,12 @@ class StandaloneHTMLBuilder(Builder):
|
||||
excluded, context=context, renderer=self.templates, onerror=onerror)
|
||||
|
||||
def copy_html_logo(self) -> None:
|
||||
if self.config.html_logo:
|
||||
if self.config.html_logo and not isurl(self.config.html_logo):
|
||||
copy_asset(path.join(self.confdir, self.config.html_logo),
|
||||
path.join(self.outdir, '_static'))
|
||||
|
||||
def copy_html_favicon(self) -> None:
|
||||
if self.config.html_favicon:
|
||||
if self.config.html_favicon and not isurl(self.config.html_favicon):
|
||||
copy_asset(path.join(self.confdir, self.config.html_favicon),
|
||||
path.join(self.outdir, '_static'))
|
||||
|
||||
@ -889,21 +899,11 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# only index pages with title
|
||||
if self.indexer is not None and title:
|
||||
filename = self.env.doc2path(pagename, base=None)
|
||||
try:
|
||||
metadata = self.env.metadata.get(pagename, {})
|
||||
if 'nosearch' in metadata:
|
||||
self.indexer.feed(pagename, filename, '', new_document(''))
|
||||
else:
|
||||
self.indexer.feed(pagename, filename, title, doctree)
|
||||
except TypeError:
|
||||
# fallback for old search-adapters
|
||||
self.indexer.feed(pagename, title, doctree) # type: ignore
|
||||
indexer_name = self.indexer.__class__.__name__
|
||||
warnings.warn(
|
||||
'The %s.feed() method signature is deprecated. Update to '
|
||||
'%s.feed(docname, filename, title, doctree).' % (
|
||||
indexer_name, indexer_name),
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
metadata = self.env.metadata.get(pagename, {})
|
||||
if 'nosearch' in metadata:
|
||||
self.indexer.feed(pagename, filename, '', new_document(''))
|
||||
else:
|
||||
self.indexer.feed(pagename, filename, title, doctree)
|
||||
|
||||
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str:
|
||||
if 'includehidden' not in kwargs:
|
||||
@ -1108,7 +1108,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
def convert_html_css_files(app: Sphinx, config: Config) -> None:
|
||||
"""This converts string styled html_css_files to tuple styled one."""
|
||||
html_css_files = [] # type: List[Tuple[str, Dict]]
|
||||
html_css_files: List[Tuple[str, Dict]] = []
|
||||
for entry in config.html_css_files:
|
||||
if isinstance(entry, str):
|
||||
html_css_files.append((entry, {}))
|
||||
@ -1125,7 +1125,7 @@ def convert_html_css_files(app: Sphinx, config: Config) -> None:
|
||||
|
||||
def convert_html_js_files(app: Sphinx, config: Config) -> None:
|
||||
"""This converts string styled html_js_files to tuple styled one."""
|
||||
html_js_files = [] # type: List[Tuple[str, Dict]]
|
||||
html_js_files: List[Tuple[str, Dict]] = []
|
||||
for entry in config.html_js_files:
|
||||
if isinstance(entry, str):
|
||||
html_js_files.append((entry, {}))
|
||||
@ -1140,7 +1140,7 @@ def convert_html_js_files(app: Sphinx, config: Config) -> None:
|
||||
config.html_js_files = html_js_files # type: ignore
|
||||
|
||||
|
||||
def setup_js_tag_helper(app: Sphinx, pagename: str, templatexname: str,
|
||||
def setup_js_tag_helper(app: Sphinx, pagename: str, templatename: str,
|
||||
context: Dict, doctree: Node) -> None:
|
||||
"""Set up js_tag() template helper.
|
||||
|
||||
@ -1157,6 +1157,8 @@ def setup_js_tag_helper(app: Sphinx, pagename: str, templatexname: str,
|
||||
if value is not None:
|
||||
if key == 'body':
|
||||
body = value
|
||||
elif key == 'data_url_root':
|
||||
attrs.append('data-url_root="%s"' % pathto('', resource=True))
|
||||
else:
|
||||
attrs.append('%s="%s"' % (key, html.escape(value, True)))
|
||||
if js.filename:
|
||||
@ -1169,6 +1171,26 @@ def setup_js_tag_helper(app: Sphinx, pagename: str, templatexname: str,
|
||||
context['js_tag'] = js_tag
|
||||
|
||||
|
||||
def setup_resource_paths(app: Sphinx, pagename: str, templatename: str,
|
||||
context: Dict, doctree: Node) -> None:
|
||||
"""Set up relative resource paths."""
|
||||
pathto = context.get('pathto')
|
||||
|
||||
# favicon_url
|
||||
favicon = context.get('favicon')
|
||||
if favicon and not isurl(favicon):
|
||||
context['favicon_url'] = pathto('_static/' + favicon, resource=True)
|
||||
else:
|
||||
context['favicon_url'] = favicon
|
||||
|
||||
# logo_url
|
||||
logo = context.get('logo')
|
||||
if logo and not isurl(logo):
|
||||
context['logo_url'] = pathto('_static/' + logo, resource=True)
|
||||
else:
|
||||
context['logo_url'] = logo
|
||||
|
||||
|
||||
def validate_math_renderer(app: Sphinx) -> None:
|
||||
if app.builder.format != 'html':
|
||||
return
|
||||
@ -1209,27 +1231,47 @@ def validate_html_static_path(app: Sphinx, config: Config) -> None:
|
||||
|
||||
def validate_html_logo(app: Sphinx, config: Config) -> None:
|
||||
"""Check html_logo setting."""
|
||||
if config.html_logo and not path.isfile(path.join(app.confdir, config.html_logo)):
|
||||
if (config.html_logo and
|
||||
not path.isfile(path.join(app.confdir, config.html_logo)) and
|
||||
not isurl(config.html_logo)):
|
||||
logger.warning(__('logo file %r does not exist'), config.html_logo)
|
||||
config.html_logo = None # type: ignore
|
||||
|
||||
|
||||
def validate_html_favicon(app: Sphinx, config: Config) -> None:
|
||||
"""Check html_favicon setting."""
|
||||
if config.html_favicon and not path.isfile(path.join(app.confdir, config.html_favicon)):
|
||||
if (config.html_favicon and
|
||||
not path.isfile(path.join(app.confdir, config.html_favicon)) and
|
||||
not isurl(config.html_favicon)):
|
||||
logger.warning(__('favicon file %r does not exist'), config.html_favicon)
|
||||
config.html_favicon = None # type: ignore
|
||||
|
||||
|
||||
class _stable_repr_object():
|
||||
|
||||
def __repr__(self):
|
||||
return '<object>'
|
||||
|
||||
|
||||
UNSET = _stable_repr_object()
|
||||
|
||||
|
||||
def migrate_html_add_permalinks(app: Sphinx, config: Config) -> None:
|
||||
"""Migrate html_add_permalinks to html_permalinks*."""
|
||||
if config.html_add_permalinks:
|
||||
if (isinstance(config.html_add_permalinks, bool) and
|
||||
config.html_add_permalinks is False):
|
||||
config.html_permalinks = False # type: ignore
|
||||
else:
|
||||
config.html_permalinks_icon = html.escape(config.html_add_permalinks) # type: ignore # NOQA
|
||||
html_add_permalinks = config.html_add_permalinks
|
||||
if html_add_permalinks is UNSET:
|
||||
return
|
||||
|
||||
# RemovedInSphinx60Warning
|
||||
logger.warning(__('html_add_permalinks has been deprecated since v3.5.0. '
|
||||
'Please use html_permalinks and html_permalinks_icon instead.'))
|
||||
if not html_add_permalinks:
|
||||
config.html_permalinks = False # type: ignore[attr-defined]
|
||||
return
|
||||
|
||||
config.html_permalinks_icon = html.escape( # type: ignore[attr-defined]
|
||||
html_add_permalinks
|
||||
)
|
||||
|
||||
# for compatibility
|
||||
import sphinxcontrib.serializinghtml # NOQA
|
||||
@ -1261,7 +1303,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value('html_sidebars', {}, 'html')
|
||||
app.add_config_value('html_additional_pages', {}, 'html')
|
||||
app.add_config_value('html_domain_indices', True, 'html', [list])
|
||||
app.add_config_value('html_add_permalinks', None, 'html')
|
||||
app.add_config_value('html_add_permalinks', UNSET, 'html')
|
||||
app.add_config_value('html_permalinks', True, 'html')
|
||||
app.add_config_value('html_permalinks_icon', '¶', 'html')
|
||||
app.add_config_value('html_use_index', True, 'html')
|
||||
@ -1283,7 +1325,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value('html_search_scorer', '', None)
|
||||
app.add_config_value('html_scaled_image_link', True, 'html')
|
||||
app.add_config_value('html_baseurl', '', 'html')
|
||||
app.add_config_value('html_codeblock_linenos_style', 'table', 'html',
|
||||
app.add_config_value('html_codeblock_linenos_style', 'inline', 'html', # RemovedInSphinx60Warning # NOQA
|
||||
ENUM('table', 'inline'))
|
||||
app.add_config_value('html_math_renderer', None, 'env')
|
||||
app.add_config_value('html4_writer', False, 'html')
|
||||
@ -1302,6 +1344,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.connect('config-inited', validate_html_favicon, priority=800)
|
||||
app.connect('builder-inited', validate_math_renderer)
|
||||
app.connect('html-page-context', setup_js_tag_helper)
|
||||
app.connect('html-page-context', setup_resource_paths)
|
||||
|
||||
# load default math renderer
|
||||
app.setup_extension('sphinx.ext.mathjax')
|
||||
|
@ -1,47 +0,0 @@
|
||||
"""
|
||||
sphinx.builders.htmlhelp
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Build HTML help support files.
|
||||
Parts adapted from Python's Doc/tools/prechm.py.
|
||||
|
||||
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinxcontrib.htmlhelp import (HTMLHelpBuilder, chm_htmlescape, chm_locales,
|
||||
default_htmlhelp_basename)
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
deprecated_alias('sphinx.builders.htmlhelp',
|
||||
{
|
||||
'chm_locales': chm_locales,
|
||||
'chm_htmlescape': chm_htmlescape,
|
||||
'HTMLHelpBuilder': HTMLHelpBuilder,
|
||||
'default_htmlhelp_basename': default_htmlhelp_basename,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'chm_locales': 'sphinxcontrib.htmlhelp.chm_locales',
|
||||
'chm_htmlescape': 'sphinxcontrib.htmlhelp.chm_htmlescape',
|
||||
'HTMLHelpBuilder': 'sphinxcontrib.htmlhelp.HTMLHelpBuilder',
|
||||
'default_htmlhelp_basename':
|
||||
'sphinxcontrib.htmlhelp.default_htmlhelp_basename',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
warnings.warn('sphinx.builders.htmlhelp has been moved to sphinxcontrib-htmlhelp.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
app.setup_extension('sphinxcontrib.htmlhelp')
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
@ -24,7 +24,7 @@ from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTING
|
||||
from sphinx.builders.latex.theming import Theme, ThemeFactory
|
||||
from sphinx.builders.latex.util import ExtBabel
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.errors import NoUri, SphinxError
|
||||
from sphinx.locale import _, __
|
||||
@ -122,10 +122,10 @@ class LaTeXBuilder(Builder):
|
||||
default_translator_class = LaTeXTranslator
|
||||
|
||||
def init(self) -> None:
|
||||
self.babel = None # type: ExtBabel
|
||||
self.context = {} # type: Dict[str, Any]
|
||||
self.docnames = [] # type: Iterable[str]
|
||||
self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]]
|
||||
self.babel: ExtBabel = None
|
||||
self.context: Dict[str, Any] = {}
|
||||
self.docnames: Iterable[str] = {}
|
||||
self.document_data: List[Tuple[str, str, str, str, str, bool]] = []
|
||||
self.themes = ThemeFactory(self.app)
|
||||
texescape.init()
|
||||
|
||||
@ -153,7 +153,7 @@ class LaTeXBuilder(Builder):
|
||||
'will be written'))
|
||||
return
|
||||
# assign subdirs to titles
|
||||
self.titles = [] # type: List[Tuple[str, str]]
|
||||
self.titles: List[Tuple[str, str]] = []
|
||||
for entry in preliminary_document_data:
|
||||
docname = entry[0]
|
||||
if docname not in self.env.all_docs:
|
||||
@ -216,14 +216,18 @@ class LaTeXBuilder(Builder):
|
||||
if not self.babel.uses_cyrillic():
|
||||
if 'X2' in self.context['fontenc']:
|
||||
self.context['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
self.context['textcyrillic'] = '\\usepackage[Xtwo]{sphinxcyrillic}'
|
||||
self.context['textcyrillic'] = ('\\usepackage[Xtwo]'
|
||||
'{sphinxpackagecyrillic}')
|
||||
elif 'T2A' in self.context['fontenc']:
|
||||
self.context['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
self.context['textcyrillic'] = '\\usepackage[TtwoA]{sphinxcyrillic}'
|
||||
self.context['textcyrillic'] = ('\\usepackage[TtwoA]'
|
||||
'{sphinxpackagecyrillic}')
|
||||
if 'LGR' in self.context['fontenc']:
|
||||
self.context['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
else:
|
||||
self.context['textgreek'] = ''
|
||||
if self.context['substitutefont'] == '':
|
||||
self.context['fontsubstitution'] = ''
|
||||
|
||||
# 'babel' key is public and user setting must be obeyed
|
||||
if self.context['babel']:
|
||||
@ -252,16 +256,16 @@ class LaTeXBuilder(Builder):
|
||||
with open(stylesheet, 'w') as f:
|
||||
f.write('\\NeedsTeXFormat{LaTeX2e}[1995/12/01]\n')
|
||||
f.write('\\ProvidesPackage{sphinxhighlight}'
|
||||
'[2016/05/29 stylesheet for highlighting with pygments]\n\n')
|
||||
'[2016/05/29 stylesheet for highlighting with pygments]\n')
|
||||
f.write('% Its contents depend on pygments_style configuration variable.\n\n')
|
||||
f.write(highlighter.get_stylesheet())
|
||||
|
||||
def write(self, *ignored: Any) -> None:
|
||||
docwriter = LaTeXWriter(self)
|
||||
docsettings = OptionParser(
|
||||
docsettings: Any = OptionParser(
|
||||
defaults=self.env.settings,
|
||||
components=(docwriter,),
|
||||
read_config_files=True).get_default_values() # type: Any
|
||||
patch_settings(docsettings)
|
||||
read_config_files=True).get_default_values()
|
||||
|
||||
self.init_document_data()
|
||||
self.write_stylesheet()
|
||||
@ -352,7 +356,7 @@ class LaTeXBuilder(Builder):
|
||||
for pendingnode in largetree.traverse(addnodes.pending_xref):
|
||||
docname = pendingnode['refdocname']
|
||||
sectname = pendingnode['refsectname']
|
||||
newnodes = [nodes.emphasis(sectname, sectname)] # type: List[Node]
|
||||
newnodes: List[Node] = [nodes.emphasis(sectname, sectname)]
|
||||
for subdir, title in self.titles:
|
||||
if docname.startswith(subdir):
|
||||
newnodes.append(nodes.Text(_(' (in '), _(' (in ')))
|
||||
@ -364,10 +368,6 @@ class LaTeXBuilder(Builder):
|
||||
pendingnode.replace_self(newnodes)
|
||||
return largetree
|
||||
|
||||
def apply_transforms(self, doctree: nodes.document) -> None:
|
||||
warnings.warn('LaTeXBuilder.apply_transforms() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
def finish(self) -> None:
|
||||
self.copy_image_files()
|
||||
self.write_message_catalog()
|
||||
@ -462,44 +462,6 @@ class LaTeXBuilder(Builder):
|
||||
return self.app.registry.latex_packages_after_hyperref
|
||||
|
||||
|
||||
def patch_settings(settings: Any) -> Any:
|
||||
"""Make settings object to show deprecation messages."""
|
||||
|
||||
class Values(type(settings)): # type: ignore
|
||||
@property
|
||||
def author(self) -> str:
|
||||
warnings.warn('settings.author is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._author
|
||||
|
||||
@property
|
||||
def title(self) -> str:
|
||||
warnings.warn('settings.title is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._title
|
||||
|
||||
@property
|
||||
def contentsname(self) -> str:
|
||||
warnings.warn('settings.contentsname is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._contentsname
|
||||
|
||||
@property
|
||||
def docname(self) -> str:
|
||||
warnings.warn('settings.docname is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._docname
|
||||
|
||||
@property
|
||||
def docclass(self) -> str:
|
||||
warnings.warn('settings.docclass is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self._docclass
|
||||
|
||||
# dynamic subclassing
|
||||
settings.__class__ = Values
|
||||
|
||||
|
||||
def validate_config_values(app: Sphinx, config: Config) -> None:
|
||||
for key in list(config.latex_elements):
|
||||
if key not in DEFAULT_SETTINGS:
|
||||
@ -525,7 +487,7 @@ def install_packages_for_ja(app: Sphinx) -> None:
|
||||
def default_latex_engine(config: Config) -> str:
|
||||
""" Better default latex_engine settings for specific languages. """
|
||||
if config.language == 'ja':
|
||||
return 'platex'
|
||||
return 'uplatex'
|
||||
elif (config.language or '').startswith('zh'):
|
||||
return 'xelatex'
|
||||
elif config.language == 'el':
|
||||
@ -556,7 +518,7 @@ def default_latex_documents(config: Config) -> List[Tuple[str, str, str, str, st
|
||||
""" Better default latex_documents settings. """
|
||||
project = texescape.escape(config.project, config.latex_engine)
|
||||
author = texescape.escape(config.author, config.latex_engine)
|
||||
return [(config.master_doc,
|
||||
return [(config.root_doc,
|
||||
make_filename_from_project(config.project) + '.tex',
|
||||
texescape.escape_abbr(project),
|
||||
texescape.escape_abbr(author),
|
||||
|
@ -11,7 +11,12 @@
|
||||
from typing import Any, Dict
|
||||
|
||||
PDFLATEX_DEFAULT_FONTPKG = r'''
|
||||
\usepackage{times}
|
||||
\usepackage{tgtermes}
|
||||
\usepackage{tgheros}
|
||||
\renewcommand{\ttdefault}{txtt}
|
||||
'''
|
||||
|
||||
PDFLATEX_DEFAULT_FONTSUBSTITUTION = r'''
|
||||
\expandafter\ifx\csname T@LGR\endcsname\relax
|
||||
\else
|
||||
% LGR was declared as font encoding
|
||||
@ -66,7 +71,7 @@ XELATEX_GREEK_DEFAULT_FONTPKG = (XELATEX_DEFAULT_FONTPKG +
|
||||
|
||||
LUALATEX_DEFAULT_FONTPKG = XELATEX_DEFAULT_FONTPKG
|
||||
|
||||
DEFAULT_SETTINGS = {
|
||||
DEFAULT_SETTINGS: Dict[str, Any] = {
|
||||
'latex_engine': 'pdflatex',
|
||||
'papersize': '',
|
||||
'pointsize': '',
|
||||
@ -76,7 +81,7 @@ DEFAULT_SETTINGS = {
|
||||
'maxlistdepth': '',
|
||||
'sphinxpkgoptions': '',
|
||||
'sphinxsetup': '',
|
||||
'fvset': '\\fvset{fontsize=\\small}',
|
||||
'fvset': '\\fvset{fontsize=auto}',
|
||||
'passoptionstopackages': '',
|
||||
'geometry': '\\usepackage{geometry}',
|
||||
'inputenc': '',
|
||||
@ -88,6 +93,7 @@ DEFAULT_SETTINGS = {
|
||||
'babel': '\\usepackage{babel}',
|
||||
'polyglossia': '',
|
||||
'fontpkg': PDFLATEX_DEFAULT_FONTPKG,
|
||||
'fontsubstitution': PDFLATEX_DEFAULT_FONTSUBSTITUTION,
|
||||
'substitutefont': '',
|
||||
'textcyrillic': '',
|
||||
'textgreek': '\\usepackage{textalpha}',
|
||||
@ -115,9 +121,9 @@ DEFAULT_SETTINGS = {
|
||||
'figure_align': 'htbp',
|
||||
'tocdepth': '',
|
||||
'secnumdepth': '',
|
||||
} # type: Dict[str, Any]
|
||||
}
|
||||
|
||||
ADDITIONAL_SETTINGS = {
|
||||
ADDITIONAL_SETTINGS: Dict[Any, Dict[str, Any]] = {
|
||||
'pdflatex': {
|
||||
'inputenc': '\\usepackage[utf8]{inputenc}',
|
||||
'utf8extra': ('\\ifdefined\\DeclareUnicodeCharacter\n'
|
||||
@ -142,6 +148,8 @@ ADDITIONAL_SETTINGS = {
|
||||
'fontenc': ('\\usepackage{fontspec}\n'
|
||||
'\\defaultfontfeatures[\\rmfamily,\\sffamily,\\ttfamily]{}'),
|
||||
'fontpkg': XELATEX_DEFAULT_FONTPKG,
|
||||
'fvset': '\\fvset{fontsize=\\small}',
|
||||
'fontsubstitution': '',
|
||||
'textgreek': '',
|
||||
'utf8extra': ('\\catcode`^^^^00a0\\active\\protected\\def^^^^00a0'
|
||||
'{\\leavevmode\\nobreak\\ }'),
|
||||
@ -153,6 +161,8 @@ ADDITIONAL_SETTINGS = {
|
||||
'fontenc': ('\\usepackage{fontspec}\n'
|
||||
'\\defaultfontfeatures[\\rmfamily,\\sffamily,\\ttfamily]{}'),
|
||||
'fontpkg': LUALATEX_DEFAULT_FONTPKG,
|
||||
'fvset': '\\fvset{fontsize=\\small}',
|
||||
'fontsubstitution': '',
|
||||
'textgreek': '',
|
||||
'utf8extra': ('\\catcode`^^^^00a0\\active\\protected\\def^^^^00a0'
|
||||
'{\\leavevmode\\nobreak\\ }'),
|
||||
@ -161,7 +171,8 @@ ADDITIONAL_SETTINGS = {
|
||||
'latex_engine': 'platex',
|
||||
'babel': '',
|
||||
'classoptions': ',dvipdfmx',
|
||||
'fontpkg': '\\usepackage{times}',
|
||||
'fontpkg': PDFLATEX_DEFAULT_FONTPKG,
|
||||
'fontsubstitution': '',
|
||||
'textgreek': '',
|
||||
'fncychap': '',
|
||||
'geometry': '\\usepackage[dvipdfm]{geometry}',
|
||||
@ -170,7 +181,8 @@ ADDITIONAL_SETTINGS = {
|
||||
'latex_engine': 'uplatex',
|
||||
'babel': '',
|
||||
'classoptions': ',dvipdfmx',
|
||||
'fontpkg': '\\usepackage{times}',
|
||||
'fontpkg': PDFLATEX_DEFAULT_FONTPKG,
|
||||
'fontsubstitution': '',
|
||||
'textgreek': '',
|
||||
'fncychap': '',
|
||||
'geometry': '\\usepackage[dvipdfm]{geometry}',
|
||||
@ -190,7 +202,7 @@ ADDITIONAL_SETTINGS = {
|
||||
('xelatex', 'el'): {
|
||||
'fontpkg': XELATEX_GREEK_DEFAULT_FONTPKG,
|
||||
},
|
||||
} # type: Dict[Any, Dict[str, Any]]
|
||||
}
|
||||
|
||||
|
||||
SHORTHANDOFF = r'''
|
||||
|
@ -106,7 +106,7 @@ class ThemeFactory:
|
||||
"""A factory class for LaTeX Themes."""
|
||||
|
||||
def __init__(self, app: Sphinx) -> None:
|
||||
self.themes = {} # type: Dict[str, Theme]
|
||||
self.themes: Dict[str, Theme] = {}
|
||||
self.theme_paths = [path.join(app.srcdir, p) for p in app.config.latex_theme_path]
|
||||
self.config = app.config
|
||||
self.load_builtin_themes(app.config)
|
||||
|
@ -33,7 +33,7 @@ class FootnoteDocnameUpdater(SphinxTransform):
|
||||
|
||||
def apply(self, **kwargs: Any) -> None:
|
||||
matcher = NodeMatcher(*self.TARGET_NODES)
|
||||
for node in self.document.traverse(matcher): # type: nodes.Element
|
||||
for node in self.document.traverse(matcher): # type: Element
|
||||
node['docname'] = self.env.docname
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ class ShowUrlsTransform(SphinxPostTransform):
|
||||
def run(self, **kwargs: Any) -> None:
|
||||
try:
|
||||
# replace id_prefix temporarily
|
||||
settings = self.document.settings # type: Any
|
||||
settings: Any = self.document.settings
|
||||
id_prefix = settings.id_prefix
|
||||
settings.id_prefix = 'show_urls'
|
||||
|
||||
@ -157,9 +157,9 @@ class FootnoteCollector(nodes.NodeVisitor):
|
||||
"""Collect footnotes and footnote references on the document"""
|
||||
|
||||
def __init__(self, document: nodes.document) -> None:
|
||||
self.auto_footnotes = [] # type: List[nodes.footnote]
|
||||
self.used_footnote_numbers = set() # type: Set[str]
|
||||
self.footnote_refs = [] # type: List[nodes.footnote_reference]
|
||||
self.auto_footnotes: List[nodes.footnote] = []
|
||||
self.used_footnote_numbers: Set[str] = set()
|
||||
self.footnote_refs: List[nodes.footnote_reference] = []
|
||||
super().__init__(document)
|
||||
|
||||
def unknown_visit(self, node: Node) -> None:
|
||||
@ -358,11 +358,11 @@ class LaTeXFootnoteTransform(SphinxPostTransform):
|
||||
|
||||
class LaTeXFootnoteVisitor(nodes.NodeVisitor):
|
||||
def __init__(self, document: nodes.document, footnotes: List[nodes.footnote]) -> None:
|
||||
self.appeared = set() # type: Set[Tuple[str, str]]
|
||||
self.footnotes = footnotes # type: List[nodes.footnote]
|
||||
self.pendings = [] # type: List[nodes.footnote]
|
||||
self.table_footnotes = [] # type: List[nodes.footnote]
|
||||
self.restricted = None # type: nodes.Element
|
||||
self.appeared: Set[Tuple[str, str]] = set()
|
||||
self.footnotes: List[nodes.footnote] = footnotes
|
||||
self.pendings: List[nodes.footnote] = []
|
||||
self.table_footnotes: List[nodes.footnote] = []
|
||||
self.restricted: Element = None
|
||||
super().__init__(document)
|
||||
|
||||
def unknown_visit(self, node: Node) -> None:
|
||||
|
@ -9,7 +9,6 @@
|
||||
"""
|
||||
|
||||
import json
|
||||
import queue
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
@ -18,6 +17,7 @@ from datetime import datetime, timezone
|
||||
from email.utils import parsedate_to_datetime
|
||||
from html.parser import HTMLParser
|
||||
from os import path
|
||||
from queue import PriorityQueue, Queue
|
||||
from threading import Thread
|
||||
from typing import (Any, Dict, Generator, List, NamedTuple, Optional, Pattern, Set, Tuple,
|
||||
Union, cast)
|
||||
@ -120,16 +120,16 @@ class CheckExternalLinksBuilder(DummyBuilder):
|
||||
'%(outdir)s/output.txt')
|
||||
|
||||
def init(self) -> None:
|
||||
self.hyperlinks = {} # type: Dict[str, Hyperlink]
|
||||
self._good = set() # type: Set[str]
|
||||
self._broken = {} # type: Dict[str, str]
|
||||
self._redirected = {} # type: Dict[str, Tuple[str, int]]
|
||||
self.hyperlinks: Dict[str, Hyperlink] = {}
|
||||
self._good: Set[str] = set()
|
||||
self._broken: Dict[str, str] = {}
|
||||
self._redirected: Dict[str, Tuple[str, int]] = {}
|
||||
# set a timeout for non-responding servers
|
||||
socket.setdefaulttimeout(5.0)
|
||||
|
||||
# create queues and worker threads
|
||||
self._wqueue = queue.PriorityQueue() # type: queue.PriorityQueue[CheckRequestType]
|
||||
self._rqueue = queue.Queue() # type: queue.Queue
|
||||
self._wqueue: PriorityQueue[CheckRequestType] = PriorityQueue()
|
||||
self._rqueue: Queue = Queue()
|
||||
|
||||
@property
|
||||
def anchors_ignore(self) -> List[Pattern]:
|
||||
@ -204,7 +204,7 @@ class CheckExternalLinksBuilder(DummyBuilder):
|
||||
None, None, {})
|
||||
return worker.limit_rate(response)
|
||||
|
||||
def rqueue(self, response: Response) -> queue.Queue:
|
||||
def rqueue(self, response: Response) -> Queue:
|
||||
warnings.warn(
|
||||
"%s.%s is deprecated." % (self.__class__.__name__, "rqueue"),
|
||||
RemovedInSphinx50Warning,
|
||||
@ -220,7 +220,7 @@ class CheckExternalLinksBuilder(DummyBuilder):
|
||||
)
|
||||
return []
|
||||
|
||||
def wqueue(self, response: Response) -> queue.Queue:
|
||||
def wqueue(self, response: Response) -> Queue:
|
||||
warnings.warn(
|
||||
"%s.%s is deprecated." % (self.__class__.__name__, "wqueue"),
|
||||
RemovedInSphinx50Warning,
|
||||
@ -313,8 +313,8 @@ class HyperlinkAvailabilityChecker:
|
||||
self.builder = builder
|
||||
self.config = config
|
||||
self.env = env
|
||||
self.rate_limits = {} # type: Dict[str, RateLimit]
|
||||
self.workers = [] # type: List[Thread]
|
||||
self.rate_limits: Dict[str, RateLimit] = {}
|
||||
self.workers: List[Thread] = []
|
||||
|
||||
self.to_ignore = [re.compile(x) for x in self.config.linkcheck_ignore]
|
||||
|
||||
@ -322,8 +322,8 @@ class HyperlinkAvailabilityChecker:
|
||||
self.rqueue = builder._rqueue
|
||||
self.wqueue = builder._wqueue
|
||||
else:
|
||||
self.rqueue = queue.Queue()
|
||||
self.wqueue = queue.PriorityQueue()
|
||||
self.rqueue = Queue()
|
||||
self.wqueue = PriorityQueue()
|
||||
|
||||
def invoke_threads(self) -> None:
|
||||
for i in range(self.config.linkcheck_workers):
|
||||
@ -364,8 +364,8 @@ class HyperlinkAvailabilityChecker:
|
||||
class HyperlinkAvailabilityCheckWorker(Thread):
|
||||
"""A worker class for checking the availability of hyperlinks."""
|
||||
|
||||
def __init__(self, env: BuildEnvironment, config: Config, rqueue: queue.Queue,
|
||||
wqueue: queue.Queue, rate_limits: Dict[str, RateLimit],
|
||||
def __init__(self, env: BuildEnvironment, config: Config, rqueue: Queue,
|
||||
wqueue: Queue, rate_limits: Dict[str, RateLimit],
|
||||
builder: CheckExternalLinksBuilder = None) -> None:
|
||||
# Warning: builder argument will be removed in the sphinx-5.0.
|
||||
# Don't use it from extensions.
|
||||
|
@ -38,7 +38,7 @@ class ManualPageBuilder(Builder):
|
||||
epilog = __('The manual pages are in %(outdir)s.')
|
||||
|
||||
default_translator_class = ManualPageTranslator
|
||||
supported_image_types = [] # type: List[str]
|
||||
supported_image_types: List[str] = []
|
||||
|
||||
def init(self) -> None:
|
||||
if not self.config.man_pages:
|
||||
@ -56,10 +56,10 @@ class ManualPageBuilder(Builder):
|
||||
@progress_message(__('writing'))
|
||||
def write(self, *ignored: Any) -> None:
|
||||
docwriter = ManualPageWriter(self)
|
||||
docsettings = OptionParser(
|
||||
docsettings: Any = OptionParser(
|
||||
defaults=self.env.settings,
|
||||
components=(docwriter,),
|
||||
read_config_files=True).get_default_values() # type: Any
|
||||
read_config_files=True).get_default_values()
|
||||
|
||||
for info in self.config.man_pages:
|
||||
docname, name, description, authors, section = info
|
||||
@ -90,7 +90,7 @@ class ManualPageBuilder(Builder):
|
||||
encoding='utf-8')
|
||||
|
||||
tree = self.env.get_doctree(docname)
|
||||
docnames = set() # type: Set[str]
|
||||
docnames: Set[str] = set()
|
||||
largetree = inline_all_toctrees(self, docnames, docname, tree,
|
||||
darkgreen, [docname])
|
||||
largetree.settings = docsettings
|
||||
@ -109,7 +109,7 @@ class ManualPageBuilder(Builder):
|
||||
def default_man_pages(config: Config) -> List[Tuple[str, str, str, List[str], int]]:
|
||||
""" Better default man_pages settings. """
|
||||
filename = make_filename_from_project(config.project)
|
||||
return [(config.master_doc, filename, '%s %s' % (config.project, config.release),
|
||||
return [(config.root_doc, filename, '%s %s' % (config.project, config.release),
|
||||
[config.author], 1)]
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
||||
app.add_config_value('man_pages', default_man_pages, None)
|
||||
app.add_config_value('man_show_urls', False, None)
|
||||
app.add_config_value('man_make_section_directory', False, None)
|
||||
app.add_config_value('man_make_section_directory', True, None)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
@ -1,42 +0,0 @@
|
||||
"""
|
||||
sphinx.builders.qthelp
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Build input files for the Qt collection generator.
|
||||
|
||||
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinxcontrib.qthelp import QtHelpBuilder, render_file
|
||||
|
||||
import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
deprecated_alias('sphinx.builders.qthelp',
|
||||
{
|
||||
'render_file': render_file,
|
||||
'QtHelpBuilder': QtHelpBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'render_file': 'sphinxcontrib.qthelp.render_file',
|
||||
'QtHelpBuilder': 'sphinxcontrib.qthelp.QtHelpBuilder',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
warnings.warn('sphinx.builders.qthelp has been moved to sphinxcontrib-qthelp.',
|
||||
RemovedInSphinx40Warning)
|
||||
|
||||
app.setup_extension('sphinxcontrib.qthelp')
|
||||
|
||||
return {
|
||||
'version': sphinx.__display_version__,
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
@ -42,7 +42,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
def get_target_uri(self, docname: str, typ: str = None) -> str:
|
||||
if docname in self.env.all_docs:
|
||||
# all references are on the same page...
|
||||
return self.config.master_doc + self.out_suffix + \
|
||||
return self.config.root_doc + self.out_suffix + \
|
||||
'#document-' + docname
|
||||
else:
|
||||
# chances are this is a html_additional_page
|
||||
@ -54,7 +54,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
|
||||
def fix_refuris(self, tree: Node) -> None:
|
||||
# fix refuris with double anchor
|
||||
fname = self.config.master_doc + self.out_suffix
|
||||
fname = self.config.root_doc + self.out_suffix
|
||||
for refnode in tree.traverse(nodes.reference):
|
||||
if 'refuri' not in refnode:
|
||||
continue
|
||||
@ -75,7 +75,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
return self.render_partial(toctree)['fragment']
|
||||
|
||||
def assemble_doctree(self) -> nodes.document:
|
||||
master = self.config.master_doc
|
||||
master = self.config.root_doc
|
||||
tree = self.env.get_doctree(master)
|
||||
tree = inline_all_toctrees(self, set(), master, tree, darkgreen, [master])
|
||||
tree['docname'] = master
|
||||
@ -93,13 +93,13 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
#
|
||||
# There are related codes in inline_all_toctres() and
|
||||
# HTMLTranslter#add_secnumber().
|
||||
new_secnumbers = {} # type: Dict[str, Tuple[int, ...]]
|
||||
new_secnumbers: Dict[str, Tuple[int, ...]] = {}
|
||||
for docname, secnums in self.env.toc_secnumbers.items():
|
||||
for id, secnum in secnums.items():
|
||||
alias = "%s/%s" % (docname, id)
|
||||
new_secnumbers[alias] = secnum
|
||||
|
||||
return {self.config.master_doc: new_secnumbers}
|
||||
return {self.config.root_doc: new_secnumbers}
|
||||
|
||||
def assemble_toc_fignumbers(self) -> Dict[str, Dict[str, Dict[str, Tuple[int, ...]]]]:
|
||||
# Assemble toc_fignumbers to resolve figure numbers on SingleHTML.
|
||||
@ -111,7 +111,7 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
#
|
||||
# There are related codes in inline_all_toctres() and
|
||||
# HTMLTranslter#add_fignumber().
|
||||
new_fignumbers = {} # type: Dict[str, Dict[str, Tuple[int, ...]]]
|
||||
new_fignumbers: Dict[str, Dict[str, Tuple[int, ...]]] = {}
|
||||
# {'foo': {'figure': {'id2': (2,), 'id1': (1,)}}, 'bar': {'figure': {'id1': (3,)}}}
|
||||
for docname, fignumlist in self.env.toc_fignumbers.items():
|
||||
for figtype, fignums in fignumlist.items():
|
||||
@ -120,11 +120,11 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
for id, fignum in fignums.items():
|
||||
new_fignumbers[alias][id] = fignum
|
||||
|
||||
return {self.config.master_doc: new_fignumbers}
|
||||
return {self.config.root_doc: new_fignumbers}
|
||||
|
||||
def get_doc_context(self, docname: str, body: str, metatags: str) -> Dict:
|
||||
# no relation links...
|
||||
toctree = TocTree(self.env).get_toctree_for(self.config.master_doc, self, False)
|
||||
toctree = TocTree(self.env).get_toctree_for(self.config.root_doc, self, False)
|
||||
# if there is no toctree, toc is None
|
||||
if toctree:
|
||||
self.fix_refuris(toctree)
|
||||
@ -160,8 +160,8 @@ class SingleFileHTMLBuilder(StandaloneHTMLBuilder):
|
||||
self.env.toc_fignumbers = self.assemble_toc_fignumbers()
|
||||
|
||||
with progress_message(__('writing')):
|
||||
self.write_doc_serialized(self.config.master_doc, doctree)
|
||||
self.write_doc(self.config.master_doc, doctree)
|
||||
self.write_doc_serialized(self.config.root_doc, doctree)
|
||||
self.write_doc(self.config.root_doc, doctree)
|
||||
|
||||
def finish(self) -> None:
|
||||
self.write_additional_files()
|
||||
|
@ -15,6 +15,7 @@ from typing import Any, Dict, Iterable, List, Tuple, Union
|
||||
from docutils import nodes
|
||||
from docutils.frontend import OptionParser
|
||||
from docutils.io import FileOutput
|
||||
from docutils.nodes import Node
|
||||
|
||||
from sphinx import addnodes, package_dir
|
||||
from sphinx.application import Sphinx
|
||||
@ -52,8 +53,8 @@ class TexinfoBuilder(Builder):
|
||||
default_translator_class = TexinfoTranslator
|
||||
|
||||
def init(self) -> None:
|
||||
self.docnames = [] # type: Iterable[str]
|
||||
self.document_data = [] # type: List[Tuple[str, str, str, str, str, str, str, bool]]
|
||||
self.docnames: Iterable[str] = []
|
||||
self.document_data: List[Tuple[str, str, str, str, str, str, str, bool]] = []
|
||||
|
||||
def get_outdated_docs(self) -> Union[str, List[str]]:
|
||||
return 'all documents' # for now
|
||||
@ -75,7 +76,7 @@ class TexinfoBuilder(Builder):
|
||||
'will be written'))
|
||||
return
|
||||
# assign subdirs to titles
|
||||
self.titles = [] # type: List[Tuple[str, str]]
|
||||
self.titles: List[Tuple[str, str]] = []
|
||||
for entry in preliminary_document_data:
|
||||
docname = entry[0]
|
||||
if docname not in self.env.all_docs:
|
||||
@ -108,10 +109,10 @@ class TexinfoBuilder(Builder):
|
||||
with progress_message(__("writing")):
|
||||
self.post_process_images(doctree)
|
||||
docwriter = TexinfoWriter(self)
|
||||
settings = OptionParser(
|
||||
settings: Any = OptionParser(
|
||||
defaults=self.env.settings,
|
||||
components=(docwriter,),
|
||||
read_config_files=True).get_default_values() # type: Any
|
||||
read_config_files=True).get_default_values()
|
||||
settings.author = author
|
||||
settings.title = title
|
||||
settings.texinfo_filename = targetname[:-5] + '.info'
|
||||
@ -154,7 +155,7 @@ class TexinfoBuilder(Builder):
|
||||
for pendingnode in largetree.traverse(addnodes.pending_xref):
|
||||
docname = pendingnode['refdocname']
|
||||
sectname = pendingnode['refsectname']
|
||||
newnodes = [nodes.emphasis(sectname, sectname)] # type: List[nodes.Node]
|
||||
newnodes: List[Node] = [nodes.emphasis(sectname, sectname)]
|
||||
for subdir, title in self.titles:
|
||||
if docname.startswith(subdir):
|
||||
newnodes.append(nodes.Text(_(' (in '), _(' (in ')))
|
||||
@ -197,7 +198,7 @@ class TexinfoBuilder(Builder):
|
||||
def default_texinfo_documents(config: Config) -> List[Tuple[str, str, str, str, str, str, str]]: # NOQA
|
||||
""" Better default texinfo_documents settings. """
|
||||
filename = make_filename_from_project(config.project)
|
||||
return [(config.master_doc, filename, config.project, config.author, filename,
|
||||
return [(config.root_doc, filename, config.project, config.author, filename,
|
||||
'One line description of project', 'Miscellaneous')]
|
||||
|
||||
|
||||
|
@ -33,11 +33,11 @@ class TextBuilder(Builder):
|
||||
allow_parallel = True
|
||||
default_translator_class = TextTranslator
|
||||
|
||||
current_docname = None # type: str
|
||||
current_docname: str = None
|
||||
|
||||
def init(self) -> None:
|
||||
# section numbers for headings in the currently visited document
|
||||
self.secnumbers = {} # type: Dict[str, Tuple[int, ...]]
|
||||
self.secnumbers: Dict[str, Tuple[int, ...]] = {}
|
||||
|
||||
def get_outdated_docs(self) -> Iterator[str]:
|
||||
for docname in self.env.found_docs:
|
||||
|
@ -9,7 +9,7 @@
|
||||
"""
|
||||
|
||||
from os import path
|
||||
from typing import Any, Dict, Iterator, Set, Union
|
||||
from typing import Any, Dict, Iterator, Set, Type, Union
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.io import StringOutput
|
||||
@ -23,11 +23,6 @@ from sphinx.util import logging
|
||||
from sphinx.util.osutil import ensuredir, os_path
|
||||
from sphinx.writers.xml import PseudoXMLWriter, XMLWriter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -42,7 +37,7 @@ class XMLBuilder(Builder):
|
||||
out_suffix = '.xml'
|
||||
allow_parallel = True
|
||||
|
||||
_writer_class = XMLWriter # type: Union[Type[XMLWriter], Type[PseudoXMLWriter]]
|
||||
_writer_class: Union[Type[XMLWriter], Type[PseudoXMLWriter]] = XMLWriter
|
||||
default_translator_class = XMLTranslator
|
||||
|
||||
def init(self) -> None:
|
||||
|
@ -50,6 +50,7 @@ BUILDERS = [
|
||||
("", "doctest", "to run all doctests embedded in the documentation "
|
||||
"(if enabled)"),
|
||||
("", "coverage", "to run coverage check of the documentation (if enabled)"),
|
||||
("", "clean", "to remove everything in the build directory"),
|
||||
]
|
||||
|
||||
|
||||
|
@ -11,13 +11,11 @@
|
||||
import argparse
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
from collections import OrderedDict
|
||||
from os import path
|
||||
from typing import Any, Callable, Dict, List, Pattern, Union
|
||||
from typing import Any, Callable, Dict, List, Union
|
||||
|
||||
# try to import readline, unix specific enhancement
|
||||
try:
|
||||
@ -36,15 +34,11 @@ from docutils.utils import column_width
|
||||
|
||||
import sphinx.locale
|
||||
from sphinx import __display_version__, package_dir
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import __
|
||||
from sphinx.util.console import (bold, color_terminal, colorize, nocolor, red, # type: ignore
|
||||
turquoise)
|
||||
from sphinx.util.console import bold, color_terminal, colorize, nocolor, red # type: ignore
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.template import SphinxRenderer
|
||||
|
||||
TERM_ENCODING = getattr(sys.stdin, 'encoding', None) # RemovedInSphinx40Warning
|
||||
|
||||
EXTENSIONS = OrderedDict([
|
||||
('autodoc', __('automatically insert docstrings from modules')),
|
||||
('doctest', __('automatically test code snippets in doctest blocks')),
|
||||
@ -135,30 +129,6 @@ def ok(x: str) -> str:
|
||||
return x
|
||||
|
||||
|
||||
def term_decode(text: Union[bytes, str]) -> str:
|
||||
warnings.warn('term_decode() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
if isinstance(text, str):
|
||||
return text
|
||||
|
||||
# Use the known encoding, if possible
|
||||
if TERM_ENCODING:
|
||||
return text.decode(TERM_ENCODING)
|
||||
|
||||
# If ascii is safe, use it with no warning
|
||||
if text.decode('ascii', 'replace').encode('ascii', 'replace') == text:
|
||||
return text.decode('ascii')
|
||||
|
||||
print(turquoise(__('* Note: non-ASCII characters entered '
|
||||
'and terminal encoding unknown -- assuming '
|
||||
'UTF-8 or Latin-1.')))
|
||||
try:
|
||||
return text.decode()
|
||||
except UnicodeDecodeError:
|
||||
return text.decode('latin1')
|
||||
|
||||
|
||||
def do_prompt(text: str, default: str = None, validator: Callable[[str], Any] = nonempty) -> Union[str, bool]: # NOQA
|
||||
while True:
|
||||
if default is not None:
|
||||
@ -187,22 +157,27 @@ def do_prompt(text: str, default: str = None, validator: Callable[[str], Any] =
|
||||
return x
|
||||
|
||||
|
||||
def convert_python_source(source: str, rex: Pattern = re.compile(r"[uU]('.*?')")) -> str:
|
||||
# remove Unicode literal prefixes
|
||||
warnings.warn('convert_python_source() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return rex.sub('\\1', source)
|
||||
|
||||
|
||||
class QuickstartRenderer(SphinxRenderer):
|
||||
def __init__(self, templatedir: str) -> None:
|
||||
self.templatedir = templatedir or ''
|
||||
super().__init__()
|
||||
|
||||
def _has_custom_template(self, template_name: str) -> bool:
|
||||
"""Check if custom template file exists.
|
||||
|
||||
Note: Please don't use this function from extensions.
|
||||
It will be removed in the future without deprecation period.
|
||||
"""
|
||||
template = path.join(self.templatedir, path.basename(template_name))
|
||||
if self.templatedir and path.exists(template):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def render(self, template_name: str, context: Dict) -> str:
|
||||
user_template = path.join(self.templatedir, path.basename(template_name))
|
||||
if self.templatedir and path.exists(user_template):
|
||||
return self.render_from_file(user_template, context)
|
||||
if self._has_custom_template(template_name):
|
||||
custom_template = path.join(self.templatedir, path.basename(template_name))
|
||||
return self.render_from_file(custom_template, context)
|
||||
else:
|
||||
return super().render(template_name, context)
|
||||
|
||||
@ -355,6 +330,7 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir:
|
||||
if 'mastertocmaxdepth' not in d:
|
||||
d['mastertocmaxdepth'] = 2
|
||||
|
||||
d['root_doc'] = d['master']
|
||||
d['now'] = time.asctime()
|
||||
d['project_underline'] = column_width(d['project']) * '='
|
||||
d.setdefault('extensions', [])
|
||||
@ -399,7 +375,13 @@ def generate(d: Dict, overwrite: bool = True, silent: bool = False, templatedir:
|
||||
write_file(path.join(srcdir, 'conf.py'), template.render_string(conf_text, d))
|
||||
|
||||
masterfile = path.join(srcdir, d['master'] + d['suffix'])
|
||||
write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))
|
||||
if template._has_custom_template('quickstart/master_doc.rst_t'):
|
||||
msg = ('A custom template `master_doc.rst_t` found. It has been renamed to '
|
||||
'`root_doc.rst_t`. Please rename it on your project too.')
|
||||
print(colorize('red', msg)) # RemovedInSphinx60Warning
|
||||
write_file(masterfile, template.render('quickstart/master_doc.rst_t', d))
|
||||
else:
|
||||
write_file(masterfile, template.render('quickstart/root_doc.rst_t', d))
|
||||
|
||||
if d.get('make_mode') is True:
|
||||
makefile_template = 'quickstart/Makefile.new_t'
|
||||
|
@ -11,24 +11,20 @@
|
||||
import re
|
||||
import traceback
|
||||
import types
|
||||
import warnings
|
||||
from collections import OrderedDict
|
||||
from os import getenv, path
|
||||
from typing import (Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple,
|
||||
Union)
|
||||
from typing import (TYPE_CHECKING, Any, Callable, Dict, Generator, Iterator, List, NamedTuple,
|
||||
Optional, Set, Tuple, Union)
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.errors import ConfigError, ExtensionError
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.osutil import cd
|
||||
from sphinx.util.pycompat import execfile_
|
||||
from sphinx.util.osutil import cd, fs_encoding
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.util.typing import NoneType
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
@ -38,9 +34,11 @@ CONFIG_FILENAME = 'conf.py'
|
||||
UNSERIALIZABLE_TYPES = (type, types.ModuleType, types.FunctionType)
|
||||
copyright_year_re = re.compile(r'^((\d{4}-)?)(\d{4})(?=[ ,])')
|
||||
|
||||
ConfigValue = NamedTuple('ConfigValue', [('name', str),
|
||||
('value', Any),
|
||||
('rebuild', Union[bool, str])])
|
||||
|
||||
class ConfigValue(NamedTuple):
|
||||
name: str
|
||||
value: Any
|
||||
rebuild: Union[bool, str]
|
||||
|
||||
|
||||
def is_serializable(obj: Any) -> bool:
|
||||
@ -73,10 +71,6 @@ class ENUM:
|
||||
return value in self.candidates
|
||||
|
||||
|
||||
# RemovedInSphinx40Warning
|
||||
string_classes = [str] # type: List
|
||||
|
||||
|
||||
class Config:
|
||||
"""Configuration file abstraction.
|
||||
|
||||
@ -94,7 +88,7 @@ class Config:
|
||||
# If you add a value here, don't forget to include it in the
|
||||
# quickstart.py file template as well as in the docs!
|
||||
|
||||
config_values = {
|
||||
config_values: Dict[str, Tuple] = {
|
||||
# general options
|
||||
'project': ('Python', 'env', []),
|
||||
'author': ('unknown', 'env', []),
|
||||
@ -111,9 +105,9 @@ class Config:
|
||||
'figure_language_filename': ('{root}.{language}{ext}', 'env', [str]),
|
||||
|
||||
'master_doc': ('index', 'env', []),
|
||||
'root_doc': (lambda config: config.master_doc, 'env', []),
|
||||
'source_suffix': ({'.rst': 'restructuredtext'}, 'env', Any),
|
||||
'source_encoding': ('utf-8-sig', 'env', []),
|
||||
'source_parsers': ({}, 'env', []),
|
||||
'exclude_patterns': ([], 'env', []),
|
||||
'default_role': (None, 'env', [str]),
|
||||
'add_function_parentheses': (True, 'env', []),
|
||||
@ -152,20 +146,20 @@ class Config:
|
||||
'smartquotes_excludes': ({'languages': ['ja'],
|
||||
'builders': ['man', 'text']},
|
||||
'env', []),
|
||||
} # type: Dict[str, Tuple]
|
||||
}
|
||||
|
||||
def __init__(self, config: Dict[str, Any] = {}, overrides: Dict[str, Any] = {}) -> None:
|
||||
self.overrides = dict(overrides)
|
||||
self.values = Config.config_values.copy()
|
||||
self._raw_config = config
|
||||
self.setup = config.get('setup', None) # type: Callable
|
||||
self.setup: Optional[Callable] = config.get('setup', None)
|
||||
|
||||
if 'extensions' in self.overrides:
|
||||
if isinstance(self.overrides['extensions'], str):
|
||||
config['extensions'] = self.overrides.pop('extensions').split(',')
|
||||
else:
|
||||
config['extensions'] = self.overrides.pop('extensions')
|
||||
self.extensions = config.get('extensions', []) # type: List[str]
|
||||
self.extensions: List[str] = config.get('extensions', [])
|
||||
|
||||
@classmethod
|
||||
def read(cls, confdir: str, overrides: Dict = None, tags: Tags = None) -> "Config":
|
||||
@ -317,14 +311,16 @@ class Config:
|
||||
|
||||
def eval_config_file(filename: str, tags: Tags) -> Dict[str, Any]:
|
||||
"""Evaluate a config file."""
|
||||
namespace = {} # type: Dict[str, Any]
|
||||
namespace: Dict[str, Any] = {}
|
||||
namespace['__file__'] = filename
|
||||
namespace['tags'] = tags
|
||||
|
||||
with cd(path.dirname(filename)):
|
||||
# during executing config file, current dir is changed to ``confdir``.
|
||||
try:
|
||||
execfile_(filename, namespace)
|
||||
with open(filename, 'rb') as f:
|
||||
code = compile(f.read(), filename.encode(fs_encoding), 'exec')
|
||||
exec(code, namespace)
|
||||
except SyntaxError as err:
|
||||
msg = __("There is a syntax error in your configuration file: %s\n")
|
||||
raise ConfigError(msg % err) from err
|
||||
@ -459,22 +455,6 @@ def check_confval_types(app: "Sphinx", config: Config) -> None:
|
||||
default=type(default)))
|
||||
|
||||
|
||||
def check_unicode(config: Config) -> None:
|
||||
"""check all string values for non-ASCII characters in bytestrings,
|
||||
since that can result in UnicodeErrors all over the place
|
||||
"""
|
||||
warnings.warn('sphinx.config.check_unicode() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
nonascii_re = re.compile(br'[\x80-\xff]')
|
||||
|
||||
for name, value in config._raw_config.items():
|
||||
if isinstance(value, bytes) 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, 'Content')
|
||||
|
||||
|
||||
def check_primary_domain(app: "Sphinx", config: Config) -> None:
|
||||
primary_domain = config.primary_domain
|
||||
if primary_domain and not app.registry.has_domain(primary_domain):
|
||||
@ -482,17 +462,17 @@ def check_primary_domain(app: "Sphinx", config: Config) -> None:
|
||||
config.primary_domain = None # type: ignore
|
||||
|
||||
|
||||
def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],
|
||||
changed: Set[str], removed: Set[str]) -> Set[str]:
|
||||
"""Adjust master_doc to 'contents' to support an old project which does not have
|
||||
no master_doc setting.
|
||||
def check_root_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],
|
||||
changed: Set[str], removed: Set[str]) -> Set[str]:
|
||||
"""Adjust root_doc to 'contents' to support an old project which does not have
|
||||
no root_doc setting.
|
||||
"""
|
||||
if (app.config.master_doc == 'index' and
|
||||
if (app.config.root_doc == 'index' and
|
||||
'index' not in app.project.docnames and
|
||||
'contents' in app.project.docnames):
|
||||
logger.warning(__('Since v2.0, Sphinx uses "index" as master_doc by default. '
|
||||
'Please add "master_doc = \'contents\'" to your conf.py.'))
|
||||
app.config.master_doc = "contents" # type: ignore
|
||||
logger.warning(__('Since v2.0, Sphinx uses "index" as root_doc by default. '
|
||||
'Please add "root_doc = \'contents\'" to your conf.py.'))
|
||||
app.config.root_doc = "contents" # type: ignore
|
||||
|
||||
return changed
|
||||
|
||||
@ -504,7 +484,7 @@ def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
app.connect('config-inited', correct_copyright_year, priority=800)
|
||||
app.connect('config-inited', check_confval_types, priority=800)
|
||||
app.connect('config-inited', check_primary_domain, priority=800)
|
||||
app.connect('env-get-outdated', check_master_doc)
|
||||
app.connect('env-get-outdated', check_root_doc)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
@ -11,18 +11,14 @@
|
||||
import sys
|
||||
import warnings
|
||||
from importlib import import_module
|
||||
from typing import Any, Dict
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
from typing import Any, Dict, Type
|
||||
|
||||
|
||||
class RemovedInSphinx40Warning(DeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInSphinx50Warning(PendingDeprecationWarning):
|
||||
class RemovedInSphinx50Warning(DeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
@ -30,11 +26,11 @@ class RemovedInSphinx60Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
RemovedInNextVersionWarning = RemovedInSphinx40Warning
|
||||
RemovedInNextVersionWarning = RemovedInSphinx50Warning
|
||||
|
||||
|
||||
def deprecated_alias(modname: str, objects: Dict[str, object],
|
||||
warning: "Type[Warning]", names: Dict[str, str] = None) -> None:
|
||||
warning: Type[Warning], names: Dict[str, str] = {}) -> None:
|
||||
module = import_module(modname)
|
||||
sys.modules[modname] = _ModuleWrapper( # type: ignore
|
||||
module, modname, objects, warning, names)
|
||||
@ -43,7 +39,7 @@ def deprecated_alias(modname: str, objects: Dict[str, object],
|
||||
class _ModuleWrapper:
|
||||
def __init__(self, module: Any, modname: str,
|
||||
objects: Dict[str, object],
|
||||
warning: "Type[Warning]",
|
||||
warning: Type[Warning],
|
||||
names: Dict[str, str]) -> None:
|
||||
self._module = module
|
||||
self._modname = modname
|
||||
@ -71,7 +67,7 @@ class _ModuleWrapper:
|
||||
class DeprecatedDict(dict):
|
||||
"""A deprecated dict which warns on each access."""
|
||||
|
||||
def __init__(self, data: Dict, message: str, warning: "Type[Warning]") -> None:
|
||||
def __init__(self, data: Dict, message: str, warning: Type[Warning]) -> None:
|
||||
self.message = message
|
||||
self.warning = warning
|
||||
super().__init__(data)
|
||||
|
@ -9,7 +9,7 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Any, Dict, Generic, List, Tuple, TypeVar, cast
|
||||
from typing import TYPE_CHECKING, Any, Dict, Generic, List, Tuple, TypeVar, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
@ -17,15 +17,13 @@ from docutils.parsers.rst import directives, roles
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.addnodes import desc_signature
|
||||
from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,
|
||||
deprecated_alias)
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning, deprecated_alias
|
||||
from sphinx.util import docutils
|
||||
from sphinx.util.docfields import DocFieldTransformer, Field, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.typing import DirectiveOption
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -60,18 +58,18 @@ class ObjectDescription(SphinxDirective, Generic[T]):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'noindex': directives.flag,
|
||||
} # type: Dict[str, DirectiveOption]
|
||||
}
|
||||
|
||||
# types of doc fields that this directive handles, see sphinx.util.docfields
|
||||
doc_field_types = [] # type: List[Field]
|
||||
domain = None # type: str
|
||||
objtype = None # type: str
|
||||
indexnode = None # type: addnodes.index
|
||||
doc_field_types: List[Field] = []
|
||||
domain: str = None
|
||||
objtype: str = None
|
||||
indexnode: addnodes.index = None
|
||||
|
||||
# Warning: this might be removed in future version. Don't touch this from extensions.
|
||||
_doc_field_type_map = {} # type: Dict[str, Tuple[Field, bool]]
|
||||
_doc_field_type_map: Dict[str, Tuple[Field, bool]] = {}
|
||||
|
||||
def get_field_type_map(self) -> Dict[str, Tuple[Field, bool]]:
|
||||
if self._doc_field_type_map == {}:
|
||||
@ -175,7 +173,7 @@ class ObjectDescription(SphinxDirective, Generic[T]):
|
||||
if self.domain:
|
||||
node['classes'].append(self.domain)
|
||||
|
||||
self.names = [] # type: List[T]
|
||||
self.names: List[T] = []
|
||||
signatures = self.get_signatures()
|
||||
for i, sig in enumerate(signatures):
|
||||
# add a signature node for each signature in the current unit
|
||||
@ -253,7 +251,7 @@ class DefaultDomain(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
domain_name = self.arguments[0].lower()
|
||||
@ -266,52 +264,6 @@ class DefaultDomain(SphinxDirective):
|
||||
self.env.temp_data['default_domain'] = self.env.domains.get(domain_name)
|
||||
return []
|
||||
|
||||
from sphinx.directives.code import CodeBlock, Highlight, LiteralInclude # noqa
|
||||
from sphinx.directives.other import (Acks, Author, Centered, Class, HList, Include, # noqa
|
||||
Only, SeeAlso, TabularColumns, TocTree, VersionChange)
|
||||
from sphinx.directives.patches import Figure, Meta # noqa
|
||||
from sphinx.domains.index import IndexDirective # noqa
|
||||
|
||||
deprecated_alias('sphinx.directives',
|
||||
{
|
||||
'Highlight': Highlight,
|
||||
'CodeBlock': CodeBlock,
|
||||
'LiteralInclude': LiteralInclude,
|
||||
'TocTree': TocTree,
|
||||
'Author': Author,
|
||||
'Index': IndexDirective,
|
||||
'VersionChange': VersionChange,
|
||||
'SeeAlso': SeeAlso,
|
||||
'TabularColumns': TabularColumns,
|
||||
'Centered': Centered,
|
||||
'Acks': Acks,
|
||||
'HList': HList,
|
||||
'Only': Only,
|
||||
'Include': Include,
|
||||
'Class': Class,
|
||||
'Figure': Figure,
|
||||
'Meta': Meta,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'Highlight': 'sphinx.directives.code.Highlight',
|
||||
'CodeBlock': 'sphinx.directives.code.CodeBlock',
|
||||
'LiteralInclude': 'sphinx.directives.code.LiteralInclude',
|
||||
'TocTree': 'sphinx.directives.other.TocTree',
|
||||
'Author': 'sphinx.directives.other.Author',
|
||||
'Index': 'sphinx.directives.other.IndexDirective',
|
||||
'VersionChange': 'sphinx.directives.other.VersionChange',
|
||||
'SeeAlso': 'sphinx.directives.other.SeeAlso',
|
||||
'TabularColumns': 'sphinx.directives.other.TabularColumns',
|
||||
'Centered': 'sphinx.directives.other.Centered',
|
||||
'Acks': 'sphinx.directives.other.Acks',
|
||||
'HList': 'sphinx.directives.other.HList',
|
||||
'Only': 'sphinx.directives.other.Only',
|
||||
'Include': 'sphinx.directives.other.Include',
|
||||
'Class': 'sphinx.directives.other.Class',
|
||||
'Figure': 'sphinx.directives.patches.Figure',
|
||||
'Meta': 'sphinx.directives.patches.Meta',
|
||||
})
|
||||
|
||||
deprecated_alias('sphinx.directives',
|
||||
{
|
||||
|
@ -8,9 +8,8 @@
|
||||
|
||||
import sys
|
||||
import textwrap
|
||||
import warnings
|
||||
from difflib import unified_diff
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
@ -19,14 +18,13 @@ from docutils.statemachine import StringList
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.directives import optional_int
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging, parselinenos
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -42,7 +40,7 @@ class Highlight(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'force': directives.flag,
|
||||
'linenothreshold': directives.positive_int,
|
||||
}
|
||||
@ -58,16 +56,6 @@ class Highlight(SphinxDirective):
|
||||
linenothreshold=linenothreshold)]
|
||||
|
||||
|
||||
class HighlightLang(Highlight):
|
||||
"""highlightlang directive (deprecated)"""
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
warnings.warn('highlightlang directive is deprecated. '
|
||||
'Please use highlight directive instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return super().run()
|
||||
|
||||
|
||||
def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:
|
||||
if not dedent:
|
||||
return textwrap.dedent(''.join(lines)).splitlines(True)
|
||||
@ -116,7 +104,7 @@ class CodeBlock(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'force': directives.flag,
|
||||
'linenos': directives.flag,
|
||||
'dedent': optional_int,
|
||||
@ -154,7 +142,7 @@ class CodeBlock(SphinxDirective):
|
||||
lines = dedent_lines(lines, self.options['dedent'], location=location)
|
||||
code = '\n'.join(lines)
|
||||
|
||||
literal = nodes.literal_block(code, code) # type: Element
|
||||
literal: Element = nodes.literal_block(code, code)
|
||||
if 'linenos' in self.options or 'lineno-start' in self.options:
|
||||
literal['linenos'] = True
|
||||
literal['classes'] += self.options.get('class', [])
|
||||
@ -392,7 +380,7 @@ class LiteralInclude(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'dedent': optional_int,
|
||||
'linenos': directives.flag,
|
||||
'lineno-start': int,
|
||||
@ -434,7 +422,7 @@ class LiteralInclude(SphinxDirective):
|
||||
reader = LiteralIncludeReader(filename, self.options, self.config)
|
||||
text, lines = reader.read(location=location)
|
||||
|
||||
retnode = nodes.literal_block(text, text, source=filename) # type: Element
|
||||
retnode: Element = nodes.literal_block(text, text, source=filename)
|
||||
retnode['force'] = 'force' in self.options
|
||||
self.set_source_info(retnode)
|
||||
if self.options.get('diff'): # if diff is set, set udiff
|
||||
@ -470,7 +458,6 @@ class LiteralInclude(SphinxDirective):
|
||||
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
directives.register_directive('highlight', Highlight)
|
||||
directives.register_directive('highlightlang', HighlightLang)
|
||||
directives.register_directive('code-block', CodeBlock)
|
||||
directives.register_directive('sourcecode', CodeBlock)
|
||||
directives.register_directive('literalinclude', LiteralInclude)
|
||||
|
@ -7,7 +7,7 @@
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Any, Dict, List, cast
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
@ -17,16 +17,15 @@ from docutils.parsers.rst.directives.misc import Class
|
||||
from docutils.parsers.rst.directives.misc import Include as BaseInclude
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.domains.changeset import VersionChange # NOQA # for compatibility
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import docname_join, url_re
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.matching import Matcher, patfilter
|
||||
from sphinx.util.nodes import explicit_title_re
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -91,7 +90,7 @@ class TocTree(SphinxDirective):
|
||||
all_docnames = self.env.found_docs.copy()
|
||||
all_docnames.remove(self.env.docname) # remove current document
|
||||
|
||||
ret = [] # type: List[Node]
|
||||
ret: List[Node] = []
|
||||
excluded = Matcher(self.config.exclude_patterns)
|
||||
for entry in self.content:
|
||||
if not entry:
|
||||
@ -137,7 +136,13 @@ class TocTree(SphinxDirective):
|
||||
line=self.lineno))
|
||||
self.env.note_reread()
|
||||
else:
|
||||
all_docnames.discard(docname)
|
||||
if docname in all_docnames:
|
||||
all_docnames.remove(docname)
|
||||
else:
|
||||
message = 'duplicated entry found in toctree: %s'
|
||||
ret.append(self.state.document.reporter.warning(message % docname,
|
||||
line=self.lineno))
|
||||
|
||||
toctree['entries'].append((title, docname))
|
||||
toctree['includefiles'].append(docname)
|
||||
|
||||
@ -158,12 +163,12 @@ class Author(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
if not self.config.show_authors:
|
||||
return []
|
||||
para = nodes.paragraph(translatable=False) # type: Element
|
||||
para: Element = nodes.paragraph(translatable=False)
|
||||
emph = nodes.emphasis()
|
||||
para += emph
|
||||
if self.name == 'sectionauthor':
|
||||
@ -178,7 +183,7 @@ class Author(SphinxDirective):
|
||||
inodes, messages = self.state.inline_text(self.arguments[0], self.lineno)
|
||||
emph.extend(inodes)
|
||||
|
||||
ret = [para] # type: List[Node]
|
||||
ret: List[Node] = [para]
|
||||
ret += messages
|
||||
return ret
|
||||
|
||||
@ -198,7 +203,7 @@ class TabularColumns(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
node = addnodes.tabular_col_spec()
|
||||
@ -215,16 +220,16 @@ class Centered(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
if not self.arguments:
|
||||
return []
|
||||
subnode = addnodes.centered() # type: Element
|
||||
subnode: Element = addnodes.centered()
|
||||
inodes, messages = self.state.inline_text(self.arguments[0], self.lineno)
|
||||
subnode.extend(inodes)
|
||||
|
||||
ret = [subnode] # type: List[Node]
|
||||
ret: List[Node] = [subnode]
|
||||
ret += messages
|
||||
return ret
|
||||
|
||||
@ -237,7 +242,7 @@ class Acks(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
node = addnodes.acks()
|
||||
@ -258,7 +263,7 @@ class HList(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'columns': int,
|
||||
}
|
||||
|
||||
@ -294,7 +299,7 @@ class Only(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
node = addnodes.only()
|
||||
@ -304,7 +309,7 @@ class Only(SphinxDirective):
|
||||
|
||||
# Same as util.nested_parse_with_titles but try to handle nested
|
||||
# sections which should be raised higher up the doctree.
|
||||
memo = self.state.memo # type: Any
|
||||
memo: Any = self.state.memo
|
||||
surrounding_title_styles = memo.title_styles
|
||||
surrounding_section_level = memo.section_level
|
||||
memo.title_styles = []
|
||||
@ -361,19 +366,6 @@ class Include(BaseInclude, SphinxDirective):
|
||||
return super().run()
|
||||
|
||||
|
||||
# Import old modules here for compatibility
|
||||
from sphinx.domains.index import IndexDirective # NOQA
|
||||
|
||||
deprecated_alias('sphinx.directives.other',
|
||||
{
|
||||
'Index': IndexDirective,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'Index': 'sphinx.domains.index.IndexDirective',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
directives.register_directive('toctree', TocTree)
|
||||
directives.register_directive('sectionauthor', Author)
|
||||
|
@ -6,7 +6,10 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Tuple, cast
|
||||
import os
|
||||
import warnings
|
||||
from os import path
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Tuple, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node, make_id, system_message
|
||||
@ -14,16 +17,23 @@ from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.directives import html, images, tables
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.deprecation import RemovedInSphinx60Warning
|
||||
from sphinx.directives import optional_int
|
||||
from sphinx.domains.math import MathDomain
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import set_source_info
|
||||
from sphinx.util.osutil import SEP, os_path, relpath
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Figure(images.Figure):
|
||||
"""The figure directive which applies `:name:` option to the figure node
|
||||
instead of the image node.
|
||||
@ -72,6 +82,11 @@ class RSTTable(tables.RSTTable):
|
||||
|
||||
Only for docutils-0.13 or older version."""
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
warnings.warn('RSTTable is deprecated.',
|
||||
RemovedInSphinx60Warning)
|
||||
return super().run()
|
||||
|
||||
def make_title(self) -> Tuple[nodes.title, List[system_message]]:
|
||||
title, message = super().make_title()
|
||||
if title:
|
||||
@ -81,16 +96,25 @@ class RSTTable(tables.RSTTable):
|
||||
|
||||
|
||||
class CSVTable(tables.CSVTable):
|
||||
"""The csv-table directive which sets source and line information to its caption.
|
||||
"""The csv-table directive which searches a CSV file from Sphinx project's source
|
||||
directory when an absolute path is given via :file: option.
|
||||
"""
|
||||
|
||||
Only for docutils-0.13 or older version."""
|
||||
def run(self) -> List[Node]:
|
||||
if 'file' in self.options and self.options['file'].startswith((SEP, os.sep)):
|
||||
env = self.state.document.settings.env
|
||||
filename = self.options['file']
|
||||
if path.exists(filename):
|
||||
logger.warning(__('":file:" option for csv-table directive now recognizes '
|
||||
'an absolute path as a relative path from source directory. '
|
||||
'Please update your document.'),
|
||||
location=(env.docname, self.lineno))
|
||||
else:
|
||||
abspath = path.join(env.srcdir, os_path(self.options['file'][1:]))
|
||||
docdir = path.dirname(env.doc2path(env.docname))
|
||||
self.options['file'] = relpath(abspath, docdir)
|
||||
|
||||
def make_title(self) -> Tuple[nodes.title, List[system_message]]:
|
||||
title, message = super().make_title()
|
||||
if title:
|
||||
set_source_info(self, title)
|
||||
|
||||
return title, message
|
||||
return super().run()
|
||||
|
||||
|
||||
class ListTable(tables.ListTable):
|
||||
@ -98,6 +122,11 @@ class ListTable(tables.ListTable):
|
||||
|
||||
Only for docutils-0.13 or older version."""
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
warnings.warn('ListTable is deprecated.',
|
||||
RemovedInSphinx60Warning)
|
||||
return super().run()
|
||||
|
||||
def make_title(self) -> Tuple[nodes.title, List[system_message]]:
|
||||
title, message = super().make_title()
|
||||
if title:
|
||||
@ -112,7 +141,7 @@ class Code(SphinxDirective):
|
||||
This is compatible with docutils' :rst:dir:`code` directive.
|
||||
"""
|
||||
optional_arguments = 1
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'class': directives.class_option,
|
||||
'force': directives.flag,
|
||||
'name': directives.unchanged,
|
||||
@ -156,7 +185,7 @@ class MathDirective(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'label': directives.unchanged,
|
||||
'name': directives.unchanged,
|
||||
'class': directives.class_option,
|
||||
@ -177,7 +206,7 @@ class MathDirective(SphinxDirective):
|
||||
self.add_name(node)
|
||||
self.set_source_info(node)
|
||||
|
||||
ret = [node] # type: List[Node]
|
||||
ret: List[Node] = [node]
|
||||
self.add_target(ret)
|
||||
return ret
|
||||
|
||||
@ -208,9 +237,7 @@ class MathDirective(SphinxDirective):
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
directives.register_directive('figure', Figure)
|
||||
directives.register_directive('meta', Meta)
|
||||
directives.register_directive('table', RSTTable)
|
||||
directives.register_directive('csv-table', CSVTable)
|
||||
directives.register_directive('list-table', ListTable)
|
||||
directives.register_directive('code', Code)
|
||||
directives.register_directive('math', MathDirective)
|
||||
|
||||
|
@ -10,7 +10,9 @@
|
||||
"""
|
||||
|
||||
import copy
|
||||
from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Union, cast
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, NamedTuple, Tuple,
|
||||
Type, Union, cast)
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, system_message
|
||||
@ -22,10 +24,7 @@ from sphinx.locale import _
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.util.typing import RoleFunction
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
@ -51,21 +50,22 @@ class ObjType:
|
||||
|
||||
def __init__(self, lname: str, *roles: Any, **attrs: Any) -> None:
|
||||
self.lname = lname
|
||||
self.roles = roles # type: Tuple
|
||||
self.attrs = self.known_attrs.copy() # type: Dict
|
||||
self.roles: Tuple = roles
|
||||
self.attrs: Dict = self.known_attrs.copy()
|
||||
self.attrs.update(attrs)
|
||||
|
||||
|
||||
IndexEntry = NamedTuple('IndexEntry', [('name', str),
|
||||
('subtype', int),
|
||||
('docname', str),
|
||||
('anchor', str),
|
||||
('extra', str),
|
||||
('qualifier', str),
|
||||
('descr', str)])
|
||||
class IndexEntry(NamedTuple):
|
||||
name: str
|
||||
subtype: int
|
||||
docname: str
|
||||
anchor: str
|
||||
extra: str
|
||||
qualifier: str
|
||||
descr: str
|
||||
|
||||
|
||||
class Index:
|
||||
class Index(ABC):
|
||||
"""
|
||||
An Index is the description for a domain-specific index. To add an index to
|
||||
a domain, subclass Index, overriding the three name attributes:
|
||||
@ -88,9 +88,9 @@ class Index:
|
||||
:rst:role:`ref` role.
|
||||
"""
|
||||
|
||||
name = None # type: str
|
||||
localname = None # type: str
|
||||
shortname = None # type: str
|
||||
name: str = None
|
||||
localname: str = None
|
||||
shortname: str = None
|
||||
|
||||
def __init__(self, domain: "Domain") -> None:
|
||||
if self.name is None or self.localname is None:
|
||||
@ -98,6 +98,7 @@ class Index:
|
||||
% self.__class__.__name__)
|
||||
self.domain = domain
|
||||
|
||||
@abstractmethod
|
||||
def generate(self, docnames: Iterable[str] = None
|
||||
) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]:
|
||||
"""Get entries for the index.
|
||||
@ -180,31 +181,31 @@ class Domain:
|
||||
#: domain label: longer, more descriptive (used in messages)
|
||||
label = ''
|
||||
#: type (usually directive) name -> ObjType instance
|
||||
object_types = {} # type: Dict[str, ObjType]
|
||||
object_types: Dict[str, ObjType] = {}
|
||||
#: directive name -> directive class
|
||||
directives = {} # type: Dict[str, Any]
|
||||
directives: Dict[str, Any] = {}
|
||||
#: role name -> role callable
|
||||
roles = {} # type: Dict[str, Union[RoleFunction, XRefRole]]
|
||||
roles: Dict[str, Union[RoleFunction, XRefRole]] = {}
|
||||
#: a list of Index subclasses
|
||||
indices = [] # type: List[Type[Index]]
|
||||
indices: List[Type[Index]] = []
|
||||
#: role name -> a warning message if reference is missing
|
||||
dangling_warnings = {} # type: Dict[str, str]
|
||||
dangling_warnings: Dict[str, str] = {}
|
||||
#: node_class -> (enum_node_type, title_getter)
|
||||
enumerable_nodes = {} # type: Dict[Type[Node], Tuple[str, Callable]]
|
||||
enumerable_nodes: Dict[Type[Node], Tuple[str, Callable]] = {}
|
||||
|
||||
#: data value for a fresh environment
|
||||
initial_data = {} # type: Dict
|
||||
initial_data: Dict = {}
|
||||
#: data value
|
||||
data = None # type: Dict
|
||||
data: Dict = None
|
||||
#: data version, bump this when the format of `self.data` changes
|
||||
data_version = 0
|
||||
|
||||
def __init__(self, env: "BuildEnvironment") -> None:
|
||||
self.env = env # type: BuildEnvironment
|
||||
self._role_cache = {} # type: Dict[str, Callable]
|
||||
self._directive_cache = {} # type: Dict[str, Callable]
|
||||
self._role2type = {} # type: Dict[str, List[str]]
|
||||
self._type2role = {} # type: Dict[str, str]
|
||||
self.env: BuildEnvironment = env
|
||||
self._role_cache: Dict[str, Callable] = {}
|
||||
self._directive_cache: Dict[str, Callable] = {}
|
||||
self._role2type: Dict[str, List[str]] = {}
|
||||
self._type2role: Dict[str, str] = {}
|
||||
|
||||
# convert class variables to instance one (to enhance through API)
|
||||
self.object_types = dict(self.object_types)
|
||||
@ -225,8 +226,8 @@ class Domain:
|
||||
for rolename in obj.roles:
|
||||
self._role2type.setdefault(rolename, []).append(name)
|
||||
self._type2role[name] = obj.roles[0] if obj.roles else ''
|
||||
self.objtypes_for_role = self._role2type.get # type: Callable[[str], List[str]]
|
||||
self.role_for_objtype = self._type2role.get # type: Callable[[str], str]
|
||||
self.objtypes_for_role: Callable[[str], List[str]] = self._role2type.get
|
||||
self.role_for_objtype: Callable[[str], str] = self._type2role.get
|
||||
|
||||
def setup(self) -> None:
|
||||
"""Set up domain object."""
|
||||
|
@ -39,6 +39,7 @@ from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList
|
||||
from sphinx.util.docfields import Field, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
T = TypeVar('T')
|
||||
@ -182,10 +183,19 @@ class ASTNestedName(ASTBase):
|
||||
verify_description_mode(mode)
|
||||
# just print the name part, with template args, not template params
|
||||
if mode == 'noneIsName':
|
||||
signode += nodes.Text(str(self))
|
||||
if self.rooted:
|
||||
signode += nodes.Text('.')
|
||||
for i in range(len(self.names)):
|
||||
if i != 0:
|
||||
signode += nodes.Text('.')
|
||||
n = self.names[i]
|
||||
n.describe_signature(signode, mode, env, '', symbol)
|
||||
elif mode == 'param':
|
||||
name = str(self)
|
||||
signode += nodes.emphasis(name, name)
|
||||
assert not self.rooted, str(self)
|
||||
assert len(self.names) == 1
|
||||
node = nodes.emphasis()
|
||||
self.names[0].describe_signature(node, 'noneIsName', env, '', symbol)
|
||||
signode += node
|
||||
elif mode == 'markType' or mode == 'lastIsName' or mode == 'markName':
|
||||
# Each element should be a pending xref targeting the complete
|
||||
# prefix.
|
||||
@ -387,19 +397,6 @@ class ASTPostfixDec(ASTPostfixOp):
|
||||
signode.append(nodes.Text('--'))
|
||||
|
||||
|
||||
class ASTPostfixMember(ASTPostfixOp):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return '.' + transform(self.name)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('.'))
|
||||
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
||||
|
||||
|
||||
class ASTPostfixMemberOfPointer(ASTPostfixOp):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
@ -682,15 +679,24 @@ class ASTParameters(ASTBase):
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
verify_description_mode(mode)
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
for arg in self.args:
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
if mode == 'lastIsName': # i.e., outer-function params
|
||||
# only use the desc_parameterlist for the outer list, not for inner lists
|
||||
if mode == 'lastIsName':
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
for arg in self.args:
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
arg.describe_signature(param, 'param', env, symbol=symbol)
|
||||
else:
|
||||
arg.describe_signature(param, 'markType', env, symbol=symbol)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
else:
|
||||
signode += nodes.Text('(', '(')
|
||||
first = True
|
||||
for arg in self.args:
|
||||
if not first:
|
||||
signode += nodes.Text(', ', ', ')
|
||||
first = False
|
||||
arg.describe_signature(signode, 'markType', env, symbol=symbol)
|
||||
signode += nodes.Text(')', ')')
|
||||
|
||||
for attr in self.attrs:
|
||||
signode += nodes.Text(' ')
|
||||
attr.describe_signature(signode)
|
||||
@ -719,7 +725,7 @@ class ASTDeclSpecsSimple(ASTBaseBase):
|
||||
self.attrs + other.attrs)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = [] # type: List[str]
|
||||
res: List[str] = []
|
||||
res.extend(transform(attr) for attr in self.attrs)
|
||||
if self.storage:
|
||||
res.append(self.storage)
|
||||
@ -773,7 +779,7 @@ class ASTDeclSpecs(ASTBase):
|
||||
self.trailingTypeSpec = trailing
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = [] # type: List[str]
|
||||
res: List[str] = []
|
||||
l = transform(self.leftSpecs)
|
||||
if len(l) > 0:
|
||||
res.append(l)
|
||||
@ -791,7 +797,7 @@ class ASTDeclSpecs(ASTBase):
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
verify_description_mode(mode)
|
||||
modifiers = [] # type: List[Node]
|
||||
modifiers: List[Node] = []
|
||||
|
||||
def _add(modifiers: List[Node], text: str) -> None:
|
||||
if len(modifiers) > 0:
|
||||
@ -873,7 +879,7 @@ class ASTArray(ASTBase):
|
||||
elif self.size:
|
||||
if addSpace:
|
||||
signode += nodes.Text(' ')
|
||||
self.size.describe_signature(signode, mode, env, symbol)
|
||||
self.size.describe_signature(signode, 'markType', env, symbol)
|
||||
signode.append(nodes.Text("]"))
|
||||
|
||||
|
||||
@ -1363,9 +1369,9 @@ class ASTDeclaration(ASTBaseBase):
|
||||
self.declaration = declaration
|
||||
self.semicolon = semicolon
|
||||
|
||||
self.symbol = None # type: Symbol
|
||||
self.symbol: Symbol = None
|
||||
# set by CObject._add_enumerator_to_parent
|
||||
self.enumeratorScopedSymbol = None # type: Symbol
|
||||
self.enumeratorScopedSymbol: Symbol = None
|
||||
|
||||
def clone(self) -> "ASTDeclaration":
|
||||
return ASTDeclaration(self.objectType, self.directiveType,
|
||||
@ -1497,8 +1503,8 @@ class Symbol:
|
||||
declaration: ASTDeclaration, docname: str, line: int) -> None:
|
||||
self.parent = parent
|
||||
# declarations in a single directive are linked together
|
||||
self.siblingAbove = None # type: Symbol
|
||||
self.siblingBelow = None # type: Symbol
|
||||
self.siblingAbove: Symbol = None
|
||||
self.siblingBelow: Symbol = None
|
||||
self.ident = ident
|
||||
self.declaration = declaration
|
||||
self.docname = docname
|
||||
@ -1507,8 +1513,8 @@ class Symbol:
|
||||
self._assert_invariants()
|
||||
|
||||
# Remember to modify Symbol.remove if modifications to the parent change.
|
||||
self._children = [] # type: List[Symbol]
|
||||
self._anonChildren = [] # type: List[Symbol]
|
||||
self._children: List[Symbol] = []
|
||||
self._anonChildren: List[Symbol] = []
|
||||
# note: _children includes _anonChildren
|
||||
if self.parent:
|
||||
self.parent._children.append(self)
|
||||
@ -2189,7 +2195,7 @@ class DefinitionParser(BaseParser):
|
||||
# "(" expression ")"
|
||||
# id-expression -> we parse this with _parse_nested_name
|
||||
self.skip_ws()
|
||||
res = self._parse_literal() # type: ASTExpression
|
||||
res: ASTExpression = self._parse_literal()
|
||||
if res is not None:
|
||||
return res
|
||||
res = self._parse_paren_expression()
|
||||
@ -2256,7 +2262,7 @@ class DefinitionParser(BaseParser):
|
||||
# | postfix "[" expression "]"
|
||||
# | postfix "[" braced-init-list [opt] "]"
|
||||
# | postfix "(" expression-list [opt] ")"
|
||||
# | postfix "." id-expression
|
||||
# | postfix "." id-expression // taken care of in primary by nested name
|
||||
# | postfix "->" id-expression
|
||||
# | postfix "++"
|
||||
# | postfix "--"
|
||||
@ -2264,7 +2270,7 @@ class DefinitionParser(BaseParser):
|
||||
prefix = self._parse_primary_expression()
|
||||
|
||||
# and now parse postfixes
|
||||
postFixes = [] # type: List[ASTPostfixOp]
|
||||
postFixes: List[ASTPostfixOp] = []
|
||||
while True:
|
||||
self.skip_ws()
|
||||
if self.skip_string_and_ws('['):
|
||||
@ -2274,17 +2280,6 @@ class DefinitionParser(BaseParser):
|
||||
self.fail("Expected ']' in end of postfix expression.")
|
||||
postFixes.append(ASTPostfixArray(expr))
|
||||
continue
|
||||
if self.skip_string('.'):
|
||||
if self.skip_string('*'):
|
||||
# don't steal the dot
|
||||
self.pos -= 2
|
||||
elif self.skip_string('..'):
|
||||
# don't steal the dot
|
||||
self.pos -= 3
|
||||
else:
|
||||
name = self._parse_nested_name()
|
||||
postFixes.append(ASTPostfixMember(name))
|
||||
continue
|
||||
if self.skip_string('->'):
|
||||
if self.skip_string('*'):
|
||||
# don't steal the arrow
|
||||
@ -2493,7 +2488,7 @@ class DefinitionParser(BaseParser):
|
||||
else:
|
||||
# TODO: add handling of more bracket-like things, and quote handling
|
||||
brackets = {'(': ')', '{': '}', '[': ']'}
|
||||
symbols = [] # type: List[str]
|
||||
symbols: List[str] = []
|
||||
while not self.eof:
|
||||
if (len(symbols) == 0 and self.current_char in end):
|
||||
break
|
||||
@ -2509,7 +2504,7 @@ class DefinitionParser(BaseParser):
|
||||
return ASTFallbackExpr(value.strip())
|
||||
|
||||
def _parse_nested_name(self) -> ASTNestedName:
|
||||
names = [] # type: List[Any]
|
||||
names: List[Any] = []
|
||||
|
||||
self.skip_ws()
|
||||
rooted = False
|
||||
@ -2693,16 +2688,13 @@ class DefinitionParser(BaseParser):
|
||||
def _parse_declarator_name_suffix(
|
||||
self, named: Union[bool, str], paramMode: str, typed: bool
|
||||
) -> ASTDeclarator:
|
||||
assert named in (True, False, 'single')
|
||||
# now we should parse the name, and then suffixes
|
||||
if named == 'maybe':
|
||||
pos = self.pos
|
||||
try:
|
||||
declId = self._parse_nested_name()
|
||||
except DefinitionError:
|
||||
self.pos = pos
|
||||
declId = None
|
||||
elif named == 'single':
|
||||
if named == 'single':
|
||||
if self.match(identifier_re):
|
||||
if self.matched_text in _keywords:
|
||||
self.fail("Expected identifier, "
|
||||
"got keyword: %s" % self.matched_text)
|
||||
identifier = ASTIdentifier(self.matched_text)
|
||||
declId = ASTNestedName([identifier], rooted=False)
|
||||
else:
|
||||
@ -2865,7 +2857,7 @@ class DefinitionParser(BaseParser):
|
||||
return ASTInitializer(bracedInit)
|
||||
|
||||
if outer == 'member':
|
||||
fallbackEnd = [] # type: List[str]
|
||||
fallbackEnd: List[str] = []
|
||||
elif outer is None: # function parameter
|
||||
fallbackEnd = [',', ')']
|
||||
else:
|
||||
@ -2880,8 +2872,8 @@ class DefinitionParser(BaseParser):
|
||||
|
||||
def _parse_type(self, named: Union[bool, str], outer: str = None) -> ASTType:
|
||||
"""
|
||||
named=False|'maybe'|True: 'maybe' is e.g., for function objects which
|
||||
doesn't need to name the arguments
|
||||
named=False|'single'|True: 'single' is e.g., for function objects which
|
||||
doesn't need to name the arguments, but otherwise is a single name
|
||||
"""
|
||||
if outer: # always named
|
||||
if outer not in ('type', 'member', 'function'):
|
||||
@ -3012,7 +3004,7 @@ class DefinitionParser(BaseParser):
|
||||
|
||||
def parse_pre_v3_type_definition(self) -> ASTDeclaration:
|
||||
self.skip_ws()
|
||||
declaration = None # type: DeclarationType
|
||||
declaration: DeclarationType = None
|
||||
if self.skip_word('struct'):
|
||||
typ = 'struct'
|
||||
declaration = self._parse_struct()
|
||||
@ -3035,7 +3027,7 @@ class DefinitionParser(BaseParser):
|
||||
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
|
||||
raise Exception('Internal error, unknown directiveType "%s".' % directiveType)
|
||||
|
||||
declaration = None # type: DeclarationType
|
||||
declaration: DeclarationType = None
|
||||
if objectType == 'member':
|
||||
declaration = self._parse_type_with_init(named=True, outer='member')
|
||||
elif objectType == 'function':
|
||||
@ -3074,7 +3066,7 @@ class DefinitionParser(BaseParser):
|
||||
|
||||
def parse_expression(self) -> Union[ASTExpression, ASTType]:
|
||||
pos = self.pos
|
||||
res = None # type: Union[ASTExpression, ASTType]
|
||||
res: Union[ASTExpression, ASTType] = None
|
||||
try:
|
||||
res = self._parse_expression()
|
||||
self.skip_ws()
|
||||
@ -3113,7 +3105,7 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
names=('rtype',)),
|
||||
]
|
||||
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'noindexentry': directives.flag,
|
||||
}
|
||||
|
||||
@ -3221,7 +3213,7 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
return super().run()
|
||||
|
||||
def handle_signature(self, sig: str, signode: TextElement) -> ASTDeclaration:
|
||||
parentSymbol = self.env.temp_data['c:parent_symbol'] # type: Symbol
|
||||
parentSymbol: Symbol = self.env.temp_data['c:parent_symbol']
|
||||
|
||||
parser = DefinitionParser(sig, location=signode, config=self.env.config)
|
||||
try:
|
||||
@ -3285,10 +3277,10 @@ class CObject(ObjectDescription[ASTDeclaration]):
|
||||
return ast
|
||||
|
||||
def before_content(self) -> None:
|
||||
lastSymbol = self.env.temp_data['c:last_symbol'] # type: Symbol
|
||||
lastSymbol: Symbol = self.env.temp_data['c:last_symbol']
|
||||
assert lastSymbol
|
||||
self.oldParentSymbol = self.env.temp_data['c:parent_symbol']
|
||||
self.oldParentKey = self.env.ref_context['c:parent_key'] # type: LookupKey
|
||||
self.oldParentKey: LookupKey = self.env.ref_context['c:parent_key']
|
||||
self.env.temp_data['c:parent_symbol'] = lastSymbol
|
||||
self.env.ref_context['c:parent_key'] = lastSymbol.get_lookup_key()
|
||||
|
||||
@ -3353,13 +3345,13 @@ class CNamespaceObject(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
rootSymbol = self.env.domaindata['c']['root_symbol']
|
||||
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
|
||||
symbol = rootSymbol
|
||||
stack = [] # type: List[Symbol]
|
||||
stack: List[Symbol] = []
|
||||
else:
|
||||
parser = DefinitionParser(self.arguments[0],
|
||||
location=self.get_source_info(),
|
||||
@ -3383,7 +3375,7 @@ class CNamespacePushObject(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
|
||||
@ -3414,7 +3406,7 @@ class CNamespacePopObject(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
stack = self.env.temp_data.get('c:namespace_stack', None)
|
||||
@ -3470,7 +3462,7 @@ class AliasTransform(SphinxTransform):
|
||||
maxdepth -= 1
|
||||
recurse = True
|
||||
|
||||
nodes = [] # type: List[Node]
|
||||
nodes: List[Node] = []
|
||||
if not skipThis:
|
||||
signode = addnodes.desc_signature('', '')
|
||||
nodes.append(signode)
|
||||
@ -3478,7 +3470,7 @@ class AliasTransform(SphinxTransform):
|
||||
|
||||
if recurse:
|
||||
if skipThis:
|
||||
childContainer = nodes # type: Union[List[Node], addnodes.desc]
|
||||
childContainer: Union[List[Node], addnodes.desc] = nodes
|
||||
else:
|
||||
content = addnodes.desc_content()
|
||||
desc = addnodes.desc()
|
||||
@ -3524,8 +3516,8 @@ class AliasTransform(SphinxTransform):
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
|
||||
rootSymbol = self.env.domains['c'].data['root_symbol'] # type: Symbol
|
||||
parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
|
||||
rootSymbol: Symbol = self.env.domains['c'].data['root_symbol']
|
||||
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
||||
if not parentSymbol:
|
||||
print("Target: ", sig)
|
||||
print("ParentKey: ", parentKey)
|
||||
@ -3568,10 +3560,10 @@ class AliasTransform(SphinxTransform):
|
||||
|
||||
|
||||
class CAliasObject(ObjectDescription):
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'maxdepth': directives.nonnegative_int,
|
||||
'noroot': directives.flag,
|
||||
} # type: Dict
|
||||
}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
"""
|
||||
@ -3591,7 +3583,7 @@ class CAliasObject(ObjectDescription):
|
||||
node['objtype'] = node['desctype'] = self.objtype
|
||||
node['noindex'] = True
|
||||
|
||||
self.names = [] # type: List[str]
|
||||
self.names: List[str] = []
|
||||
aliasOptions = {
|
||||
'maxdepth': self.options.get('maxdepth', 1),
|
||||
'noroot': 'noroot' in self.options,
|
||||
@ -3669,7 +3661,7 @@ class CExprRole(SphinxRole):
|
||||
if asCode:
|
||||
# render the expression as inline code
|
||||
self.class_type = 'c-expr'
|
||||
self.node_type = nodes.literal # type: Type[TextElement]
|
||||
self.node_type: Type[TextElement] = nodes.literal
|
||||
else:
|
||||
# render the expression as inline text
|
||||
self.class_type = 'c-texpr'
|
||||
@ -3748,10 +3740,10 @@ class CDomain(Domain):
|
||||
'expr': CExprRole(asCode=True),
|
||||
'texpr': CExprRole(asCode=False)
|
||||
}
|
||||
initial_data = {
|
||||
initial_data: Dict[str, Union[Symbol, Dict[str, Tuple[str, str, str]]]] = {
|
||||
'root_symbol': Symbol(None, None, None, None, None),
|
||||
'objects': {}, # fullname -> docname, node_id, objtype
|
||||
} # type: Dict[str, Union[Symbol, Dict[str, Tuple[str, str, str]]]]
|
||||
}
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
if Symbol.debug_show_tree:
|
||||
@ -3809,10 +3801,10 @@ class CDomain(Domain):
|
||||
logger.warning('Unparseable C cross-reference: %r\n%s', target, e,
|
||||
location=node)
|
||||
return None, None
|
||||
parentKey = node.get("c:parent_key", None) # type: LookupKey
|
||||
parentKey: LookupKey = node.get("c:parent_key", None)
|
||||
rootSymbol = self.data['root_symbol']
|
||||
if parentKey:
|
||||
parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
|
||||
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
||||
if not parentSymbol:
|
||||
print("Target: ", target)
|
||||
print("ParentKey: ", parentKey)
|
||||
|
@ -8,8 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
from typing import Any, Dict, List, cast
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
@ -18,9 +17,9 @@ from sphinx import addnodes
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.locale import _
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
@ -38,9 +37,13 @@ versionlabel_classes = {
|
||||
}
|
||||
|
||||
|
||||
# TODO: move to typing.NamedTuple after dropping py35 support (see #5958)
|
||||
ChangeSet = namedtuple('ChangeSet',
|
||||
['type', 'docname', 'lineno', 'module', 'descname', 'content'])
|
||||
class ChangeSet(NamedTuple):
|
||||
type: str
|
||||
docname: str
|
||||
lineno: int
|
||||
module: str
|
||||
descname: str
|
||||
content: str
|
||||
|
||||
|
||||
class VersionChange(SphinxDirective):
|
||||
@ -51,7 +54,7 @@ class VersionChange(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
node = addnodes.versionmodified()
|
||||
@ -91,7 +94,7 @@ class VersionChange(SphinxDirective):
|
||||
domain = cast(ChangeSetDomain, self.env.get_domain('changeset'))
|
||||
domain.note_changeset(node)
|
||||
|
||||
ret = [node] # type: List[Node]
|
||||
ret: List[Node] = [node]
|
||||
ret += messages
|
||||
return ret
|
||||
|
||||
@ -102,9 +105,9 @@ class ChangeSetDomain(Domain):
|
||||
name = 'changeset'
|
||||
label = 'changeset'
|
||||
|
||||
initial_data = {
|
||||
initial_data: Dict = {
|
||||
'changes': {}, # version -> list of ChangeSet
|
||||
} # type: Dict
|
||||
}
|
||||
|
||||
@property
|
||||
def changesets(self) -> Dict[str, List[ChangeSet]]:
|
||||
|
@ -8,7 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Set, Tuple, cast
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Set, Tuple, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element
|
||||
@ -20,8 +20,7 @@ from sphinx.transforms import SphinxTransform
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.nodes import copy_source_info, make_refnode
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
@ -39,6 +39,7 @@ from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList
|
||||
from sphinx.util.docfields import Field, GroupedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
T = TypeVar('T')
|
||||
@ -179,7 +180,6 @@ T = TypeVar('T')
|
||||
declarator ->
|
||||
ptr-declarator
|
||||
| noptr-declarator parameters-and-qualifiers trailing-return-type
|
||||
(TODO: for now we don't support trailing-eturn-type)
|
||||
ptr-declarator ->
|
||||
noptr-declarator
|
||||
| ptr-operator ptr-declarator
|
||||
@ -306,6 +306,7 @@ _operator_re = re.compile(r'''(?x)
|
||||
| \+\+ | --
|
||||
| ->\*? | \,
|
||||
| (<<|>>)=? | && | \|\|
|
||||
| <=>
|
||||
| [!<>=/*%+|&^~-]=?
|
||||
| (\b(and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|xor|xor_eq)\b)
|
||||
''')
|
||||
@ -494,6 +495,7 @@ _id_operator_v2 = {
|
||||
'>': 'gt',
|
||||
'<=': 'le',
|
||||
'>=': 'ge',
|
||||
'<=>': 'ss',
|
||||
'!': 'nt', 'not': 'nt',
|
||||
'&&': 'aa', 'and': 'aa',
|
||||
'||': 'oo', 'or': 'oo',
|
||||
@ -516,10 +518,10 @@ _id_operator_unary_v2 = {
|
||||
'!': 'nt', 'not': 'nt',
|
||||
'~': 'co', 'compl': 'co'
|
||||
}
|
||||
_id_char_from_prefix = {
|
||||
_id_char_from_prefix: Dict[Optional[str], str] = {
|
||||
None: 'c', 'u8': 'c',
|
||||
'u': 'Ds', 'U': 'Di', 'L': 'w'
|
||||
} # type: Dict[Any, str]
|
||||
}
|
||||
# these are ordered by preceedence
|
||||
_expression_bin_ops = [
|
||||
['||', 'or'],
|
||||
@ -528,7 +530,7 @@ _expression_bin_ops = [
|
||||
['^', 'xor'],
|
||||
['&', 'bitand'],
|
||||
['==', '!=', 'not_eq'],
|
||||
['<=', '>=', '<', '>'],
|
||||
['<=>', '<=', '>=', '<', '>'],
|
||||
['<<', '>>'],
|
||||
['+', '-'],
|
||||
['*', '/', '%'],
|
||||
@ -716,8 +718,7 @@ class ASTNestedName(ASTBase):
|
||||
res.append('')
|
||||
for i in range(len(self.names)):
|
||||
n = self.names[i]
|
||||
t = self.templates[i]
|
||||
if t:
|
||||
if self.templates[i]:
|
||||
res.append("template " + transform(n))
|
||||
else:
|
||||
res.append(transform(n))
|
||||
@ -728,16 +729,29 @@ class ASTNestedName(ASTBase):
|
||||
verify_description_mode(mode)
|
||||
# just print the name part, with template args, not template params
|
||||
if mode == 'noneIsName':
|
||||
signode += nodes.Text(str(self))
|
||||
if self.rooted:
|
||||
signode += nodes.Text('::')
|
||||
for i in range(len(self.names)):
|
||||
if i != 0:
|
||||
signode += nodes.Text('::')
|
||||
n = self.names[i]
|
||||
if self.templates[i]:
|
||||
signode += nodes.Text("template")
|
||||
signode += nodes.Text(" ")
|
||||
n.describe_signature(signode, mode, env, '', symbol)
|
||||
elif mode == 'param':
|
||||
name = str(self)
|
||||
signode += nodes.emphasis(name, name)
|
||||
assert not self.rooted, str(self)
|
||||
assert len(self.names) == 1
|
||||
assert not self.templates[0]
|
||||
node = nodes.emphasis()
|
||||
self.names[0].describe_signature(node, 'noneIsName', env, '', symbol)
|
||||
signode += node
|
||||
elif mode == 'markType' or mode == 'lastIsName' or mode == 'markName':
|
||||
# Each element should be a pending xref targeting the complete
|
||||
# prefix. however, only the identifier part should be a link, such
|
||||
# that template args can be a link as well.
|
||||
# For 'lastIsName' we should also prepend template parameter lists.
|
||||
templateParams = [] # type: List[Any]
|
||||
templateParams: List[Any] = []
|
||||
if mode == 'lastIsName':
|
||||
assert symbol is not None
|
||||
if symbol.declaration.templatePrefix is not None:
|
||||
@ -1248,7 +1262,7 @@ class ASTSizeofParamPack(ASTExpression):
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('sizeof...('))
|
||||
self.identifier.describe_signature(signode, mode, env,
|
||||
self.identifier.describe_signature(signode, 'markType', env,
|
||||
symbol=symbol, prefix="", templateArgs="")
|
||||
signode.append(nodes.Text(')'))
|
||||
|
||||
@ -1965,15 +1979,23 @@ class ASTParametersQualifiers(ASTBase):
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
verify_description_mode(mode)
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
for arg in self.args:
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
if mode == 'lastIsName': # i.e., outer-function params
|
||||
# only use the desc_parameterlist for the outer list, not for inner lists
|
||||
if mode == 'lastIsName':
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
for arg in self.args:
|
||||
param = addnodes.desc_parameter('', '', noemph=True)
|
||||
arg.describe_signature(param, 'param', env, symbol=symbol)
|
||||
else:
|
||||
arg.describe_signature(param, 'markType', env, symbol=symbol)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
else:
|
||||
signode += nodes.Text('(', '(')
|
||||
first = True
|
||||
for arg in self.args:
|
||||
if not first:
|
||||
signode += nodes.Text(', ', ', ')
|
||||
first = False
|
||||
arg.describe_signature(signode, 'markType', env, symbol=symbol)
|
||||
signode += nodes.Text(')', ')')
|
||||
|
||||
def _add_anno(signode: TextElement, text: str) -> None:
|
||||
signode += nodes.Text(' ')
|
||||
@ -2035,7 +2057,7 @@ class ASTDeclSpecsSimple(ASTBase):
|
||||
self.attrs + other.attrs)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = [] # type: List[str]
|
||||
res: List[str] = []
|
||||
res.extend(transform(attr) for attr in self.attrs)
|
||||
if self.storage:
|
||||
res.append(self.storage)
|
||||
@ -2122,7 +2144,7 @@ class ASTDeclSpecs(ASTBase):
|
||||
return ''.join(res)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = [] # type: List[str]
|
||||
res: List[str] = []
|
||||
l = transform(self.leftSpecs)
|
||||
if len(l) > 0:
|
||||
res.append(l)
|
||||
@ -2189,7 +2211,7 @@ class ASTArray(ASTBase):
|
||||
verify_description_mode(mode)
|
||||
signode.append(nodes.Text("["))
|
||||
if self.size:
|
||||
self.size.describe_signature(signode, mode, env, symbol)
|
||||
self.size.describe_signature(signode, 'markType', env, symbol)
|
||||
signode.append(nodes.Text("]"))
|
||||
|
||||
|
||||
@ -2657,7 +2679,7 @@ class ASTDeclaratorMemPtr(ASTDeclarator):
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
verify_description_mode(mode)
|
||||
self.className.describe_signature(signode, mode, env, symbol)
|
||||
self.className.describe_signature(signode, 'markType', env, symbol)
|
||||
signode += nodes.Text('::*')
|
||||
|
||||
def _add_anno(signode: TextElement, text: str) -> None:
|
||||
@ -3613,9 +3635,9 @@ class ASTDeclaration(ASTBase):
|
||||
self.trailingRequiresClause = trailingRequiresClause
|
||||
self.semicolon = semicolon
|
||||
|
||||
self.symbol = None # type: Symbol
|
||||
self.symbol: Symbol = None
|
||||
# set by CPPObject._add_enumerator_to_parent
|
||||
self.enumeratorScopedSymbol = None # type: Symbol
|
||||
self.enumeratorScopedSymbol: Symbol = None
|
||||
|
||||
def clone(self) -> "ASTDeclaration":
|
||||
templatePrefixClone = self.templatePrefix.clone() if self.templatePrefix else None
|
||||
@ -3835,8 +3857,8 @@ class Symbol:
|
||||
docname: str, line: int) -> None:
|
||||
self.parent = parent
|
||||
# declarations in a single directive are linked together
|
||||
self.siblingAbove = None # type: Symbol
|
||||
self.siblingBelow = None # type: Symbol
|
||||
self.siblingAbove: Symbol = None
|
||||
self.siblingBelow: Symbol = None
|
||||
self.identOrOp = identOrOp
|
||||
self.templateParams = templateParams # template<templateParams>
|
||||
self.templateArgs = templateArgs # identifier<templateArgs>
|
||||
@ -3847,8 +3869,8 @@ class Symbol:
|
||||
self._assert_invariants()
|
||||
|
||||
# Remember to modify Symbol.remove if modifications to the parent change.
|
||||
self._children = [] # type: List[Symbol]
|
||||
self._anonChildren = [] # type: List[Symbol]
|
||||
self._children: List[Symbol] = []
|
||||
self._anonChildren: List[Symbol] = []
|
||||
# note: _children includes _anonChildren
|
||||
if self.parent:
|
||||
self.parent._children.append(self)
|
||||
@ -3918,7 +3940,7 @@ class Symbol:
|
||||
self.parent = None
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
newChildren = [] # type: List[Symbol]
|
||||
newChildren: List[Symbol] = []
|
||||
for sChild in self._children:
|
||||
sChild.clear_doc(docname)
|
||||
if sChild.declaration and sChild.docname == docname:
|
||||
@ -4950,7 +4972,7 @@ class DefinitionParser(BaseParser):
|
||||
# fold-expression
|
||||
# id-expression -> we parse this with _parse_nested_name
|
||||
self.skip_ws()
|
||||
res = self._parse_literal() # type: ASTExpression
|
||||
res: ASTExpression = self._parse_literal()
|
||||
if res is not None:
|
||||
return res
|
||||
self.skip_ws()
|
||||
@ -4978,7 +5000,7 @@ class DefinitionParser(BaseParser):
|
||||
if self.skip_string(close):
|
||||
return [], False
|
||||
|
||||
exprs = [] # type: List[Union[ASTExpression, ASTBracedInitList]]
|
||||
exprs: List[Union[ASTExpression, ASTBracedInitList]] = []
|
||||
trailingComma = False
|
||||
while True:
|
||||
self.skip_ws()
|
||||
@ -5057,7 +5079,7 @@ class DefinitionParser(BaseParser):
|
||||
# | "typeid" "(" type-id ")"
|
||||
|
||||
prefixType = None
|
||||
prefix = None # type: Any
|
||||
prefix: Any = None
|
||||
self.skip_ws()
|
||||
|
||||
cast = None
|
||||
@ -5140,7 +5162,7 @@ class DefinitionParser(BaseParser):
|
||||
raise self._make_multi_error(errors, header) from eInner
|
||||
|
||||
# and now parse postfixes
|
||||
postFixes = [] # type: List[ASTPostfixOp]
|
||||
postFixes: List[ASTPostfixOp] = []
|
||||
while True:
|
||||
self.skip_ws()
|
||||
if prefixType in ['expr', 'cast', 'typeid']:
|
||||
@ -5309,7 +5331,7 @@ class DefinitionParser(BaseParser):
|
||||
# exclusive-or = and ^
|
||||
# and = equality &
|
||||
# equality = relational ==, !=
|
||||
# relational = shift <, >, <=, >=
|
||||
# relational = shift <, >, <=, >=, <=>
|
||||
# shift = additive <<, >>
|
||||
# additive = multiplicative +, -
|
||||
# multiplicative = pm *, /, %
|
||||
@ -5370,7 +5392,7 @@ class DefinitionParser(BaseParser):
|
||||
# logical-or-expression
|
||||
# | logical-or-expression "?" expression ":" assignment-expression
|
||||
# | logical-or-expression assignment-operator initializer-clause
|
||||
exprs = [] # type: List[Union[ASTExpression, ASTBracedInitList]]
|
||||
exprs: List[Union[ASTExpression, ASTBracedInitList]] = []
|
||||
ops = []
|
||||
orExpr = self._parse_logical_or_expression(inTemplate=inTemplate)
|
||||
exprs.append(orExpr)
|
||||
@ -5443,7 +5465,7 @@ class DefinitionParser(BaseParser):
|
||||
else:
|
||||
# TODO: add handling of more bracket-like things, and quote handling
|
||||
brackets = {'(': ')', '{': '}', '[': ']', '<': '>'}
|
||||
symbols = [] # type: List[str]
|
||||
symbols: List[str] = []
|
||||
while not self.eof:
|
||||
if (len(symbols) == 0 and self.current_char in end):
|
||||
break
|
||||
@ -5506,7 +5528,7 @@ class DefinitionParser(BaseParser):
|
||||
if self.skip_string('>'):
|
||||
return ASTTemplateArgs([], False)
|
||||
prevErrors = []
|
||||
templateArgs = [] # type: List[Union[ASTType, ASTTemplateArgConstant]]
|
||||
templateArgs: List[Union[ASTType, ASTTemplateArgConstant]] = []
|
||||
packExpansion = False
|
||||
while 1:
|
||||
pos = self.pos
|
||||
@ -5558,8 +5580,8 @@ class DefinitionParser(BaseParser):
|
||||
return ASTTemplateArgs(templateArgs, packExpansion)
|
||||
|
||||
def _parse_nested_name(self, memberPointer: bool = False) -> ASTNestedName:
|
||||
names = [] # type: List[ASTNestedNameElement]
|
||||
templates = [] # type: List[bool]
|
||||
names: List[ASTNestedNameElement] = []
|
||||
templates: List[bool] = []
|
||||
|
||||
self.skip_ws()
|
||||
rooted = False
|
||||
@ -5572,7 +5594,7 @@ class DefinitionParser(BaseParser):
|
||||
else:
|
||||
template = False
|
||||
templates.append(template)
|
||||
identOrOp = None # type: Union[ASTIdentifier, ASTOperator]
|
||||
identOrOp: Union[ASTIdentifier, ASTOperator] = None
|
||||
if self.skip_word_and_ws('operator'):
|
||||
identOrOp = self._parse_operator()
|
||||
else:
|
||||
@ -6075,7 +6097,7 @@ class DefinitionParser(BaseParser):
|
||||
return ASTInitializer(bracedInit)
|
||||
|
||||
if outer == 'member':
|
||||
fallbackEnd = [] # type: List[str]
|
||||
fallbackEnd: List[str] = []
|
||||
elif outer == 'templateParam':
|
||||
fallbackEnd = [',', '>']
|
||||
elif outer is None: # function parameter
|
||||
@ -6161,7 +6183,7 @@ class DefinitionParser(BaseParser):
|
||||
typed=typed)
|
||||
else:
|
||||
paramMode = 'type'
|
||||
if outer == 'member': # i.e., member
|
||||
if outer == 'member':
|
||||
named = True
|
||||
elif outer == 'operatorCast':
|
||||
paramMode = 'operatorCast'
|
||||
@ -6354,7 +6376,7 @@ class DefinitionParser(BaseParser):
|
||||
def _parse_template_parameter_list(self) -> ASTTemplateParams:
|
||||
# only: '<' parameter-list '>'
|
||||
# we assume that 'template' has just been parsed
|
||||
templateParams = [] # type: List[ASTTemplateParam]
|
||||
templateParams: List[ASTTemplateParam] = []
|
||||
self.skip_ws()
|
||||
if not self.skip_string("<"):
|
||||
self.fail("Expected '<' after 'template'")
|
||||
@ -6477,11 +6499,11 @@ class DefinitionParser(BaseParser):
|
||||
|
||||
def _parse_template_declaration_prefix(self, objectType: str
|
||||
) -> Optional[ASTTemplateDeclarationPrefix]:
|
||||
templates = [] # type: List[Union[ASTTemplateParams, ASTTemplateIntroduction]]
|
||||
templates: List[Union[ASTTemplateParams, ASTTemplateIntroduction]] = []
|
||||
while 1:
|
||||
self.skip_ws()
|
||||
# the saved position is only used to provide a better error message
|
||||
params = None # type: Union[ASTTemplateParams, ASTTemplateIntroduction]
|
||||
params: Union[ASTTemplateParams, ASTTemplateIntroduction] = None
|
||||
pos = self.pos
|
||||
if self.skip_word("template"):
|
||||
try:
|
||||
@ -6537,7 +6559,7 @@ class DefinitionParser(BaseParser):
|
||||
msg += str(nestedName)
|
||||
self.warn(msg)
|
||||
|
||||
newTemplates = [] # type: List[Union[ASTTemplateParams, ASTTemplateIntroduction]]
|
||||
newTemplates: List[Union[ASTTemplateParams, ASTTemplateIntroduction]] = []
|
||||
for i in range(numExtra):
|
||||
newTemplates.append(ASTTemplateParams([]))
|
||||
if templatePrefix and not isMemberInstantiation:
|
||||
@ -6557,7 +6579,7 @@ class DefinitionParser(BaseParser):
|
||||
templatePrefix = None
|
||||
requiresClause = None
|
||||
trailingRequiresClause = None
|
||||
declaration = None # type: Any
|
||||
declaration: Any = None
|
||||
|
||||
self.skip_ws()
|
||||
if self.match(_visibility_re):
|
||||
@ -6697,7 +6719,7 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
names=('returns', 'return')),
|
||||
]
|
||||
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'noindexentry': directives.flag,
|
||||
'tparam-line-spec': directives.flag,
|
||||
}
|
||||
@ -6856,7 +6878,7 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
return super().run()
|
||||
|
||||
def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration:
|
||||
parentSymbol = self.env.temp_data['cpp:parent_symbol'] # type: Symbol
|
||||
parentSymbol: Symbol = self.env.temp_data['cpp:parent_symbol']
|
||||
|
||||
parser = DefinitionParser(sig, location=signode, config=self.env.config)
|
||||
try:
|
||||
@ -6903,10 +6925,10 @@ class CPPObject(ObjectDescription[ASTDeclaration]):
|
||||
return ast
|
||||
|
||||
def before_content(self) -> None:
|
||||
lastSymbol = self.env.temp_data['cpp:last_symbol'] # type: Symbol
|
||||
lastSymbol: Symbol = self.env.temp_data['cpp:last_symbol']
|
||||
assert lastSymbol
|
||||
self.oldParentSymbol = self.env.temp_data['cpp:parent_symbol']
|
||||
self.oldParentKey = self.env.ref_context['cpp:parent_key'] # type: LookupKey
|
||||
self.oldParentKey: LookupKey = self.env.ref_context['cpp:parent_key']
|
||||
self.env.temp_data['cpp:parent_symbol'] = lastSymbol
|
||||
self.env.ref_context['cpp:parent_key'] = lastSymbol.get_lookup_key()
|
||||
|
||||
@ -6963,13 +6985,13 @@ class CPPNamespaceObject(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
rootSymbol = self.env.domaindata['cpp']['root_symbol']
|
||||
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
|
||||
symbol = rootSymbol
|
||||
stack = [] # type: List[Symbol]
|
||||
stack: List[Symbol] = []
|
||||
else:
|
||||
parser = DefinitionParser(self.arguments[0],
|
||||
location=self.get_source_info(),
|
||||
@ -6994,7 +7016,7 @@ class CPPNamespacePushObject(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
|
||||
@ -7026,7 +7048,7 @@ class CPPNamespacePopObject(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
stack = self.env.temp_data.get('cpp:namespace_stack', None)
|
||||
@ -7081,7 +7103,7 @@ class AliasTransform(SphinxTransform):
|
||||
maxdepth -= 1
|
||||
recurse = True
|
||||
|
||||
nodes = [] # type: List[Node]
|
||||
nodes: List[Node] = []
|
||||
if not skipThis:
|
||||
signode = addnodes.desc_signature('', '')
|
||||
nodes.append(signode)
|
||||
@ -7089,7 +7111,7 @@ class AliasTransform(SphinxTransform):
|
||||
|
||||
if recurse:
|
||||
if skipThis:
|
||||
childContainer = nodes # type: Union[List[Node], addnodes.desc]
|
||||
childContainer: Union[List[Node], addnodes.desc] = nodes
|
||||
else:
|
||||
content = addnodes.desc_content()
|
||||
desc = addnodes.desc()
|
||||
@ -7138,15 +7160,15 @@ class AliasTransform(SphinxTransform):
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
|
||||
rootSymbol = self.env.domains['cpp'].data['root_symbol'] # type: Symbol
|
||||
parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
|
||||
rootSymbol: Symbol = self.env.domains['cpp'].data['root_symbol']
|
||||
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
||||
if not parentSymbol:
|
||||
print("Target: ", sig)
|
||||
print("ParentKey: ", parentKey)
|
||||
print(rootSymbol.dump(1))
|
||||
assert parentSymbol # should be there
|
||||
|
||||
symbols = [] # type: List[Symbol]
|
||||
symbols: List[Symbol] = []
|
||||
if isShorthand:
|
||||
assert isinstance(ast, ASTNamespace)
|
||||
ns = ast
|
||||
@ -7203,10 +7225,10 @@ class AliasTransform(SphinxTransform):
|
||||
|
||||
|
||||
class CPPAliasObject(ObjectDescription):
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'maxdepth': directives.nonnegative_int,
|
||||
'noroot': directives.flag,
|
||||
} # type: Dict
|
||||
}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
"""
|
||||
@ -7225,7 +7247,7 @@ class CPPAliasObject(ObjectDescription):
|
||||
# 'desctype' is a backwards compatible attribute
|
||||
node['objtype'] = node['desctype'] = self.objtype
|
||||
|
||||
self.names = [] # type: List[str]
|
||||
self.names: List[str] = []
|
||||
aliasOptions = {
|
||||
'maxdepth': self.options.get('maxdepth', 1),
|
||||
'noroot': 'noroot' in self.options,
|
||||
@ -7285,7 +7307,7 @@ class CPPExprRole(SphinxRole):
|
||||
if asCode:
|
||||
# render the expression as inline code
|
||||
self.class_type = 'cpp-expr'
|
||||
self.node_type = nodes.literal # type: Type[TextElement]
|
||||
self.node_type: Type[TextElement] = nodes.literal
|
||||
else:
|
||||
# render the expression as inline text
|
||||
self.class_type = 'cpp-texpr'
|
||||
@ -7466,10 +7488,10 @@ class CPPDomain(Domain):
|
||||
logger.warning('Unparseable C++ cross-reference: %r\n%s', t, ex,
|
||||
location=node)
|
||||
return None, None
|
||||
parentKey = node.get("cpp:parent_key", None) # type: LookupKey
|
||||
parentKey: LookupKey = node.get("cpp:parent_key", None)
|
||||
rootSymbol = self.data['root_symbol']
|
||||
if parentKey:
|
||||
parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
|
||||
parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
|
||||
if not parentSymbol:
|
||||
print("Target: ", target)
|
||||
print("ParentKey: ", parentKey.data)
|
||||
@ -7623,7 +7645,7 @@ class CPPDomain(Domain):
|
||||
target = node.get('reftarget', None)
|
||||
if target is None:
|
||||
return None
|
||||
parentKey = node.get("cpp:parent_key", None) # type: LookupKey
|
||||
parentKey: LookupKey = node.get("cpp:parent_key", None)
|
||||
if parentKey is None or len(parentKey.data) <= 0:
|
||||
return None
|
||||
|
||||
@ -7644,10 +7666,11 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value("cpp_debug_lookup", False, '')
|
||||
app.add_config_value("cpp_debug_show_tree", False, '')
|
||||
|
||||
def setDebugFlags(app):
|
||||
def initStuff(app):
|
||||
Symbol.debug_lookup = app.config.cpp_debug_lookup
|
||||
Symbol.debug_show_tree = app.config.cpp_debug_show_tree
|
||||
app.connect("builder-inited", setDebugFlags)
|
||||
app.config.cpp_index_common_prefix.sort(reverse=True)
|
||||
app.connect("builder-inited", initStuff)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
@ -8,7 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Iterable, List, Tuple
|
||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node, system_message
|
||||
@ -20,9 +20,9 @@ from sphinx.environment import BuildEnvironment
|
||||
from sphinx.util import logging, split_index_msg
|
||||
from sphinx.util.docutils import ReferenceRole, SphinxDirective
|
||||
from sphinx.util.nodes import process_index_entry
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ class IndexDirective(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'name': directives.unchanged,
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ from sphinx.util import logging
|
||||
from sphinx.util.docfields import Field, GroupedField, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import make_id, make_refnode
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -41,13 +42,13 @@ class JSObject(ObjectDescription[Tuple[str, str]]):
|
||||
has_arguments = False
|
||||
|
||||
#: what is displayed right before the documentation entry
|
||||
display_prefix = None # type: str
|
||||
display_prefix: str = None
|
||||
|
||||
#: If ``allow_nesting`` is ``True``, the object prefixes will be accumulated
|
||||
#: based on directive nesting
|
||||
allow_nesting = False
|
||||
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'noindex': directives.flag,
|
||||
'noindexentry': directives.flag,
|
||||
}
|
||||
@ -253,7 +254,7 @@ class JSModule(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'noindex': directives.flag
|
||||
}
|
||||
|
||||
@ -261,7 +262,7 @@ class JSModule(SphinxDirective):
|
||||
mod_name = self.arguments[0].strip()
|
||||
self.env.ref_context['js:module'] = mod_name
|
||||
noindex = 'noindex' in self.options
|
||||
ret = [] # type: List[Node]
|
||||
ret: List[Node] = []
|
||||
if not noindex:
|
||||
domain = cast(JavaScriptDomain, self.env.get_domain('js'))
|
||||
|
||||
@ -345,10 +346,10 @@ class JavaScriptDomain(Domain):
|
||||
'attr': JSXRefRole(),
|
||||
'mod': JSXRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
initial_data: Dict[str, Dict[str, Tuple[str, str]]] = {
|
||||
'objects': {}, # fullname -> docname, node_id, objtype
|
||||
'modules': {}, # modname -> docname, node_id
|
||||
} # type: Dict[str, Dict[str, Tuple[str, str]]]
|
||||
}
|
||||
|
||||
@property
|
||||
def objects(self) -> Dict[str, Tuple[str, str, str]]:
|
||||
|
@ -8,14 +8,12 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict, Iterable, List, Tuple
|
||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, make_id, system_message
|
||||
|
||||
from sphinx.addnodes import pending_xref
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.locale import __
|
||||
@ -23,8 +21,7 @@ from sphinx.roles import XRefRole
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.nodes import make_refnode
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
|
||||
@ -44,10 +41,10 @@ class MathDomain(Domain):
|
||||
name = 'math'
|
||||
label = 'mathematics'
|
||||
|
||||
initial_data = {
|
||||
initial_data: Dict = {
|
||||
'objects': {}, # labelid -> (docname, eqno)
|
||||
'has_equations': {}, # docname -> bool
|
||||
} # type: Dict
|
||||
}
|
||||
dangling_warnings = {
|
||||
'eq': 'equation not found: %(target)s',
|
||||
}
|
||||
@ -139,24 +136,6 @@ class MathDomain(Domain):
|
||||
def get_objects(self) -> List:
|
||||
return []
|
||||
|
||||
def add_equation(self, env: BuildEnvironment, docname: str, labelid: str) -> int:
|
||||
warnings.warn('MathDomain.add_equation() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
if labelid in self.equations:
|
||||
path = env.doc2path(self.equations[labelid][0])
|
||||
msg = __('duplicate label of equation %s, other instance in %s') % (labelid, path)
|
||||
raise UserWarning(msg)
|
||||
else:
|
||||
eqno = self.get_next_equation_number(docname)
|
||||
self.equations[labelid] = (docname, eqno)
|
||||
return eqno
|
||||
|
||||
def get_next_equation_number(self, docname: str) -> int:
|
||||
warnings.warn('MathDomain.get_next_equation_number() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
targets = [eq for eq in self.equations.values() if eq[0] == docname]
|
||||
return len(targets) + 1
|
||||
|
||||
def has_equations(self, docname: str = None) -> bool:
|
||||
if docname:
|
||||
return self.data['has_equations'].get(docname, False)
|
||||
|
@ -15,17 +15,17 @@ import sys
|
||||
import typing
|
||||
import warnings
|
||||
from inspect import Parameter
|
||||
from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple, cast
|
||||
from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Tuple, Type, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.addnodes import desc_signature, pending_xref
|
||||
from sphinx.addnodes import desc_signature, pending_xref, pending_xref_condition
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.domains import Domain, Index, IndexEntry, ObjType
|
||||
from sphinx.environment import BuildEnvironment
|
||||
@ -37,13 +37,8 @@ from sphinx.util import logging
|
||||
from sphinx.util.docfields import Field, GroupedField, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.inspect import signature_from_str
|
||||
from sphinx.util.nodes import make_id, make_refnode
|
||||
from sphinx.util.typing import TextlikeNode
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
from sphinx.util.nodes import find_pending_xref_condition, make_id, make_refnode
|
||||
from sphinx.util.typing import OptionSpec, TextlikeNode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -68,14 +63,20 @@ pairindextypes = {
|
||||
'builtin': _('built-in function'),
|
||||
}
|
||||
|
||||
ObjectEntry = NamedTuple('ObjectEntry', [('docname', str),
|
||||
('node_id', str),
|
||||
('objtype', str)])
|
||||
ModuleEntry = NamedTuple('ModuleEntry', [('docname', str),
|
||||
('node_id', str),
|
||||
('synopsis', str),
|
||||
('platform', str),
|
||||
('deprecated', bool)])
|
||||
|
||||
class ObjectEntry(NamedTuple):
|
||||
docname: str
|
||||
node_id: str
|
||||
objtype: str
|
||||
canonical: bool
|
||||
|
||||
|
||||
class ModuleEntry(NamedTuple):
|
||||
docname: str
|
||||
node_id: str
|
||||
synopsis: str
|
||||
platform: str
|
||||
deprecated: bool
|
||||
|
||||
|
||||
def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xref:
|
||||
@ -91,7 +92,17 @@ def type_to_xref(text: str, env: BuildEnvironment = None) -> addnodes.pending_xr
|
||||
else:
|
||||
kwargs = {}
|
||||
|
||||
return pending_xref('', nodes.Text(text),
|
||||
if env.config.python_use_unqualified_type_names:
|
||||
# Note: It would be better to use qualname to describe the object to support support
|
||||
# nested classes. But python domain can't access the real python object because this
|
||||
# module should work not-dynamically.
|
||||
shortname = text.split('.')[-1]
|
||||
contnodes: List[Node] = [pending_xref_condition('', shortname, condition='resolved'),
|
||||
pending_xref_condition('', text, condition='*')]
|
||||
else:
|
||||
contnodes = [nodes.Text(text)]
|
||||
|
||||
return pending_xref('', *contnodes,
|
||||
refdomain='py', reftype=reftype, reftarget=text, **kwargs)
|
||||
|
||||
|
||||
@ -101,12 +112,17 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod
|
||||
if isinstance(node, ast.Attribute):
|
||||
return [nodes.Text("%s.%s" % (unparse(node.value)[0], node.attr))]
|
||||
elif isinstance(node, ast.BinOp):
|
||||
result = unparse(node.left) # type: List[Node]
|
||||
result: List[Node] = unparse(node.left)
|
||||
result.extend(unparse(node.op))
|
||||
result.extend(unparse(node.right))
|
||||
return result
|
||||
elif isinstance(node, ast.BitOr):
|
||||
return [nodes.Text(' '), addnodes.desc_sig_punctuation('', '|'), nodes.Text(' ')]
|
||||
elif isinstance(node, ast.Constant): # type: ignore
|
||||
if node.value is Ellipsis:
|
||||
return [addnodes.desc_sig_punctuation('', "...")]
|
||||
else:
|
||||
return [nodes.Text(node.value)]
|
||||
elif isinstance(node, ast.Expr):
|
||||
return unparse(node.value)
|
||||
elif isinstance(node, ast.Index):
|
||||
@ -142,13 +158,6 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod
|
||||
|
||||
return result
|
||||
else:
|
||||
if sys.version_info >= (3, 6):
|
||||
if isinstance(node, ast.Constant):
|
||||
if node.value is Ellipsis:
|
||||
return [addnodes.desc_sig_punctuation('', "...")]
|
||||
else:
|
||||
return [nodes.Text(node.value)]
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
if isinstance(node, ast.Ellipsis):
|
||||
return [addnodes.desc_sig_punctuation('', "...")]
|
||||
@ -230,7 +239,7 @@ def _pseudo_parse_arglist(signode: desc_signature, arglist: str) -> None:
|
||||
string literal (e.g. default argument value).
|
||||
"""
|
||||
paramlist = addnodes.desc_parameterlist()
|
||||
stack = [paramlist] # type: List[Element]
|
||||
stack: List[Element] = [paramlist]
|
||||
try:
|
||||
for argument in arglist.split(','):
|
||||
argument = argument.strip()
|
||||
@ -274,7 +283,7 @@ def _pseudo_parse_arglist(signode: desc_signature, arglist: str) -> None:
|
||||
# when it comes to handling "." and "~" prefixes.
|
||||
class PyXrefMixin:
|
||||
def make_xref(self, rolename: str, domain: str, target: str,
|
||||
innernode: "Type[TextlikeNode]" = nodes.emphasis,
|
||||
innernode: Type[TextlikeNode] = nodes.emphasis,
|
||||
contnode: Node = None, env: BuildEnvironment = None) -> Node:
|
||||
result = super().make_xref(rolename, domain, target, # type: ignore
|
||||
innernode, contnode, env)
|
||||
@ -293,7 +302,7 @@ class PyXrefMixin:
|
||||
return result
|
||||
|
||||
def make_xrefs(self, rolename: str, domain: str, target: str,
|
||||
innernode: "Type[TextlikeNode]" = nodes.emphasis,
|
||||
innernode: Type[TextlikeNode] = nodes.emphasis,
|
||||
contnode: Node = None, env: BuildEnvironment = None) -> List[Node]:
|
||||
delims = r'(\s*[\[\]\(\),](?:\s*or\s)?\s*|\s+or\s+)'
|
||||
delims_re = re.compile(delims)
|
||||
@ -317,7 +326,7 @@ class PyXrefMixin:
|
||||
|
||||
class PyField(PyXrefMixin, Field):
|
||||
def make_xref(self, rolename: str, domain: str, target: str,
|
||||
innernode: "Type[TextlikeNode]" = nodes.emphasis,
|
||||
innernode: Type[TextlikeNode] = nodes.emphasis,
|
||||
contnode: Node = None, env: BuildEnvironment = None) -> Node:
|
||||
if rolename == 'class' and target == 'None':
|
||||
# None is not a type, so use obj role instead.
|
||||
@ -332,7 +341,7 @@ class PyGroupedField(PyXrefMixin, GroupedField):
|
||||
|
||||
class PyTypedField(PyXrefMixin, TypedField):
|
||||
def make_xref(self, rolename: str, domain: str, target: str,
|
||||
innernode: "Type[TextlikeNode]" = nodes.emphasis,
|
||||
innernode: Type[TextlikeNode] = nodes.emphasis,
|
||||
contnode: Node = None, env: BuildEnvironment = None) -> Node:
|
||||
if rolename == 'class' and target == 'None':
|
||||
# None is not a type, so use obj role instead.
|
||||
@ -348,10 +357,11 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
|
||||
:cvar allow_nesting: Class is an object that allows for nested namespaces
|
||||
:vartype allow_nesting: bool
|
||||
"""
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'noindex': directives.flag,
|
||||
'noindexentry': directives.flag,
|
||||
'module': directives.unchanged,
|
||||
'canonical': directives.unchanged,
|
||||
'annotation': directives.unchanged,
|
||||
}
|
||||
|
||||
@ -361,7 +371,7 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
|
||||
'keyword', 'kwarg', 'kwparam'),
|
||||
typerolename='class', typenames=('paramtype', 'type'),
|
||||
can_collapse=True),
|
||||
PyTypedField('variable', label=_('Variables'), rolename='obj',
|
||||
PyTypedField('variable', label=_('Variables'),
|
||||
names=('var', 'ivar', 'cvar'),
|
||||
typerolename='class', typenames=('vartype',),
|
||||
can_collapse=True),
|
||||
@ -493,6 +503,11 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
|
||||
domain = cast(PythonDomain, self.env.get_domain('py'))
|
||||
domain.note_object(fullname, self.objtype, node_id, location=signode)
|
||||
|
||||
canonical_name = self.options.get('canonical')
|
||||
if canonical_name:
|
||||
domain.note_object(canonical_name, self.objtype, node_id, canonical=True,
|
||||
location=signode)
|
||||
|
||||
if 'noindexentry' not in self.options:
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
@ -557,44 +572,10 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
|
||||
self.env.ref_context.pop('py:module')
|
||||
|
||||
|
||||
class PyModulelevel(PyObject):
|
||||
"""
|
||||
Description of an object on module level (functions, data).
|
||||
"""
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
for cls in self.__class__.__mro__:
|
||||
if cls.__name__ != 'DirectiveAdapter':
|
||||
warnings.warn('PyModulelevel is deprecated. '
|
||||
'Please check the implementation of %s' % cls,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
break
|
||||
else:
|
||||
warnings.warn('PyModulelevel is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
return super().run()
|
||||
|
||||
def needs_arglist(self) -> bool:
|
||||
return self.objtype == 'function'
|
||||
|
||||
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
|
||||
if self.objtype == 'function':
|
||||
if not modname:
|
||||
return _('%s() (built-in function)') % name_cls[0]
|
||||
return _('%s() (in module %s)') % (name_cls[0], modname)
|
||||
elif self.objtype == 'data':
|
||||
if not modname:
|
||||
return _('%s (built-in variable)') % name_cls[0]
|
||||
return _('%s (in module %s)') % (name_cls[0], modname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class PyFunction(PyObject):
|
||||
"""Description of a function."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
option_spec.update({
|
||||
'async': directives.flag,
|
||||
})
|
||||
@ -648,7 +629,7 @@ class PyDecoratorFunction(PyFunction):
|
||||
class PyVariable(PyObject):
|
||||
"""Description of a variable."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
option_spec.update({
|
||||
'type': directives.unchanged,
|
||||
'value': directives.unchanged,
|
||||
@ -681,7 +662,7 @@ class PyClasslike(PyObject):
|
||||
Description of a class-like object (classes, interfaces, exceptions).
|
||||
"""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
option_spec.update({
|
||||
'final': directives.flag,
|
||||
})
|
||||
@ -705,95 +686,10 @@ class PyClasslike(PyObject):
|
||||
return ''
|
||||
|
||||
|
||||
class PyClassmember(PyObject):
|
||||
"""
|
||||
Description of a class member (methods, attributes).
|
||||
"""
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
for cls in self.__class__.__mro__:
|
||||
if cls.__name__ != 'DirectiveAdapter':
|
||||
warnings.warn('PyClassmember is deprecated. '
|
||||
'Please check the implementation of %s' % cls,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
break
|
||||
else:
|
||||
warnings.warn('PyClassmember is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
return super().run()
|
||||
|
||||
def needs_arglist(self) -> bool:
|
||||
return self.objtype.endswith('method')
|
||||
|
||||
def get_signature_prefix(self, sig: str) -> str:
|
||||
if self.objtype == 'staticmethod':
|
||||
return 'static '
|
||||
elif self.objtype == 'classmethod':
|
||||
return 'classmethod '
|
||||
return ''
|
||||
|
||||
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
|
||||
name, cls = name_cls
|
||||
add_modules = self.env.config.add_module_names
|
||||
if self.objtype == 'method':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s method)') % (methname, modname, clsname)
|
||||
else:
|
||||
return _('%s() (%s method)') % (methname, clsname)
|
||||
elif self.objtype == 'staticmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname and add_modules:
|
||||
return _('%s() (%s.%s static method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s static method)') % (methname, clsname)
|
||||
elif self.objtype == 'classmethod':
|
||||
try:
|
||||
clsname, methname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s() (in module %s)') % (name, modname)
|
||||
else:
|
||||
return '%s()' % name
|
||||
if modname:
|
||||
return _('%s() (%s.%s class method)') % (methname, modname,
|
||||
clsname)
|
||||
else:
|
||||
return _('%s() (%s class method)') % (methname, clsname)
|
||||
elif self.objtype == 'attribute':
|
||||
try:
|
||||
clsname, attrname = name.rsplit('.', 1)
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s (in module %s)') % (name, modname)
|
||||
else:
|
||||
return name
|
||||
if modname and add_modules:
|
||||
return _('%s (%s.%s attribute)') % (attrname, modname, clsname)
|
||||
else:
|
||||
return _('%s (%s attribute)') % (attrname, clsname)
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class PyMethod(PyObject):
|
||||
"""Description of a method."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
option_spec.update({
|
||||
'abstractmethod': directives.flag,
|
||||
'async': directives.flag,
|
||||
@ -854,7 +750,7 @@ class PyMethod(PyObject):
|
||||
class PyClassMethod(PyMethod):
|
||||
"""Description of a classmethod."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
self.name = 'py:method'
|
||||
@ -866,7 +762,7 @@ class PyClassMethod(PyMethod):
|
||||
class PyStaticMethod(PyMethod):
|
||||
"""Description of a staticmethod."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
self.name = 'py:method'
|
||||
@ -894,7 +790,7 @@ class PyDecoratorMethod(PyMethod):
|
||||
class PyAttribute(PyObject):
|
||||
"""Description of an attribute."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec: OptionSpec = PyObject.option_spec.copy()
|
||||
option_spec.update({
|
||||
'type': directives.unchanged,
|
||||
'value': directives.unchanged,
|
||||
@ -929,6 +825,46 @@ class PyAttribute(PyObject):
|
||||
return _('%s (%s attribute)') % (attrname, clsname)
|
||||
|
||||
|
||||
class PyProperty(PyObject):
|
||||
"""Description of an attribute."""
|
||||
|
||||
option_spec = PyObject.option_spec.copy()
|
||||
option_spec.update({
|
||||
'abstractmethod': directives.flag,
|
||||
'type': directives.unchanged,
|
||||
})
|
||||
|
||||
def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]:
|
||||
fullname, prefix = super().handle_signature(sig, signode)
|
||||
|
||||
typ = self.options.get('type')
|
||||
if typ:
|
||||
signode += addnodes.desc_annotation(typ, ': ' + typ)
|
||||
|
||||
return fullname, prefix
|
||||
|
||||
def get_signature_prefix(self, sig: str) -> str:
|
||||
prefix = ['property']
|
||||
if 'abstractmethod' in self.options:
|
||||
prefix.insert(0, 'abstract')
|
||||
|
||||
return ' '.join(prefix) + ' '
|
||||
|
||||
def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str:
|
||||
name, cls = name_cls
|
||||
try:
|
||||
clsname, attrname = name.rsplit('.', 1)
|
||||
if modname and self.env.config.add_module_names:
|
||||
clsname = '.'.join([modname, clsname])
|
||||
except ValueError:
|
||||
if modname:
|
||||
return _('%s (in module %s)') % (name, modname)
|
||||
else:
|
||||
return name
|
||||
|
||||
return _('%s (%s property)') % (attrname, clsname)
|
||||
|
||||
|
||||
class PyDecoratorMixin:
|
||||
"""
|
||||
Mixin for decorator directives.
|
||||
@ -961,7 +897,7 @@ class PyModule(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'platform': lambda x: x,
|
||||
'synopsis': lambda x: x,
|
||||
'noindex': directives.flag,
|
||||
@ -974,7 +910,7 @@ class PyModule(SphinxDirective):
|
||||
modname = self.arguments[0].strip()
|
||||
noindex = 'noindex' in self.options
|
||||
self.env.ref_context['py:module'] = modname
|
||||
ret = [] # type: List[Node]
|
||||
ret: List[Node] = []
|
||||
if not noindex:
|
||||
# note module to the domain
|
||||
node_id = make_id(self.env, self.state.document, 'module', modname)
|
||||
@ -1025,7 +961,7 @@ class PyCurrentModule(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
modname = self.arguments[0].strip()
|
||||
@ -1085,10 +1021,9 @@ class PythonModuleIndex(Index):
|
||||
|
||||
def generate(self, docnames: Iterable[str] = None
|
||||
) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]:
|
||||
content = {} # type: Dict[str, List[IndexEntry]]
|
||||
content: Dict[str, List[IndexEntry]] = {}
|
||||
# list of prefixes to ignore
|
||||
ignores = None # type: List[str]
|
||||
ignores = self.domain.env.config['modindex_common_prefix'] # type: ignore
|
||||
ignores: List[str] = 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(self.domain.data['modules'].items(),
|
||||
@ -1151,7 +1086,7 @@ class PythonDomain(Domain):
|
||||
"""Python language domain."""
|
||||
name = 'py'
|
||||
label = 'Python'
|
||||
object_types = {
|
||||
object_types: Dict[str, ObjType] = {
|
||||
'function': ObjType(_('function'), 'func', 'obj'),
|
||||
'data': ObjType(_('data'), 'data', 'obj'),
|
||||
'class': ObjType(_('class'), 'class', 'exc', 'obj'),
|
||||
@ -1160,8 +1095,9 @@ class PythonDomain(Domain):
|
||||
'classmethod': ObjType(_('class method'), 'meth', 'obj'),
|
||||
'staticmethod': ObjType(_('static method'), 'meth', 'obj'),
|
||||
'attribute': ObjType(_('attribute'), 'attr', 'obj'),
|
||||
'property': ObjType(_('property'), 'attr', '_prop', 'obj'),
|
||||
'module': ObjType(_('module'), 'mod', 'obj'),
|
||||
} # type: Dict[str, ObjType]
|
||||
}
|
||||
|
||||
directives = {
|
||||
'function': PyFunction,
|
||||
@ -1172,6 +1108,7 @@ class PythonDomain(Domain):
|
||||
'classmethod': PyClassMethod,
|
||||
'staticmethod': PyStaticMethod,
|
||||
'attribute': PyAttribute,
|
||||
'property': PyProperty,
|
||||
'module': PyModule,
|
||||
'currentmodule': PyCurrentModule,
|
||||
'decorator': PyDecoratorFunction,
|
||||
@ -1188,10 +1125,10 @@ class PythonDomain(Domain):
|
||||
'mod': PyXRefRole(),
|
||||
'obj': PyXRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
initial_data: Dict[str, Dict[str, Tuple[Any]]] = {
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
'modules': {}, # modname -> docname, synopsis, platform, deprecated
|
||||
} # type: Dict[str, Dict[str, Tuple[Any]]]
|
||||
}
|
||||
indices = [
|
||||
PythonModuleIndex,
|
||||
]
|
||||
@ -1200,7 +1137,8 @@ class PythonDomain(Domain):
|
||||
def objects(self) -> Dict[str, ObjectEntry]:
|
||||
return self.data.setdefault('objects', {}) # fullname -> ObjectEntry
|
||||
|
||||
def note_object(self, name: str, objtype: str, node_id: str, location: Any = None) -> None:
|
||||
def note_object(self, name: str, objtype: str, node_id: str,
|
||||
canonical: bool = False, location: Any = None) -> None:
|
||||
"""Note a python object for cross reference.
|
||||
|
||||
.. versionadded:: 2.1
|
||||
@ -1210,7 +1148,7 @@ class PythonDomain(Domain):
|
||||
logger.warning(__('duplicate object description of %s, '
|
||||
'other instance in %s, use :noindex: for one of them'),
|
||||
name, other.docname, location=location)
|
||||
self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype)
|
||||
self.objects[name] = ObjectEntry(self.env.docname, node_id, objtype, canonical)
|
||||
|
||||
@property
|
||||
def modules(self) -> Dict[str, ModuleEntry]:
|
||||
@ -1255,7 +1193,7 @@ class PythonDomain(Domain):
|
||||
if not name:
|
||||
return []
|
||||
|
||||
matches = [] # type: List[Tuple[str, ObjectEntry]]
|
||||
matches: List[Tuple[str, ObjectEntry]] = []
|
||||
|
||||
newname = None
|
||||
if searchmode == 1:
|
||||
@ -1308,8 +1246,17 @@ class PythonDomain(Domain):
|
||||
type, searchmode)
|
||||
|
||||
if not matches and type == 'attr':
|
||||
# fallback to meth (for property)
|
||||
# fallback to meth (for property; Sphinx-2.4.x)
|
||||
# this ensures that `:attr:` role continues to refer to the old property entry
|
||||
# that defined by ``method`` directive in old reST files.
|
||||
matches = self.find_obj(env, modname, clsname, target, 'meth', searchmode)
|
||||
if not matches and type == 'meth':
|
||||
# fallback to attr (for property)
|
||||
# this ensures that `:meth:` in the old reST files can refer to the property
|
||||
# entry that defined by ``property`` directive.
|
||||
#
|
||||
# Note: _prop is a secret role only for internal look-up.
|
||||
matches = self.find_obj(env, modname, clsname, target, '_prop', searchmode)
|
||||
|
||||
if not matches:
|
||||
return None
|
||||
@ -1322,14 +1269,22 @@ class PythonDomain(Domain):
|
||||
if obj[2] == 'module':
|
||||
return self._make_module_refnode(builder, fromdocname, name, contnode)
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
|
||||
# determine the content of the reference by conditions
|
||||
content = find_pending_xref_condition(node, 'resolved')
|
||||
if content:
|
||||
children = content.children
|
||||
else:
|
||||
# if not found, use contnode
|
||||
children = [contnode]
|
||||
|
||||
return make_refnode(builder, fromdocname, obj[0], obj[1], children, name)
|
||||
|
||||
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
target: str, node: pending_xref, contnode: Element
|
||||
) -> List[Tuple[str, Element]]:
|
||||
modname = node.get('py:module')
|
||||
clsname = node.get('py:class')
|
||||
results = [] # type: List[Tuple[str, Element]]
|
||||
results: List[Tuple[str, Element]] = []
|
||||
|
||||
# always search in "refspecific" mode with the :any: role
|
||||
matches = self.find_obj(env, modname, clsname, target, None, 1)
|
||||
@ -1339,9 +1294,17 @@ class PythonDomain(Domain):
|
||||
self._make_module_refnode(builder, fromdocname,
|
||||
name, contnode)))
|
||||
else:
|
||||
# determine the content of the reference by conditions
|
||||
content = find_pending_xref_condition(node, 'resolved')
|
||||
if content:
|
||||
children = content.children
|
||||
else:
|
||||
# if not found, use contnode
|
||||
children = [contnode]
|
||||
|
||||
results.append(('py:' + self.role_for_objtype(obj[2]),
|
||||
make_refnode(builder, fromdocname, obj[0], obj[1],
|
||||
contnode, name)))
|
||||
children, name)))
|
||||
return results
|
||||
|
||||
def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
|
||||
@ -1363,7 +1326,11 @@ class PythonDomain(Domain):
|
||||
yield (modname, modname, 'module', mod.docname, mod.node_id, 0)
|
||||
for refname, obj in self.objects.items():
|
||||
if obj.objtype != 'module': # modules are already handled
|
||||
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
|
||||
if obj.canonical:
|
||||
# canonical names are not full-text searchable.
|
||||
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, -1)
|
||||
else:
|
||||
yield (refname, refname, obj.objtype, obj.docname, obj.node_id, 1)
|
||||
|
||||
def get_full_qualified_name(self, node: Element) -> str:
|
||||
modname = node.get('py:module')
|
||||
@ -1384,6 +1351,10 @@ def builtin_resolver(app: Sphinx, env: BuildEnvironment,
|
||||
|
||||
return s in typing.__all__ # type: ignore
|
||||
|
||||
content = find_pending_xref_condition(node, 'resolved')
|
||||
if content:
|
||||
contnode = content.children[0] # type: ignore
|
||||
|
||||
if node.get('refdomain') != 'py':
|
||||
return None
|
||||
elif node.get('reftype') in ('class', 'obj') and node.get('reftarget') == 'None':
|
||||
@ -1404,12 +1375,13 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.setup_extension('sphinx.directives')
|
||||
|
||||
app.add_domain(PythonDomain)
|
||||
app.add_config_value('python_use_unqualified_type_names', False, 'env')
|
||||
app.connect('object-description-transform', filter_meta_fields)
|
||||
app.connect('missing-reference', builtin_resolver, priority=900)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'env_version': 2,
|
||||
'env_version': 3,
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ from sphinx.locale import _, __
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.nodes import make_id, make_refnode
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -117,7 +118,7 @@ class ReSTDirectiveOption(ReSTMarkup):
|
||||
"""
|
||||
Description of an option for reST directive.
|
||||
"""
|
||||
option_spec = ReSTMarkup.option_spec.copy()
|
||||
option_spec: OptionSpec = ReSTMarkup.option_spec.copy()
|
||||
option_spec.update({
|
||||
'type': directives.unchanged,
|
||||
})
|
||||
@ -217,9 +218,9 @@ class ReSTDomain(Domain):
|
||||
'dir': XRefRole(),
|
||||
'role': XRefRole(),
|
||||
}
|
||||
initial_data = {
|
||||
initial_data: Dict[str, Dict[Tuple[str, str], str]] = {
|
||||
'objects': {}, # fullname -> docname, objtype
|
||||
} # type: Dict[str, Dict[Tuple[str, str], str]]
|
||||
}
|
||||
|
||||
@property
|
||||
def objects(self) -> Dict[Tuple[str, str], Tuple[str, str]]:
|
||||
@ -258,7 +259,7 @@ class ReSTDomain(Domain):
|
||||
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
target: str, node: pending_xref, contnode: Element
|
||||
) -> List[Tuple[str, Element]]:
|
||||
results = [] # type: List[Tuple[str, Element]]
|
||||
results: List[Tuple[str, Element]] = []
|
||||
for objtype in self.object_types:
|
||||
todocname, node_id = self.objects.get((objtype, target), (None, None))
|
||||
if todocname:
|
||||
|
@ -12,7 +12,8 @@ import re
|
||||
import unicodedata
|
||||
import warnings
|
||||
from copy import copy
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast
|
||||
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, Iterator, List, Optional,
|
||||
Tuple, Type, Union, cast)
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, system_message
|
||||
@ -21,7 +22,7 @@ from docutils.statemachine import StringList
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.addnodes import desc_signature, pending_xref
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.locale import _, __
|
||||
@ -29,12 +30,9 @@ from sphinx.roles import XRefRole
|
||||
from sphinx.util import docname_join, logging, ws_re
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import clean_astext, make_id, make_refnode
|
||||
from sphinx.util.typing import RoleFunction
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
from sphinx.util.typing import OptionSpec, RoleFunction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.environment import BuildEnvironment
|
||||
@ -52,8 +50,8 @@ class GenericObject(ObjectDescription[str]):
|
||||
"""
|
||||
A generic x-ref directive registered with Sphinx.add_object_type().
|
||||
"""
|
||||
indextemplate = ''
|
||||
parse_node = None # type: Callable[[GenericObject, BuildEnvironment, str, desc_signature], str] # NOQA
|
||||
indextemplate: str = ''
|
||||
parse_node: Callable[["GenericObject", "BuildEnvironment", str, desc_signature], str] = None # NOQA
|
||||
|
||||
def handle_signature(self, sig: str, signode: desc_signature) -> str:
|
||||
if self.parse_node:
|
||||
@ -134,7 +132,7 @@ class Target(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
# normalize whitespace in fullname like XRefRole does
|
||||
@ -150,7 +148,7 @@ class Target(SphinxDirective):
|
||||
node['ids'].append(old_node_id)
|
||||
|
||||
self.state.document.note_explicit_target(node)
|
||||
ret = [node] # type: List[Node]
|
||||
ret: List[Node] = [node]
|
||||
if self.indextemplate:
|
||||
indexentry = self.indextemplate % (fullname,)
|
||||
indextype = 'single'
|
||||
@ -267,7 +265,7 @@ class Program(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
program = ws_re.sub('-', self.arguments[0].strip())
|
||||
@ -292,8 +290,8 @@ def split_term_classifiers(line: str) -> List[Optional[str]]:
|
||||
|
||||
|
||||
def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index_key: str,
|
||||
source: str, lineno: int, node_id: str = None,
|
||||
document: nodes.document = None) -> nodes.term:
|
||||
source: str, lineno: int, node_id: str, document: nodes.document
|
||||
) -> nodes.term:
|
||||
# get a text-only representation of the term and register it
|
||||
# as a cross-reference target
|
||||
term = nodes.term('', '', *textnodes)
|
||||
@ -304,23 +302,10 @@ def make_glossary_term(env: "BuildEnvironment", textnodes: Iterable[Node], index
|
||||
if node_id:
|
||||
# node_id is given from outside (mainly i18n module), use it forcedly
|
||||
term['ids'].append(node_id)
|
||||
elif document:
|
||||
else:
|
||||
node_id = make_id(env, document, 'term', termtext)
|
||||
term['ids'].append(node_id)
|
||||
document.note_explicit_target(term)
|
||||
else:
|
||||
warnings.warn('make_glossary_term() expects document is passed as an argument.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
gloss_entries = env.temp_data.setdefault('gloss_entries', set())
|
||||
node_id = nodes.make_id('term-' + termtext)
|
||||
if node_id == 'term':
|
||||
# "term" is not good for node_id. Generate it by sequence number instead.
|
||||
node_id = 'term-%d' % env.new_serialno('glossary')
|
||||
|
||||
while node_id in gloss_entries:
|
||||
node_id = 'term-%d' % env.new_serialno('glossary')
|
||||
gloss_entries.add(node_id)
|
||||
term['ids'].append(node_id)
|
||||
|
||||
std = cast(StandardDomain, env.get_domain('std'))
|
||||
std._note_term(termtext, node_id, location=term)
|
||||
@ -344,7 +329,7 @@ class Glossary(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'sorted': directives.flag,
|
||||
}
|
||||
|
||||
@ -358,11 +343,11 @@ class Glossary(SphinxDirective):
|
||||
# be* a definition list.
|
||||
|
||||
# first, collect single entries
|
||||
entries = [] # type: List[Tuple[List[Tuple[str, str, int]], StringList]]
|
||||
entries: List[Tuple[List[Tuple[str, str, int]], StringList]] = []
|
||||
in_definition = True
|
||||
in_comment = False
|
||||
was_empty = True
|
||||
messages = [] # type: List[Node]
|
||||
messages: List[Node] = []
|
||||
for line, (source, lineno) in zip(self.content, self.content.items):
|
||||
# empty line -> add to last definition
|
||||
if not line:
|
||||
@ -417,9 +402,9 @@ class Glossary(SphinxDirective):
|
||||
# now, parse all the entries into a big definition list
|
||||
items = []
|
||||
for terms, definition in entries:
|
||||
termtexts = [] # type: List[str]
|
||||
termnodes = [] # type: List[Node]
|
||||
system_messages = [] # type: List[Node]
|
||||
termtexts: List[str] = []
|
||||
termnodes: List[Node] = []
|
||||
system_messages: List[Node] = []
|
||||
for line, source, lineno in terms:
|
||||
parts = split_term_classifiers(line)
|
||||
# parse the term with inline markup
|
||||
@ -428,7 +413,7 @@ class Glossary(SphinxDirective):
|
||||
|
||||
# use first classifier as a index key
|
||||
term = make_glossary_term(self.env, textnodes, parts[1], source, lineno,
|
||||
document=self.state.document)
|
||||
node_id=None, document=self.state.document)
|
||||
term.rawsource = line
|
||||
system_messages.extend(sysmsg)
|
||||
termtexts.append(term.astext())
|
||||
@ -458,7 +443,7 @@ class Glossary(SphinxDirective):
|
||||
def token_xrefs(text: str, productionGroup: str = '') -> List[Node]:
|
||||
if len(productionGroup) != 0:
|
||||
productionGroup += ':'
|
||||
retnodes = [] # type: List[Node]
|
||||
retnodes: List[Node] = []
|
||||
pos = 0
|
||||
for m in token_re.finditer(text):
|
||||
if m.start() > pos:
|
||||
@ -497,11 +482,11 @@ class ProductionList(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
domain = cast(StandardDomain, self.env.get_domain('std'))
|
||||
node = addnodes.productionlist() # type: Element
|
||||
node: Element = addnodes.productionlist()
|
||||
self.set_source_info(node)
|
||||
# The backslash handling is from ObjectDescription.get_signatures
|
||||
nl_escape_re = re.compile(r'\\\n')
|
||||
@ -574,7 +559,7 @@ class StandardDomain(Domain):
|
||||
name = 'std'
|
||||
label = 'Default'
|
||||
|
||||
object_types = {
|
||||
object_types: Dict[str, ObjType] = {
|
||||
'term': ObjType(_('glossary term'), 'term', searchprio=-1),
|
||||
'token': ObjType(_('grammar token'), 'token', searchprio=-1),
|
||||
'label': ObjType(_('reference label'), 'ref', 'keyword',
|
||||
@ -582,17 +567,17 @@ class StandardDomain(Domain):
|
||||
'envvar': ObjType(_('environment variable'), 'envvar'),
|
||||
'cmdoption': ObjType(_('program option'), 'option'),
|
||||
'doc': ObjType(_('document'), 'doc', searchprio=-1)
|
||||
} # type: Dict[str, ObjType]
|
||||
}
|
||||
|
||||
directives = {
|
||||
directives: Dict[str, Type[Directive]] = {
|
||||
'program': Program,
|
||||
'cmdoption': Cmdoption, # old name for backwards compatibility
|
||||
'option': Cmdoption,
|
||||
'envvar': EnvVar,
|
||||
'glossary': Glossary,
|
||||
'productionlist': ProductionList,
|
||||
} # type: Dict[str, Type[Directive]]
|
||||
roles = {
|
||||
}
|
||||
roles: Dict[str, Union[RoleFunction, XRefRole]] = {
|
||||
'option': OptionXRefRole(warn_dangling=True),
|
||||
'envvar': EnvVarXRefRole(),
|
||||
# links to tokens in grammar productions
|
||||
@ -610,7 +595,7 @@ class StandardDomain(Domain):
|
||||
'keyword': XRefRole(warn_dangling=True),
|
||||
# links to documents
|
||||
'doc': XRefRole(warn_dangling=True, innernodeclass=nodes.inline),
|
||||
} # type: Dict[str, Union[RoleFunction, XRefRole]]
|
||||
}
|
||||
|
||||
initial_data = {
|
||||
'progoptions': {}, # (program, name) -> docname, labelid
|
||||
@ -635,11 +620,12 @@ class StandardDomain(Domain):
|
||||
'option': 'unknown option: %(target)s',
|
||||
}
|
||||
|
||||
enumerable_nodes = { # node_class -> (figtype, title_getter)
|
||||
# node_class -> (figtype, title_getter)
|
||||
enumerable_nodes: Dict[Type[Node], Tuple[str, Callable]] = {
|
||||
nodes.figure: ('figure', None),
|
||||
nodes.table: ('table', None),
|
||||
nodes.container: ('code-block', None),
|
||||
} # type: Dict[Type[Node], Tuple[str, Callable]]
|
||||
}
|
||||
|
||||
def __init__(self, env: "BuildEnvironment") -> None:
|
||||
super().__init__(env)
|
||||
@ -721,7 +707,7 @@ class StandardDomain(Domain):
|
||||
return self.data.setdefault('anonlabels', {}) # labelname -> docname, labelid
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
key = None # type: Any
|
||||
key: Any = None
|
||||
for key, (fn, _l) in list(self.progoptions.items()):
|
||||
if fn == docname:
|
||||
del self.progoptions[key]
|
||||
@ -837,11 +823,6 @@ class StandardDomain(Domain):
|
||||
resolver = self._resolve_doc_xref
|
||||
elif typ == 'option':
|
||||
resolver = self._resolve_option_xref
|
||||
elif typ == 'citation':
|
||||
warnings.warn('pending_xref(domain=std, type=citation) is deprecated: %r' % node,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
domain = env.get_domain('citation')
|
||||
return domain.resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
|
||||
elif typ == 'term':
|
||||
resolver = self._resolve_term_xref
|
||||
else:
|
||||
@ -1012,7 +993,7 @@ class StandardDomain(Domain):
|
||||
def resolve_any_xref(self, env: "BuildEnvironment", fromdocname: str,
|
||||
builder: "Builder", target: str, node: pending_xref,
|
||||
contnode: Element) -> List[Tuple[str, Element]]:
|
||||
results = [] # type: List[Tuple[str, Element]]
|
||||
results: List[Tuple[str, Element]] = []
|
||||
ltarget = target.lower() # :ref: lowercases its target automatically
|
||||
for role in ('ref', 'option'): # do not try "keyword"
|
||||
res = self.resolve_xref(env, fromdocname, builder, role,
|
||||
@ -1076,7 +1057,7 @@ class StandardDomain(Domain):
|
||||
|
||||
def get_enumerable_node_type(self, node: Node) -> str:
|
||||
"""Get type of enumerable nodes."""
|
||||
def has_child(node: Element, cls: "Type") -> bool:
|
||||
def has_child(node: Element, cls: Type) -> bool:
|
||||
return any(isinstance(child, cls) for child in node)
|
||||
|
||||
if isinstance(node, nodes.section):
|
||||
@ -1127,18 +1108,6 @@ class StandardDomain(Domain):
|
||||
else:
|
||||
return None
|
||||
|
||||
def note_citations(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
|
||||
warnings.warn('StandardDomain.note_citations() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
def note_citation_refs(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
|
||||
warnings.warn('StandardDomain.note_citation_refs() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
def note_labels(self, env: "BuildEnvironment", docname: str, document: nodes.document) -> None: # NOQA
|
||||
warnings.warn('StandardDomain.note_labels() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
|
||||
def warn_missing_reference(app: "Sphinx", domain: Domain, node: pending_xref) -> bool:
|
||||
if (domain and domain.name != 'std') or node['reftype'] != 'ref':
|
||||
|
@ -10,18 +10,18 @@
|
||||
|
||||
import os
|
||||
import pickle
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from copy import copy
|
||||
from datetime import datetime
|
||||
from os import path
|
||||
from typing import Any, Callable, Dict, Generator, Iterator, List, Set, Tuple, Union, cast
|
||||
from typing import (TYPE_CHECKING, Any, Callable, Dict, Generator, Iterator, List, Set, Tuple,
|
||||
Union)
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.errors import BuildEnvironmentError, DocumentError, ExtensionError, SphinxError
|
||||
@ -35,15 +35,14 @@ from sphinx.util.i18n import CatalogRepository, docname_to_domain
|
||||
from sphinx.util.nodes import is_translatable
|
||||
from sphinx.util.osutil import canon_path, os_path
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
default_settings = {
|
||||
default_settings: Dict[str, Any] = {
|
||||
'embed_stylesheet': False,
|
||||
'cloak_email_addresses': True,
|
||||
'pep_base_url': 'https://www.python.org/dev/peps/',
|
||||
@ -56,7 +55,7 @@ default_settings = {
|
||||
'halt_level': 5,
|
||||
'file_insertion_enabled': True,
|
||||
'smartquotes_locales': [],
|
||||
} # type: Dict[str, Any]
|
||||
}
|
||||
|
||||
# This is increased every time an environment attribute is added
|
||||
# or changed to properly invalidate pickle files.
|
||||
@ -75,10 +74,10 @@ CONFIG_CHANGED_REASON = {
|
||||
}
|
||||
|
||||
|
||||
versioning_conditions = {
|
||||
versioning_conditions: Dict[str, Union[bool, Callable]] = {
|
||||
'none': False,
|
||||
'text': is_translatable,
|
||||
} # type: Dict[str, Union[bool, Callable]]
|
||||
}
|
||||
|
||||
|
||||
class BuildEnvironment:
|
||||
@ -88,24 +87,24 @@ class BuildEnvironment:
|
||||
transformations to resolve links to them.
|
||||
"""
|
||||
|
||||
domains = None # type: Dict[str, Domain]
|
||||
domains: Dict[str, Domain] = None
|
||||
|
||||
# --------- ENVIRONMENT INITIALIZATION -------------------------------------
|
||||
|
||||
def __init__(self, app: "Sphinx" = None):
|
||||
self.app = None # type: Sphinx
|
||||
self.doctreedir = None # type: str
|
||||
self.srcdir = None # type: str
|
||||
self.config = None # type: Config
|
||||
self.config_status = None # type: int
|
||||
self.config_status_extra = None # type: str
|
||||
self.events = None # type: EventManager
|
||||
self.project = None # type: Project
|
||||
self.version = None # type: Dict[str, str]
|
||||
self.app: Sphinx = None
|
||||
self.doctreedir: str = None
|
||||
self.srcdir: str = None
|
||||
self.config: Config = None
|
||||
self.config_status: int = None
|
||||
self.config_status_extra: str = None
|
||||
self.events: EventManager = None
|
||||
self.project: Project = None
|
||||
self.version: Dict[str, str] = None
|
||||
|
||||
# the method of doctree versioning; see set_versioning_method
|
||||
self.versioning_condition = None # type: Union[bool, Callable]
|
||||
self.versioning_compare = None # type: bool
|
||||
self.versioning_condition: Union[bool, Callable] = None
|
||||
self.versioning_compare: bool = None
|
||||
|
||||
# all the registered domains, set by the application
|
||||
self.domains = {}
|
||||
@ -117,70 +116,67 @@ class BuildEnvironment:
|
||||
# All "docnames" here are /-separated and relative and exclude
|
||||
# the source suffix.
|
||||
|
||||
self.all_docs = {} # type: Dict[str, float]
|
||||
# docname -> mtime at the time of reading
|
||||
# contains all read docnames
|
||||
self.dependencies = defaultdict(set) # type: Dict[str, Set[str]]
|
||||
# docname -> set of dependent file
|
||||
# names, relative to documentation root
|
||||
self.included = defaultdict(set) # type: Dict[str, Set[str]]
|
||||
# docname -> set of included file
|
||||
# docnames included from other documents
|
||||
self.reread_always = set() # type: Set[str]
|
||||
# docnames to re-read unconditionally on
|
||||
# next build
|
||||
# docname -> mtime at the time of reading
|
||||
# contains all read docnames
|
||||
self.all_docs: Dict[str, float] = {}
|
||||
# docname -> set of dependent file
|
||||
# names, relative to documentation root
|
||||
self.dependencies: Dict[str, Set[str]] = defaultdict(set)
|
||||
# docname -> set of included file
|
||||
# docnames included from other documents
|
||||
self.included: Dict[str, Set[str]] = defaultdict(set)
|
||||
# docnames to re-read unconditionally on next build
|
||||
self.reread_always: Set[str] = set()
|
||||
|
||||
# File metadata
|
||||
self.metadata = defaultdict(dict) # type: Dict[str, Dict[str, Any]]
|
||||
# docname -> dict of metadata items
|
||||
# docname -> dict of metadata items
|
||||
self.metadata: Dict[str, Dict[str, Any]] = defaultdict(dict)
|
||||
|
||||
# TOC inventory
|
||||
self.titles = {} # type: Dict[str, nodes.title]
|
||||
# docname -> title node
|
||||
self.longtitles = {} # type: Dict[str, nodes.title]
|
||||
# docname -> title node; only different if
|
||||
# set differently with title directive
|
||||
self.tocs = {} # type: Dict[str, nodes.bullet_list]
|
||||
# docname -> table of contents nodetree
|
||||
self.toc_num_entries = {} # type: Dict[str, int]
|
||||
# docname -> number of real entries
|
||||
# docname -> title node
|
||||
self.titles: Dict[str, nodes.title] = {}
|
||||
# docname -> title node; only different if
|
||||
# set differently with title directive
|
||||
self.longtitles: Dict[str, nodes.title] = {}
|
||||
# docname -> table of contents nodetree
|
||||
self.tocs: Dict[str, nodes.bullet_list] = {}
|
||||
# docname -> number of real entries
|
||||
self.toc_num_entries: Dict[str, int] = {}
|
||||
|
||||
# used to determine when to show the TOC
|
||||
# in a sidebar (don't show if it's only one item)
|
||||
self.toc_secnumbers = {} # type: Dict[str, Dict[str, Tuple[int, ...]]]
|
||||
# docname -> dict of sectionid -> number
|
||||
self.toc_fignumbers = {} # type: Dict[str, Dict[str, Dict[str, Tuple[int, ...]]]]
|
||||
# docname -> dict of figtype ->
|
||||
# dict of figureid -> number
|
||||
# docname -> dict of sectionid -> number
|
||||
self.toc_secnumbers: Dict[str, Dict[str, Tuple[int, ...]]] = {}
|
||||
# docname -> dict of figtype -> dict of figureid -> number
|
||||
self.toc_fignumbers: Dict[str, Dict[str, Dict[str, Tuple[int, ...]]]] = {}
|
||||
|
||||
self.toctree_includes = {} # type: Dict[str, List[str]]
|
||||
# docname -> list of toctree includefiles
|
||||
self.files_to_rebuild = {} # type: Dict[str, Set[str]]
|
||||
# docname -> set of files
|
||||
# (containing its TOCs) to rebuild too
|
||||
self.glob_toctrees = set() # type: Set[str]
|
||||
# docnames that have :glob: toctrees
|
||||
self.numbered_toctrees = set() # type: Set[str]
|
||||
# docnames that have :numbered: toctrees
|
||||
# docname -> list of toctree includefiles
|
||||
self.toctree_includes: Dict[str, List[str]] = {}
|
||||
# docname -> set of files (containing its TOCs) to rebuild too
|
||||
self.files_to_rebuild: Dict[str, Set[str]] = {}
|
||||
# docnames that have :glob: toctrees
|
||||
self.glob_toctrees: Set[str] = set()
|
||||
# docnames that have :numbered: toctrees
|
||||
self.numbered_toctrees: Set[str] = set()
|
||||
|
||||
# domain-specific inventories, here to be pickled
|
||||
self.domaindata = {} # type: Dict[str, Dict]
|
||||
# domainname -> domain-specific dict
|
||||
# domainname -> domain-specific dict
|
||||
self.domaindata: Dict[str, Dict] = {}
|
||||
|
||||
# these map absolute path -> (docnames, unique filename)
|
||||
self.images = FilenameUniqDict() # type: FilenameUniqDict
|
||||
self.dlfiles = DownloadFiles() # type: DownloadFiles
|
||||
# filename -> (set of docnames, destination)
|
||||
self.images: FilenameUniqDict = FilenameUniqDict()
|
||||
# filename -> (set of docnames, destination)
|
||||
self.dlfiles: DownloadFiles = DownloadFiles()
|
||||
|
||||
# the original URI for images
|
||||
self.original_image_uri = {} # type: Dict[str, str]
|
||||
self.original_image_uri: Dict[str, str] = {}
|
||||
|
||||
# temporary data storage while reading a document
|
||||
self.temp_data = {} # type: Dict[str, Any]
|
||||
self.temp_data: Dict[str, Any] = {}
|
||||
# context for cross-references (e.g. current module or class)
|
||||
# this is similar to temp_data, but will for example be copied to
|
||||
# attributes of "any" cross references
|
||||
self.ref_context = {} # type: Dict[str, Any]
|
||||
self.ref_context: Dict[str, Any] = {}
|
||||
|
||||
# set up environment
|
||||
if app:
|
||||
@ -270,7 +266,7 @@ class BuildEnvironment:
|
||||
raise an exception if the user tries to use an environment with an
|
||||
incompatible versioning method.
|
||||
"""
|
||||
condition = None # type: Union[bool, Callable]
|
||||
condition: Union[bool, Callable] = None
|
||||
if callable(method):
|
||||
condition = method
|
||||
else:
|
||||
@ -320,28 +316,13 @@ class BuildEnvironment:
|
||||
"""
|
||||
return self.project.path2doc(filename)
|
||||
|
||||
def doc2path(self, docname: str, base: Union[bool, str] = True, suffix: str = None) -> str:
|
||||
def doc2path(self, docname: str, base: bool = True) -> str:
|
||||
"""Return the filename for the document name.
|
||||
|
||||
If *base* is True, return absolute path under self.srcdir.
|
||||
If *base* is None, return relative path to self.srcdir.
|
||||
If *base* is a path string, return absolute path under that.
|
||||
If *suffix* is not None, add it instead of config.source_suffix.
|
||||
If *base* is False, return relative path to self.srcdir.
|
||||
"""
|
||||
if suffix:
|
||||
warnings.warn('The suffix argument for doc2path() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
if base not in (True, False, None):
|
||||
warnings.warn('The string style base argument for doc2path() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
pathname = self.project.doc2path(docname, base is True)
|
||||
if suffix:
|
||||
filename, _ = path.splitext(pathname)
|
||||
pathname = filename + suffix
|
||||
if base and base is not True:
|
||||
pathname = path.join(base, pathname) # type: ignore
|
||||
return pathname
|
||||
return self.project.doc2path(docname, base)
|
||||
|
||||
def relfn2path(self, filename: str, docname: str = None) -> Tuple[str, str]:
|
||||
"""Return paths to a file referenced from a document, relative to
|
||||
@ -401,8 +382,8 @@ class BuildEnvironment:
|
||||
# clear all files no longer present
|
||||
removed = set(self.all_docs) - self.found_docs
|
||||
|
||||
added = set() # type: Set[str]
|
||||
changed = set() # type: Set[str]
|
||||
added: Set[str] = set()
|
||||
changed: Set[str] = set()
|
||||
|
||||
if config_changed:
|
||||
# config values affect e.g. substitutions
|
||||
@ -410,21 +391,28 @@ class BuildEnvironment:
|
||||
else:
|
||||
for docname in self.found_docs:
|
||||
if docname not in self.all_docs:
|
||||
logger.debug('[build target] added %r', docname)
|
||||
added.add(docname)
|
||||
continue
|
||||
# if the doctree file is not there, rebuild
|
||||
filename = path.join(self.doctreedir, docname + '.doctree')
|
||||
if not path.isfile(filename):
|
||||
logger.debug('[build target] changed %r', docname)
|
||||
changed.add(docname)
|
||||
continue
|
||||
# check the "reread always" list
|
||||
if docname in self.reread_always:
|
||||
logger.debug('[build target] changed %r', docname)
|
||||
changed.add(docname)
|
||||
continue
|
||||
# check the mtime of the document
|
||||
mtime = self.all_docs[docname]
|
||||
newmtime = path.getmtime(self.doc2path(docname))
|
||||
if newmtime > mtime:
|
||||
logger.debug('[build target] outdated %r: %s -> %s',
|
||||
docname,
|
||||
datetime.utcfromtimestamp(mtime),
|
||||
datetime.utcfromtimestamp(newmtime))
|
||||
changed.add(docname)
|
||||
continue
|
||||
# finally, check the mtime of dependencies
|
||||
@ -447,7 +435,7 @@ class BuildEnvironment:
|
||||
return added, changed, removed
|
||||
|
||||
def check_dependents(self, app: "Sphinx", already: Set[str]) -> Generator[str, None, None]:
|
||||
to_rewrite = [] # type: List[str]
|
||||
to_rewrite: List[str] = []
|
||||
for docnames in self.events.emit('env-get-updated', self):
|
||||
to_rewrite.extend(docnames)
|
||||
for docname in set(to_rewrite):
|
||||
@ -610,7 +598,7 @@ class BuildEnvironment:
|
||||
traversed.add(subdocname)
|
||||
|
||||
relations = {}
|
||||
docnames = traverse_toctree(None, self.config.master_doc)
|
||||
docnames = traverse_toctree(None, self.config.root_doc)
|
||||
prevdoc = None
|
||||
parent, docname = next(docnames)
|
||||
for nextparent, nextdoc in docnames:
|
||||
@ -628,7 +616,7 @@ class BuildEnvironment:
|
||||
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:
|
||||
if docname == self.config.root_doc:
|
||||
# the master file is not included anywhere ;)
|
||||
continue
|
||||
if docname in included:
|
||||
@ -643,19 +631,3 @@ class BuildEnvironment:
|
||||
for domain in self.domains.values():
|
||||
domain.check_consistency()
|
||||
self.events.emit('env-check-consistency', self)
|
||||
|
||||
@property
|
||||
def indexentries(self) -> Dict[str, List[Tuple[str, str, str, str, str]]]:
|
||||
warnings.warn('env.indexentries() is deprecated. Please use IndexDomain instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
from sphinx.domains.index import IndexDomain
|
||||
domain = cast(IndexDomain, self.get_domain('index'))
|
||||
return domain.entries
|
||||
|
||||
@indexentries.setter
|
||||
def indexentries(self, entries: Dict[str, List[Tuple[str, str, str, str, str]]]) -> None:
|
||||
warnings.warn('env.indexentries() is deprecated. Please use IndexDomain instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
from sphinx.domains.index import IndexDomain
|
||||
domain = cast(IndexDomain, self.get_domain('index'))
|
||||
domain.data['entries'] = entries
|
||||
|
@ -31,7 +31,7 @@ class IndexEntries:
|
||||
_fixre: Pattern = re.compile(r'(.*) ([(][^()]*[)])')
|
||||
) -> List[Tuple[str, List[Tuple[str, Any]]]]:
|
||||
"""Create the real index from the collected index entries."""
|
||||
new = {} # type: Dict[str, List]
|
||||
new: Dict[str, List] = {}
|
||||
|
||||
def add_entry(word: str, subword: str, main: str, link: bool = True,
|
||||
dic: Dict = new, key: str = None) -> None:
|
||||
@ -126,7 +126,7 @@ class IndexEntries:
|
||||
# (in module foo)
|
||||
# (in module bar)
|
||||
oldkey = ''
|
||||
oldsubitems = None # type: Dict[str, List]
|
||||
oldsubitems: Dict[str, List] = None
|
||||
i = 0
|
||||
while i < len(newlist):
|
||||
key, (targets, subitems, _key) = newlist[i]
|
||||
|
@ -8,7 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Iterable, List, cast
|
||||
from typing import TYPE_CHECKING, Any, Iterable, List, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
@ -19,8 +19,7 @@ from sphinx.util import logging, url_re
|
||||
from sphinx.util.matching import Matcher
|
||||
from sphinx.util.nodes import clean_astext, process_only_nodes
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
@ -103,7 +102,7 @@ class TocTree:
|
||||
if not subnode['anchorname']:
|
||||
# give the whole branch a 'current' class
|
||||
# (useful for styling it differently)
|
||||
branchnode = subnode # type: Element
|
||||
branchnode: Element = subnode
|
||||
while branchnode:
|
||||
branchnode['classes'].append('current')
|
||||
branchnode = branchnode.parent
|
||||
@ -120,7 +119,7 @@ class TocTree:
|
||||
) -> List[Element]:
|
||||
"""Return TOC entries for a toctree node."""
|
||||
refs = [(e[0], e[1]) for e in toctreenode['entries']]
|
||||
entries = [] # type: List[Element]
|
||||
entries: List[Element] = []
|
||||
for (title, ref) in refs:
|
||||
try:
|
||||
refdoc = None
|
||||
@ -237,7 +236,7 @@ class TocTree:
|
||||
newnode = addnodes.compact_paragraph('', '')
|
||||
caption = toctree.attributes.get('caption')
|
||||
if caption:
|
||||
caption_node = nodes.caption(caption, '', *[nodes.Text(caption)])
|
||||
caption_node = nodes.title(caption, '', *[nodes.Text(caption)])
|
||||
caption_node.line = toctree.line
|
||||
caption_node.source = toctree.source
|
||||
caption_node.rawsource = toctree['rawcaption']
|
||||
@ -269,7 +268,7 @@ class TocTree:
|
||||
for p, children in self.env.toctree_includes.items():
|
||||
for child in children:
|
||||
parent[child] = p
|
||||
ancestors = [] # type: List[str]
|
||||
ancestors: List[str] = []
|
||||
d = docname
|
||||
while d in parent and d not in ancestors:
|
||||
ancestors.append(d)
|
||||
@ -316,8 +315,8 @@ class TocTree:
|
||||
def get_toctree_for(self, docname: str, builder: "Builder", collapse: bool,
|
||||
**kwargs: Any) -> Element:
|
||||
"""Return the global TOC nodetree."""
|
||||
doctree = self.env.get_doctree(self.env.config.master_doc)
|
||||
toctrees = [] # type: List[Element]
|
||||
doctree = self.env.get_doctree(self.env.config.root_doc)
|
||||
toctrees: List[Element] = []
|
||||
if 'includehidden' not in kwargs:
|
||||
kwargs['includehidden'] = True
|
||||
if 'maxdepth' not in kwargs or not kwargs['maxdepth']:
|
||||
|
@ -8,14 +8,13 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Set
|
||||
from typing import TYPE_CHECKING, Dict, List, Set
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -28,7 +27,7 @@ class EnvironmentCollector:
|
||||
entries and toctrees, etc.
|
||||
"""
|
||||
|
||||
listener_ids = None # type: Dict[str, int]
|
||||
listener_ids: Dict[str, int] = None
|
||||
|
||||
def enable(self, app: "Sphinx") -> None:
|
||||
assert self.listener_ids is None
|
||||
|
@ -48,7 +48,7 @@ class ImageCollector(EnvironmentCollector):
|
||||
# choose the best image from these candidates. The special key * is
|
||||
# set if there is only single candidate to be used by a writer.
|
||||
# The special key ? is set for nonlocal URIs.
|
||||
candidates = {} # type: Dict[str, str]
|
||||
candidates: Dict[str, str] = {}
|
||||
node['candidates'] = candidates
|
||||
imguri = node['uri']
|
||||
if imguri.startswith('data:'):
|
||||
@ -94,7 +94,7 @@ class ImageCollector(EnvironmentCollector):
|
||||
|
||||
def collect_candidates(self, env: BuildEnvironment, imgpath: str,
|
||||
candidates: Dict[str, str], node: Node) -> None:
|
||||
globbed = {} # type: Dict[str, List[str]]
|
||||
globbed: Dict[str, List[str]] = {}
|
||||
for filename in glob(imgpath):
|
||||
new_imgpath = relative_path(path.join(env.srcdir, 'dummy'),
|
||||
filename)
|
||||
|
@ -1,63 +0,0 @@
|
||||
"""
|
||||
sphinx.environment.collectors.indexentries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Index entries collector for sphinx.environment.
|
||||
|
||||
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict, Set
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment.collectors import EnvironmentCollector
|
||||
from sphinx.util import logging, split_index_msg
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IndexEntriesCollector(EnvironmentCollector):
|
||||
name = 'indices'
|
||||
|
||||
def __init__(self) -> None:
|
||||
warnings.warn('IndexEntriesCollector is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
def clear_doc(self, app: Sphinx, env: BuildEnvironment, docname: str) -> None:
|
||||
env.indexentries.pop(docname, None)
|
||||
|
||||
def merge_other(self, app: Sphinx, env: BuildEnvironment,
|
||||
docnames: Set[str], other: BuildEnvironment) -> None:
|
||||
for docname in docnames:
|
||||
env.indexentries[docname] = other.indexentries[docname]
|
||||
|
||||
def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
|
||||
docname = app.env.docname
|
||||
entries = app.env.indexentries[docname] = []
|
||||
for node in doctree.traverse(addnodes.index):
|
||||
try:
|
||||
for entry in node['entries']:
|
||||
split_index_msg(entry[0], entry[1])
|
||||
except ValueError as exc:
|
||||
logger.warning(str(exc), location=node)
|
||||
node.parent.remove(node)
|
||||
else:
|
||||
for entry in node['entries']:
|
||||
entries.append(entry)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_env_collector(IndexEntriesCollector)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
@ -50,7 +50,7 @@ class TitleCollector(EnvironmentCollector):
|
||||
break
|
||||
else:
|
||||
# document has no title
|
||||
titlenode += nodes.Text('<no title>')
|
||||
titlenode += nodes.Text(doctree.get('title', '<no title>'))
|
||||
app.env.titles[app.env.docname] = titlenode
|
||||
app.env.longtitles[app.env.docname] = longtitlenode
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Set, Tuple, TypeVar, cast
|
||||
from typing import Any, Dict, List, Set, Tuple, Type, TypeVar, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
@ -22,11 +22,6 @@ from sphinx.locale import __
|
||||
from sphinx.transforms import SphinxContentsFilter
|
||||
from sphinx.util import logging, url_re
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
N = TypeVar('N')
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -67,9 +62,9 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
docname = app.env.docname
|
||||
numentries = [0] # nonlocal again...
|
||||
|
||||
def traverse_in_section(node: Element, cls: "Type[N]") -> List[N]:
|
||||
def traverse_in_section(node: Element, cls: Type[N]) -> List[N]:
|
||||
"""Like traverse(), but stay within the same section."""
|
||||
result = [] # type: List[N]
|
||||
result: List[N] = []
|
||||
if isinstance(node, cls):
|
||||
result.append(node)
|
||||
for child in node.children:
|
||||
@ -80,7 +75,7 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
return result
|
||||
|
||||
def build_toc(node: Element, depth: int = 1) -> nodes.bullet_list:
|
||||
entries = [] # type: List[Element]
|
||||
entries: List[Element] = []
|
||||
for sectionnode in node:
|
||||
# find all toctree nodes in this section and add them
|
||||
# to the toc (just copying the toctree node which is then
|
||||
@ -105,7 +100,7 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
'', '', internal=True, refuri=docname,
|
||||
anchorname=anchorname, *nodetext)
|
||||
para = addnodes.compact_paragraph('', '', reference)
|
||||
item = nodes.list_item('', para) # type: Element
|
||||
item: Element = nodes.list_item('', para)
|
||||
sub_item = build_toc(sectionnode, depth + 1)
|
||||
if sub_item:
|
||||
item += sub_item
|
||||
@ -141,7 +136,7 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
# a list of all docnames whose section numbers changed
|
||||
rewrite_needed = []
|
||||
|
||||
assigned = set() # type: Set[str]
|
||||
assigned: Set[str] = set()
|
||||
old_secnumbers = env.toc_secnumbers
|
||||
env.toc_secnumbers = {}
|
||||
|
||||
@ -191,7 +186,7 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
'(nested numbered toctree?)'), ref,
|
||||
location=toctreenode, type='toc', subtype='secnum')
|
||||
elif ref in env.tocs:
|
||||
secnums = {} # type: Dict[str, Tuple[int, ...]]
|
||||
secnums: Dict[str, Tuple[int, ...]] = {}
|
||||
env.toc_secnumbers[ref] = secnums
|
||||
assigned.add(ref)
|
||||
_walk_toc(env.tocs[ref], secnums, depth, env.titles.get(ref))
|
||||
@ -215,10 +210,10 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
|
||||
rewrite_needed = []
|
||||
|
||||
assigned = set() # type: Set[str]
|
||||
assigned: Set[str] = set()
|
||||
old_fignumbers = env.toc_fignumbers
|
||||
env.toc_fignumbers = {}
|
||||
fignum_counter = {} # type: Dict[str, Dict[Tuple[int, ...], int]]
|
||||
fignum_counter: Dict[str, Dict[Tuple[int, ...], int]] = {}
|
||||
|
||||
def get_figtype(node: Node) -> str:
|
||||
for domain in env.domains.values():
|
||||
@ -286,7 +281,7 @@ class TocTreeCollector(EnvironmentCollector):
|
||||
_walk_doctree(docname, doctree, secnum)
|
||||
|
||||
if env.config.numfig:
|
||||
_walk_doc(env.config.master_doc, tuple())
|
||||
_walk_doc(env.config.root_doc, tuple())
|
||||
for docname, fignums in env.toc_fignumbers.items():
|
||||
if fignums != old_fignumbers.get(docname):
|
||||
rewrite_needed.append(docname)
|
||||
|
@ -10,29 +10,26 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from operator import attrgetter
|
||||
from typing import Any, Callable, Dict, List, NamedTuple, Tuple
|
||||
from typing import TYPE_CHECKING, Any, Callable, Dict, List, NamedTuple, Tuple, Type
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.errors import ExtensionError, SphinxError
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import safe_getattr
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
EventListener = NamedTuple('EventListener', [('id', int),
|
||||
('handler', Callable),
|
||||
('priority', int)])
|
||||
|
||||
class EventListener(NamedTuple):
|
||||
id: int
|
||||
handler: Callable
|
||||
priority: int
|
||||
|
||||
|
||||
# List of all known core events. Maps name to arguments description.
|
||||
@ -58,13 +55,10 @@ core_events = {
|
||||
class EventManager:
|
||||
"""Event manager for Sphinx."""
|
||||
|
||||
def __init__(self, app: "Sphinx" = None) -> None:
|
||||
if app is None:
|
||||
warnings.warn('app argument is required for EventManager.',
|
||||
RemovedInSphinx40Warning)
|
||||
def __init__(self, app: "Sphinx") -> None:
|
||||
self.app = app
|
||||
self.events = core_events.copy()
|
||||
self.listeners = defaultdict(list) # type: Dict[str, List[EventListener]]
|
||||
self.listeners: Dict[str, List[EventListener]] = defaultdict(list)
|
||||
self.next_listener_id = 0
|
||||
|
||||
def add(self, name: str) -> None:
|
||||
@ -91,7 +85,7 @@ class EventManager:
|
||||
listeners.remove(listener)
|
||||
|
||||
def emit(self, name: str, *args: Any,
|
||||
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> List:
|
||||
allowed_exceptions: Tuple[Type[Exception], ...] = ()) -> List:
|
||||
"""Emit a Sphinx event."""
|
||||
try:
|
||||
logger.debug('[app] emitting event: %r%s', name, repr(args)[:100])
|
||||
@ -104,11 +98,7 @@ class EventManager:
|
||||
listeners = sorted(self.listeners[name], key=attrgetter("priority"))
|
||||
for listener in listeners:
|
||||
try:
|
||||
if self.app is None:
|
||||
# for compatibility; RemovedInSphinx40Warning
|
||||
results.append(listener.handler(*args))
|
||||
else:
|
||||
results.append(listener.handler(self.app, *args))
|
||||
results.append(listener.handler(self.app, *args))
|
||||
except allowed_exceptions:
|
||||
# pass through the errors specified as *allowed_exceptions*
|
||||
raise
|
||||
@ -121,7 +111,7 @@ class EventManager:
|
||||
return results
|
||||
|
||||
def emit_firstresult(self, name: str, *args: Any,
|
||||
allowed_exceptions: Tuple["Type[Exception]", ...] = ()) -> Any:
|
||||
allowed_exceptions: Tuple[Type[Exception], ...] = ()) -> Any:
|
||||
"""Emit a Sphinx event and returns first result.
|
||||
|
||||
This returns the result of the first handler that doesn't return ``None``.
|
||||
|
@ -19,7 +19,6 @@ import glob
|
||||
import locale
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
from copy import copy
|
||||
from fnmatch import fnmatch
|
||||
from importlib.machinery import EXTENSION_SUFFIXES
|
||||
@ -29,9 +28,7 @@ from typing import Any, Generator, List, Tuple
|
||||
import sphinx.locale
|
||||
from sphinx import __display_version__, package_dir
|
||||
from sphinx.cmd.quickstart import EXTENSIONS
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import rst
|
||||
from sphinx.util.osutil import FileAvoidWrite, ensuredir
|
||||
from sphinx.util.template import ReSTRenderer
|
||||
|
||||
@ -51,20 +48,6 @@ PY_SUFFIXES = ('.py', '.pyx') + tuple(EXTENSION_SUFFIXES)
|
||||
template_dir = path.join(package_dir, 'templates', 'apidoc')
|
||||
|
||||
|
||||
def makename(package: str, module: str) -> str:
|
||||
"""Join package and module with a dot."""
|
||||
warnings.warn('makename() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
# Both package and module can be None/empty.
|
||||
if package:
|
||||
name = package
|
||||
if module:
|
||||
name += '.' + module
|
||||
else:
|
||||
name = module
|
||||
return name
|
||||
|
||||
|
||||
def is_initpy(filename: str) -> bool:
|
||||
"""Check *filename* is __init__ file or not."""
|
||||
basename = path.basename(filename)
|
||||
@ -109,26 +92,6 @@ def write_file(name: str, text: str, opts: Any) -> None:
|
||||
f.write(text)
|
||||
|
||||
|
||||
def format_heading(level: int, text: str, escape: bool = True) -> str:
|
||||
"""Create a heading of <level> [1, 2 or 3 supported]."""
|
||||
warnings.warn('format_warning() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
if escape:
|
||||
text = rst.escape(text)
|
||||
underlining = ['=', '-', '~', ][level - 1] * len(text)
|
||||
return '%s\n%s\n\n' % (text, underlining)
|
||||
|
||||
|
||||
def format_directive(module: str, package: str = None) -> str:
|
||||
"""Create the automodule directive and add the options."""
|
||||
warnings.warn('format_directive() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
directive = '.. automodule:: %s\n' % module_join(package, module)
|
||||
for option in OPTIONS:
|
||||
directive += ' :%s:\n' % option
|
||||
return directive
|
||||
|
||||
|
||||
def create_module_file(package: str, basename: str, opts: Any,
|
||||
user_template_dir: str = None) -> None:
|
||||
"""Build the text of the file and write the file."""
|
||||
@ -206,33 +169,6 @@ def create_modules_toc_file(modules: List[str], opts: Any, name: str = 'modules'
|
||||
write_file(name, text, opts)
|
||||
|
||||
|
||||
def shall_skip(module: str, opts: Any, excludes: List[str] = []) -> bool:
|
||||
"""Check if we want to skip this module."""
|
||||
warnings.warn('shall_skip() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
# skip if the file doesn't exist and not using implicit namespaces
|
||||
if not opts.implicit_namespaces and not path.exists(module):
|
||||
return True
|
||||
|
||||
# Are we a package (here defined as __init__.py, not the folder in itself)
|
||||
if is_initpy(module):
|
||||
# Yes, check if we have any non-excluded modules at all here
|
||||
all_skipped = True
|
||||
basemodule = path.dirname(module)
|
||||
for submodule in glob.glob(path.join(basemodule, '*.py')):
|
||||
if not is_excluded(path.join(basemodule, submodule), excludes):
|
||||
# There's a non-excluded module here, we won't skip
|
||||
all_skipped = False
|
||||
if all_skipped:
|
||||
return True
|
||||
|
||||
# skip if it has a "private" name and this is selected
|
||||
filename = path.basename(module)
|
||||
if is_initpy(filename) and filename.startswith('_') and not opts.includeprivate:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_skipped_package(dirname: str, opts: Any, excludes: List[str] = []) -> bool:
|
||||
"""Check if we want to skip this module."""
|
||||
if not path.isdir(dirname):
|
||||
@ -279,7 +215,7 @@ def walk(rootpath: str, excludes: List[str], opts: Any
|
||||
# remove hidden ('.') and private ('_') directories, as well as
|
||||
# excluded dirs
|
||||
if includeprivate:
|
||||
exclude_prefixes = ('.',) # type: Tuple[str, ...]
|
||||
exclude_prefixes: Tuple[str, ...] = ('.',)
|
||||
else:
|
||||
exclude_prefixes = ('.', '_')
|
||||
|
||||
@ -536,13 +472,6 @@ def main(argv: List[str] = sys.argv[1:]) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
deprecated_alias('sphinx.ext.apidoc',
|
||||
{
|
||||
'INITPY': '__init__.py',
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
|
||||
|
||||
# So program can be started with "python -m sphinx.apidoc ..."
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -14,16 +14,15 @@ import re
|
||||
import warnings
|
||||
from inspect import Parameter, Signature
|
||||
from types import ModuleType
|
||||
from typing import (Any, Callable, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type,
|
||||
TypeVar, Union)
|
||||
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterator, List, Optional, Sequence,
|
||||
Set, Tuple, Type, TypeVar, Union)
|
||||
|
||||
from docutils.statemachine import StringList
|
||||
|
||||
import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,
|
||||
RemovedInSphinx60Warning)
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.ext.autodoc.importer import (get_class_members, get_object_members, import_module,
|
||||
import_object)
|
||||
@ -34,13 +33,10 @@ from sphinx.util import inspect, logging
|
||||
from sphinx.util.docstrings import extract_metadata, prepare_docstring
|
||||
from sphinx.util.inspect import (evaluate_signature, getdoc, object_description, safe_getattr,
|
||||
stringify_signature)
|
||||
from sphinx.util.typing import get_type_hints, restify
|
||||
from sphinx.util.typing import OptionSpec, get_type_hints, restify
|
||||
from sphinx.util.typing import stringify as stringify_typehint
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # NOQA # for python3.5.1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.ext.autodoc.directive import DocumenterBridge
|
||||
|
||||
|
||||
@ -313,7 +309,9 @@ class Documenter:
|
||||
#: true if the generated content may contain titles
|
||||
titles_allowed = False
|
||||
|
||||
option_spec = {'noindex': bool_option} # type: Dict[str, Callable]
|
||||
option_spec: OptionSpec = {
|
||||
'noindex': bool_option
|
||||
}
|
||||
|
||||
def get_attr(self, obj: Any, name: str, *defargs: Any) -> Any:
|
||||
"""getattr() override for types such as Zope interfaces."""
|
||||
@ -327,31 +325,31 @@ class Documenter:
|
||||
|
||||
def __init__(self, directive: "DocumenterBridge", name: str, indent: str = '') -> None:
|
||||
self.directive = directive
|
||||
self.config = directive.env.config
|
||||
self.env = directive.env # type: BuildEnvironment
|
||||
self.config: Config = directive.env.config
|
||||
self.env: BuildEnvironment = directive.env
|
||||
self.options = directive.genopt
|
||||
self.name = name
|
||||
self.indent = indent
|
||||
# the module and object path within the module, and the fully
|
||||
# qualified name (all set after resolve_name succeeds)
|
||||
self.modname = None # type: str
|
||||
self.module = None # type: ModuleType
|
||||
self.objpath = None # type: List[str]
|
||||
self.fullname = None # type: str
|
||||
self.modname: str = None
|
||||
self.module: ModuleType = None
|
||||
self.objpath: List[str] = None
|
||||
self.fullname: str = None
|
||||
# extra signature items (arguments and return annotation,
|
||||
# also set after resolve_name succeeds)
|
||||
self.args = None # type: str
|
||||
self.retann = None # type: str
|
||||
self.args: str = None
|
||||
self.retann: str = None
|
||||
# the object to document (set after import_object succeeds)
|
||||
self.object = None # type: Any
|
||||
self.object_name = None # type: str
|
||||
self.object: Any = None
|
||||
self.object_name: str = None
|
||||
# the parent/owner of the object to document
|
||||
self.parent = None # type: Any
|
||||
self.parent: Any = None
|
||||
# the module analyzer to get at attribute docs, or None
|
||||
self.analyzer = None # type: ModuleAnalyzer
|
||||
self.analyzer: ModuleAnalyzer = None
|
||||
|
||||
@property
|
||||
def documenters(self) -> Dict[str, "Type[Documenter]"]:
|
||||
def documenters(self) -> Dict[str, Type["Documenter"]]:
|
||||
"""Returns registered Documenter classes"""
|
||||
return self.env.app.registry.documenters
|
||||
|
||||
@ -540,16 +538,12 @@ class Documenter:
|
||||
# etc. don't support a prepended module name
|
||||
self.add_line(' :module: %s' % self.modname, sourcename)
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
"""Decode and return lines of the docstring(s) for the object.
|
||||
|
||||
When it returns None value, autodoc-process-docstring will not be called for this
|
||||
object.
|
||||
"""
|
||||
if encoding is not None:
|
||||
warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."
|
||||
% self.__class__.__name__,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
if ignore is not None:
|
||||
warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."
|
||||
% self.__class__.__name__,
|
||||
@ -828,7 +822,7 @@ class Documenter:
|
||||
members_check_module, members = self.get_object_members(want_all)
|
||||
|
||||
# document non-skipped members
|
||||
memberdocumenters = [] # type: List[Tuple[Documenter, bool]]
|
||||
memberdocumenters: List[Tuple[Documenter, bool]] = []
|
||||
for (mname, member, isattr) in self.filter_members(members, want_all):
|
||||
classes = [cls for cls in self.documenters.values()
|
||||
if cls.can_document_member(member, mname, isattr, self)]
|
||||
@ -910,7 +904,7 @@ class Documenter:
|
||||
# This is used for situations where you have a module that collects the
|
||||
# functions and classes of internal submodules.
|
||||
guess_modname = self.get_real_modname()
|
||||
self.real_modname = real_modname or guess_modname
|
||||
self.real_modname: str = real_modname or guess_modname
|
||||
|
||||
# try to also get a source code analyzer for attribute docs
|
||||
try:
|
||||
@ -924,15 +918,15 @@ class Documenter:
|
||||
self.analyzer = None
|
||||
# at least add the module.__file__ as a dependency
|
||||
if hasattr(self.module, '__file__') and self.module.__file__:
|
||||
self.directive.filename_set.add(self.module.__file__)
|
||||
self.directive.record_dependencies.add(self.module.__file__)
|
||||
else:
|
||||
self.directive.filename_set.add(self.analyzer.srcname)
|
||||
self.directive.record_dependencies.add(self.analyzer.srcname)
|
||||
|
||||
if self.real_modname != guess_modname:
|
||||
# Add module to dependency list if target object is defined in other module.
|
||||
try:
|
||||
analyzer = ModuleAnalyzer.for_module(guess_modname)
|
||||
self.directive.filename_set.add(analyzer.srcname)
|
||||
self.directive.record_dependencies.add(analyzer.srcname)
|
||||
except PycodeError:
|
||||
pass
|
||||
|
||||
@ -978,7 +972,7 @@ class ModuleDocumenter(Documenter):
|
||||
content_indent = ''
|
||||
titles_allowed = True
|
||||
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'members': members_option, 'undoc-members': bool_option,
|
||||
'noindex': bool_option, 'inherited-members': inherited_members_option,
|
||||
'show-inheritance': bool_option, 'synopsis': identity,
|
||||
@ -986,12 +980,12 @@ class ModuleDocumenter(Documenter):
|
||||
'member-order': member_order_option, 'exclude-members': exclude_members_option,
|
||||
'private-members': members_option, 'special-members': members_option,
|
||||
'imported-members': bool_option, 'ignore-module-all': bool_option
|
||||
} # type: Dict[str, Callable]
|
||||
}
|
||||
|
||||
def __init__(self, *args: Any) -> None:
|
||||
super().__init__(*args)
|
||||
merge_members_option(self.options)
|
||||
self.__all__ = None # type: Optional[Sequence[str]]
|
||||
self.__all__: Optional[Sequence[str]] = None
|
||||
|
||||
@classmethod
|
||||
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any
|
||||
@ -1048,7 +1042,7 @@ class ModuleDocumenter(Documenter):
|
||||
else:
|
||||
attr_docs = {}
|
||||
|
||||
members = {} # type: Dict[str, ObjectMember]
|
||||
members: Dict[str, ObjectMember] = {}
|
||||
for name in dir(self.object):
|
||||
try:
|
||||
value = safe_getattr(self.object, name, None)
|
||||
@ -1103,7 +1097,7 @@ class ModuleDocumenter(Documenter):
|
||||
# Sort by __all__
|
||||
def keyfunc(entry: Tuple[Documenter, bool]) -> int:
|
||||
name = entry[0].name.split('::')[1]
|
||||
if name in self.__all__:
|
||||
if self.__all__ and name in self.__all__:
|
||||
return self.__all__.index(name)
|
||||
else:
|
||||
return len(self.__all__)
|
||||
@ -1173,15 +1167,10 @@ class DocstringSignatureMixin:
|
||||
Mixin for FunctionDocumenter and MethodDocumenter to provide the
|
||||
feature of reading the signature from the docstring.
|
||||
"""
|
||||
_new_docstrings = None # type: List[List[str]]
|
||||
_signatures = None # type: List[str]
|
||||
|
||||
def _find_signature(self, encoding: str = None) -> Tuple[str, str]:
|
||||
if encoding is not None:
|
||||
warnings.warn("The 'encoding' argument to autodoc.%s._find_signature() is "
|
||||
"deprecated." % self.__class__.__name__,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
_new_docstrings: List[List[str]] = None
|
||||
_signatures: List[str] = None
|
||||
|
||||
def _find_signature(self) -> Tuple[str, str]:
|
||||
# candidates of the object name
|
||||
valid_names = [self.objpath[-1]] # type: ignore
|
||||
if isinstance(self, ClassDocumenter):
|
||||
@ -1202,20 +1191,17 @@ class DocstringSignatureMixin:
|
||||
break
|
||||
|
||||
if line.endswith('\\'):
|
||||
multiline = True
|
||||
line = line.rstrip('\\').rstrip()
|
||||
else:
|
||||
multiline = False
|
||||
|
||||
# match first line of docstring against signature RE
|
||||
match = py_ext_sig_re.match(line)
|
||||
if not match:
|
||||
continue
|
||||
break
|
||||
exmod, path, base, args, retann = match.groups()
|
||||
|
||||
# the base name must match ours
|
||||
if base not in valid_names:
|
||||
continue
|
||||
break
|
||||
|
||||
# re-prepare docstring to ignore more leading indentation
|
||||
tab_width = self.directive.state.document.settings.tab_width # type: ignore
|
||||
@ -1229,27 +1215,16 @@ class DocstringSignatureMixin:
|
||||
# subsequent signatures
|
||||
self._signatures.append("(%s) -> %s" % (args, retann))
|
||||
|
||||
if multiline:
|
||||
# the signature have multiple signatures on docstring
|
||||
continue
|
||||
else:
|
||||
# don't look any further
|
||||
break
|
||||
|
||||
if result:
|
||||
# finish the loop when signature found
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if encoding is not None:
|
||||
warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."
|
||||
% self.__class__.__name__,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
def get_doc(self, ignore: int = None) -> List[List[str]]:
|
||||
if self._new_docstrings is not None:
|
||||
return self._new_docstrings
|
||||
return super().get_doc(None, ignore) # type: ignore
|
||||
return super().get_doc(ignore) # type: ignore
|
||||
|
||||
def format_signature(self, **kwargs: Any) -> str:
|
||||
if self.args is None and self.config.autodoc_docstring_signature: # type: ignore
|
||||
@ -1436,16 +1411,16 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
||||
"""
|
||||
objtype = 'class'
|
||||
member_order = 20
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'members': members_option, 'undoc-members': bool_option,
|
||||
'noindex': bool_option, 'inherited-members': inherited_members_option,
|
||||
'show-inheritance': bool_option, 'member-order': member_order_option,
|
||||
'exclude-members': exclude_members_option,
|
||||
'private-members': members_option, 'special-members': members_option,
|
||||
} # type: Dict[str, Callable]
|
||||
}
|
||||
|
||||
_signature_class = None # type: Any
|
||||
_signature_method_name = None # type: str
|
||||
_signature_class: Any = None
|
||||
_signature_method_name: str = None
|
||||
|
||||
def __init__(self, *args: Any) -> None:
|
||||
super().__init__(*args)
|
||||
@ -1605,6 +1580,20 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
||||
|
||||
return []
|
||||
|
||||
def get_canonical_fullname(self) -> Optional[str]:
|
||||
__modname__ = safe_getattr(self.object, '__module__', self.modname)
|
||||
__qualname__ = safe_getattr(self.object, '__qualname__', None)
|
||||
if __qualname__ is None:
|
||||
__qualname__ = safe_getattr(self.object, '__name__', None)
|
||||
if __qualname__ and '<locals>' in __qualname__:
|
||||
# No valid qualname found if the object is defined as locals
|
||||
__qualname__ = None
|
||||
|
||||
if __modname__ and __qualname__:
|
||||
return '.'.join([__modname__, __qualname__])
|
||||
else:
|
||||
return None
|
||||
|
||||
def add_directive_header(self, sig: str) -> None:
|
||||
sourcename = self.get_sourcename()
|
||||
|
||||
@ -1615,6 +1604,10 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
||||
if self.analyzer and '.'.join(self.objpath) in self.analyzer.finals:
|
||||
self.add_line(' :final:', sourcename)
|
||||
|
||||
canonical_fullname = self.get_canonical_fullname()
|
||||
if not self.doc_as_attr and canonical_fullname and self.fullname != canonical_fullname:
|
||||
self.add_line(' :canonical: %s' % canonical_fullname, sourcename)
|
||||
|
||||
# add inheritance info, if wanted
|
||||
if not self.doc_as_attr and self.options.show_inheritance:
|
||||
sourcename = self.get_sourcename()
|
||||
@ -1649,11 +1642,7 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): # type:
|
||||
else:
|
||||
return False, [m for m in members.values() if m.class_ == self.object]
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if encoding is not None:
|
||||
warnings.warn("The 'encoding' argument to autodoc.%s.get_doc() is deprecated."
|
||||
% self.__class__.__name__,
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if self.doc_as_attr:
|
||||
# Don't show the docstring of the class when it is an alias.
|
||||
return None
|
||||
@ -1746,12 +1735,12 @@ class ExceptionDocumenter(ClassDocumenter):
|
||||
|
||||
class DataDocumenterMixinBase:
|
||||
# define types of instance variables
|
||||
config = None # type: Config
|
||||
env = None # type: BuildEnvironment
|
||||
modname = None # type: str
|
||||
parent = None # type: Any
|
||||
object = None # type: Any
|
||||
objpath = None # type: List[str]
|
||||
config: Config = None
|
||||
env: BuildEnvironment = None
|
||||
modname: str = None
|
||||
parent: Any = None
|
||||
object: Any = None
|
||||
objpath: List[str] = None
|
||||
|
||||
def should_suppress_directive_header(self) -> bool:
|
||||
"""Check directive header should be suppressed."""
|
||||
@ -1814,7 +1803,7 @@ class TypeVarMixin(DataDocumenterMixinBase):
|
||||
return (isinstance(self.object, TypeVar) or
|
||||
super().should_suppress_directive_header())
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if ignore is not None:
|
||||
warnings.warn("The 'ignore' argument to autodoc.%s.get_doc() is deprecated."
|
||||
% self.__class__.__name__,
|
||||
@ -1833,6 +1822,8 @@ class TypeVarMixin(DataDocumenterMixinBase):
|
||||
attrs = [repr(self.object.__name__)]
|
||||
for constraint in self.object.__constraints__:
|
||||
attrs.append(stringify_typehint(constraint))
|
||||
if self.object.__bound__:
|
||||
attrs.append(r"bound=\ " + restify(self.object.__bound__))
|
||||
if self.object.__covariant__:
|
||||
attrs.append("covariant=True")
|
||||
if self.object.__contravariant__:
|
||||
@ -1878,11 +1869,11 @@ class UninitializedGlobalVariableMixin(DataDocumenterMixinBase):
|
||||
return (self.object is UNINITIALIZED_ATTR or
|
||||
super().should_suppress_value_header())
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if self.object is UNINITIALIZED_ATTR:
|
||||
return []
|
||||
else:
|
||||
return super().get_doc(encoding, ignore) # type: ignore
|
||||
return super().get_doc(ignore) # type: ignore
|
||||
|
||||
|
||||
class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
|
||||
@ -1893,7 +1884,7 @@ class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
|
||||
objtype = 'data'
|
||||
member_order = 40
|
||||
priority = -10
|
||||
option_spec = dict(ModuleLevelDocumenter.option_spec)
|
||||
option_spec: OptionSpec = dict(ModuleLevelDocumenter.option_spec)
|
||||
option_spec["annotation"] = annotation_option
|
||||
option_spec["no-value"] = bool_option
|
||||
|
||||
@ -1977,13 +1968,13 @@ class DataDocumenter(GenericAliasMixin, NewTypeMixin, TypeVarMixin,
|
||||
|
||||
return None
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> List[List[str]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
# Check the variable has a docstring-comment
|
||||
comment = self.get_module_comment(self.objpath[-1])
|
||||
if comment:
|
||||
return [comment]
|
||||
else:
|
||||
return super().get_doc(encoding, ignore)
|
||||
return super().get_doc(ignore)
|
||||
|
||||
def add_content(self, more_content: Optional[StringList], no_docstring: bool = False
|
||||
) -> None:
|
||||
@ -2204,13 +2195,13 @@ class NonDataDescriptorMixin(DataDocumenterMixinBase):
|
||||
return (not getattr(self, 'non_data_descriptor', False) or
|
||||
super().should_suppress_directive_header())
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if getattr(self, 'non_data_descriptor', False):
|
||||
# the docstring of non datadescriptor is very probably the wrong thing
|
||||
# to display
|
||||
return None
|
||||
else:
|
||||
return super().get_doc(encoding, ignore) # type: ignore
|
||||
return super().get_doc(ignore) # type: ignore
|
||||
|
||||
|
||||
class SlotsMixin(DataDocumenterMixinBase):
|
||||
@ -2243,7 +2234,7 @@ class SlotsMixin(DataDocumenterMixinBase):
|
||||
else:
|
||||
return super().should_suppress_directive_header()
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if self.object is SLOTSATTR:
|
||||
try:
|
||||
__slots__ = inspect.getslots(self.parent)
|
||||
@ -2257,7 +2248,7 @@ class SlotsMixin(DataDocumenterMixinBase):
|
||||
(self.parent.__qualname__, exc), type='autodoc')
|
||||
return []
|
||||
else:
|
||||
return super().get_doc(encoding, ignore) # type: ignore
|
||||
return super().get_doc(ignore) # type: ignore
|
||||
|
||||
|
||||
class RuntimeInstanceAttributeMixin(DataDocumenterMixinBase):
|
||||
@ -2361,11 +2352,11 @@ class UninitializedInstanceAttributeMixin(DataDocumenterMixinBase):
|
||||
return (self.object is UNINITIALIZED_ATTR or
|
||||
super().should_suppress_value_header())
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
if self.object is UNINITIALIZED_ATTR:
|
||||
return None
|
||||
else:
|
||||
return super().get_doc(encoding, ignore) # type: ignore
|
||||
return super().get_doc(ignore) # type: ignore
|
||||
|
||||
|
||||
class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type: ignore
|
||||
@ -2377,7 +2368,7 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
"""
|
||||
objtype = 'attribute'
|
||||
member_order = 60
|
||||
option_spec = dict(ModuleLevelDocumenter.option_spec)
|
||||
option_spec: OptionSpec = dict(ModuleLevelDocumenter.option_spec)
|
||||
option_spec["annotation"] = annotation_option
|
||||
option_spec["no-value"] = bool_option
|
||||
|
||||
@ -2512,7 +2503,7 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
|
||||
return None
|
||||
|
||||
def get_doc(self, encoding: str = None, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
def get_doc(self, ignore: int = None) -> Optional[List[List[str]]]:
|
||||
# Check the attribute has a docstring-comment
|
||||
comment = self.get_attribute_comment(self.parent, self.objpath[-1])
|
||||
if comment:
|
||||
@ -2524,7 +2515,7 @@ class AttributeDocumenter(GenericAliasMixin, NewTypeMixin, SlotsMixin, # type:
|
||||
# ref: https://github.com/sphinx-doc/sphinx/issues/7805
|
||||
orig = self.config.autodoc_inherit_docstrings
|
||||
self.config.autodoc_inherit_docstrings = False # type: ignore
|
||||
return super().get_doc(encoding, ignore)
|
||||
return super().get_doc(ignore)
|
||||
finally:
|
||||
self.config.autodoc_inherit_docstrings = orig # type: ignore
|
||||
|
||||
@ -2545,7 +2536,6 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
|
||||
Specialized Documenter subclass for properties.
|
||||
"""
|
||||
objtype = 'property'
|
||||
directivetype = 'method'
|
||||
member_order = 60
|
||||
|
||||
# before AttributeDocumenter
|
||||
@ -2568,7 +2558,20 @@ class PropertyDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): #
|
||||
sourcename = self.get_sourcename()
|
||||
if inspect.isabstractmethod(self.object):
|
||||
self.add_line(' :abstractmethod:', sourcename)
|
||||
self.add_line(' :property:', sourcename)
|
||||
|
||||
if safe_getattr(self.object, 'fget', None):
|
||||
try:
|
||||
signature = inspect.signature(self.object.fget,
|
||||
type_aliases=self.config.autodoc_type_aliases)
|
||||
if signature.return_annotation is not Parameter.empty:
|
||||
objrepr = stringify_typehint(signature.return_annotation)
|
||||
self.add_line(' :type: ' + objrepr, sourcename)
|
||||
except TypeError as exc:
|
||||
logger.warning(__("Failed to get a function signature for %s: %s"),
|
||||
self.fullname, exc)
|
||||
return None
|
||||
except ValueError:
|
||||
raise
|
||||
|
||||
|
||||
class NewTypeAttributeDocumenter(AttributeDocumenter):
|
||||
@ -2589,7 +2592,7 @@ class NewTypeAttributeDocumenter(AttributeDocumenter):
|
||||
return not isinstance(parent, ModuleDocumenter) and inspect.isNewType(member)
|
||||
|
||||
|
||||
def get_documenters(app: Sphinx) -> Dict[str, "Type[Documenter]"]:
|
||||
def get_documenters(app: Sphinx) -> Dict[str, Type[Documenter]]:
|
||||
"""Returns registered Documenter classes"""
|
||||
warnings.warn("get_documenters() is deprecated.", RemovedInSphinx50Warning, stacklevel=2)
|
||||
return app.registry.documenters
|
||||
@ -2643,6 +2646,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value('autodoc_mock_imports', [], True)
|
||||
app.add_config_value('autodoc_typehints', "signature", True,
|
||||
ENUM("signature", "description", "none"))
|
||||
app.add_config_value('autodoc_typehints_description_target', 'all', True,
|
||||
ENUM('all', 'documented'))
|
||||
app.add_config_value('autodoc_type_aliases', {}, True)
|
||||
app.add_config_value('autodoc_warningiserror', True, True)
|
||||
app.add_config_value('autodoc_inherit_docstrings', True, True)
|
||||
@ -2653,6 +2658,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
||||
app.connect('config-inited', migrate_autodoc_member_order, priority=800)
|
||||
|
||||
app.setup_extension('sphinx.ext.autodoc.preserve_defaults')
|
||||
app.setup_extension('sphinx.ext.autodoc.type_comment')
|
||||
app.setup_extension('sphinx.ext.autodoc.typehints')
|
||||
|
||||
|
@ -7,27 +7,22 @@
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Callable, Dict, List, Set
|
||||
from typing import Any, Callable, Dict, List, Set, Type
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
from docutils.parsers.rst.states import RSTState, Struct
|
||||
from docutils.parsers.rst.states import RSTState
|
||||
from docutils.statemachine import StringList
|
||||
from docutils.utils import Reporter, assemble_option_dict
|
||||
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning, RemovedInSphinx60Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.ext.autodoc import Documenter, Options
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.docutils import SphinxDirective, switch_source_input
|
||||
from sphinx.util.nodes import nested_parse_with_titles
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -56,27 +51,27 @@ class DocumenterBridge:
|
||||
"""A parameters container for Documenters."""
|
||||
|
||||
def __init__(self, env: BuildEnvironment, reporter: Reporter, options: Options,
|
||||
lineno: int, state: Any = None) -> None:
|
||||
lineno: int, state: Any) -> None:
|
||||
self.env = env
|
||||
self._reporter = reporter
|
||||
self.genopt = options
|
||||
self.lineno = lineno
|
||||
self.filename_set = set() # type: Set[str]
|
||||
self.record_dependencies: Set[str] = set()
|
||||
self.result = StringList()
|
||||
|
||||
if state:
|
||||
self.state = state
|
||||
else:
|
||||
# create fake object for self.state.document.settings.tab_width
|
||||
warnings.warn('DocumenterBridge requires a state object on instantiation.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
settings = Struct(tab_width=8)
|
||||
document = Struct(settings=settings)
|
||||
self.state = Struct(document=document)
|
||||
self.state = state
|
||||
|
||||
def warn(self, msg: str) -> None:
|
||||
warnings.warn('DocumenterBridge.warn is deprecated. Plase use sphinx.util.logging '
|
||||
'module instead.',
|
||||
RemovedInSphinx60Warning, stacklevel=2)
|
||||
logger.warning(msg, location=(self.env.docname, self.lineno))
|
||||
|
||||
@property
|
||||
def filename_set(self) -> Set:
|
||||
warnings.warn('DocumenterBridge.filename_set is deprecated.',
|
||||
RemovedInSphinx60Warning, stacklevel=2)
|
||||
return self.record_dependencies
|
||||
|
||||
@property
|
||||
def reporter(self) -> Reporter:
|
||||
warnings.warn('DocumenterBridge.reporter is deprecated.',
|
||||
@ -84,7 +79,7 @@ class DocumenterBridge:
|
||||
return self._reporter
|
||||
|
||||
|
||||
def process_documenter_options(documenter: "Type[Documenter]", config: Config, options: Dict
|
||||
def process_documenter_options(documenter: Type[Documenter], config: Config, options: Dict
|
||||
) -> Options:
|
||||
"""Recognize options of Documenter from user input."""
|
||||
for name in AUTODOC_DEFAULT_OPTIONS:
|
||||
@ -115,7 +110,7 @@ def parse_generated_content(state: RSTState, content: StringList, documenter: Do
|
||||
"""Parse a generated content by Documenter."""
|
||||
with switch_source_input(state, content):
|
||||
if documenter.titles_allowed:
|
||||
node = nodes.section() # type: Element
|
||||
node: Element = nodes.section()
|
||||
# necessary so that the child nodes get the right source/line set
|
||||
node.document = state.document
|
||||
nested_parse_with_titles(state, content, node)
|
||||
@ -172,7 +167,7 @@ class AutodocDirective(SphinxDirective):
|
||||
|
||||
# record all filenames as dependencies -- this will at least
|
||||
# partially make automatic invalidation possible
|
||||
for fn in params.filename_set:
|
||||
for fn in params.record_dependencies:
|
||||
self.state.document.settings.record_dependencies.add(fn)
|
||||
|
||||
result = parse_generated_content(self.state, params.result, documenter)
|
||||
|
@ -11,10 +11,9 @@
|
||||
import importlib
|
||||
import traceback
|
||||
import warnings
|
||||
from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Optional, Tuple
|
||||
from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple
|
||||
|
||||
from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,
|
||||
deprecated_alias)
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.ext.autodoc.mock import ismock, undecorate
|
||||
from sphinx.pycode import ModuleAnalyzer, PycodeError
|
||||
from sphinx.util import logging
|
||||
@ -148,7 +147,7 @@ def get_module_members(module: Any) -> List[Tuple[str, Any]]:
|
||||
warnings.warn('sphinx.ext.autodoc.importer.get_module_members() is deprecated.',
|
||||
RemovedInSphinx50Warning)
|
||||
|
||||
members = {} # type: Dict[str, Tuple[str, Any]]
|
||||
members: Dict[str, Tuple[str, Any]] = {}
|
||||
for name in dir(module):
|
||||
try:
|
||||
value = safe_getattr(module, name, None)
|
||||
@ -164,21 +163,10 @@ def get_module_members(module: Any) -> List[Tuple[str, Any]]:
|
||||
return sorted(list(members.values()))
|
||||
|
||||
|
||||
Attribute = NamedTuple('Attribute', [('name', str),
|
||||
('directly_defined', bool),
|
||||
('value', Any)])
|
||||
|
||||
|
||||
def _getmro(obj: Any) -> Tuple["Type", ...]:
|
||||
warnings.warn('sphinx.ext.autodoc.importer._getmro() is deprecated.',
|
||||
RemovedInSphinx40Warning)
|
||||
return getmro(obj)
|
||||
|
||||
|
||||
def _getannotations(obj: Any) -> Mapping[str, Any]:
|
||||
warnings.warn('sphinx.ext.autodoc.importer._getannotations() is deprecated.',
|
||||
RemovedInSphinx40Warning)
|
||||
return getannotations(obj)
|
||||
class Attribute(NamedTuple):
|
||||
name: str
|
||||
directly_defined: bool
|
||||
value: Any
|
||||
|
||||
|
||||
def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
|
||||
@ -189,7 +177,7 @@ def get_object_members(subject: Any, objpath: List[str], attrgetter: Callable,
|
||||
# the members directly defined in the class
|
||||
obj_dict = attrgetter(subject, '__dict__', {})
|
||||
|
||||
members = {} # type: Dict[str, Attribute]
|
||||
members: Dict[str, Attribute] = {}
|
||||
|
||||
# enum members
|
||||
if isenumclass(subject):
|
||||
@ -250,7 +238,7 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
|
||||
# the members directly defined in the class
|
||||
obj_dict = attrgetter(subject, '__dict__', {})
|
||||
|
||||
members = {} # type: Dict[str, ObjectMember]
|
||||
members: Dict[str, ObjectMember] = {}
|
||||
|
||||
# enum members
|
||||
if isenumclass(subject):
|
||||
@ -327,24 +315,3 @@ def get_class_members(subject: Any, objpath: List[str], attrgetter: Callable
|
||||
pass
|
||||
|
||||
return members
|
||||
|
||||
|
||||
from sphinx.ext.autodoc.mock import (MockFinder, MockLoader, _MockModule, _MockObject, # NOQA
|
||||
mock)
|
||||
|
||||
deprecated_alias('sphinx.ext.autodoc.importer',
|
||||
{
|
||||
'_MockModule': _MockModule,
|
||||
'_MockObject': _MockObject,
|
||||
'MockFinder': MockFinder,
|
||||
'MockLoader': MockLoader,
|
||||
'mock': mock,
|
||||
},
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'_MockModule': 'sphinx.ext.autodoc.mock._MockModule',
|
||||
'_MockObject': 'sphinx.ext.autodoc.mock._MockObject',
|
||||
'MockFinder': 'sphinx.ext.autodoc.mock.MockFinder',
|
||||
'MockLoader': 'sphinx.ext.autodoc.mock.MockLoader',
|
||||
'mock': 'sphinx.ext.autodoc.mock.mock',
|
||||
})
|
||||
|
@ -14,7 +14,7 @@ import sys
|
||||
from importlib.abc import Loader, MetaPathFinder
|
||||
from importlib.machinery import ModuleSpec
|
||||
from types import ModuleType
|
||||
from typing import Any, Generator, Iterator, List, Sequence, Tuple, Union
|
||||
from typing import Any, Generator, Iterator, List, Optional, Sequence, Tuple, Union
|
||||
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.inspect import safe_getattr
|
||||
@ -27,7 +27,7 @@ class _MockObject:
|
||||
|
||||
__display_name__ = '_MockObject'
|
||||
__sphinx_mock__ = True
|
||||
__sphinx_decorator_args__ = () # type: Tuple[Any, ...]
|
||||
__sphinx_decorator_args__: Tuple[Any, ...] = ()
|
||||
|
||||
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
|
||||
if len(args) == 3 and isinstance(args[1], tuple):
|
||||
@ -86,8 +86,8 @@ class _MockModule(ModuleType):
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__(name)
|
||||
self.__all__ = [] # type: List[str]
|
||||
self.__path__ = [] # type: List[str]
|
||||
self.__all__: List[str] = []
|
||||
self.__path__: List[str] = []
|
||||
|
||||
def __getattr__(self, name: str) -> _MockObject:
|
||||
return _make_subclass(name, self.__name__)()
|
||||
@ -118,10 +118,10 @@ class MockFinder(MetaPathFinder):
|
||||
super().__init__()
|
||||
self.modnames = modnames
|
||||
self.loader = MockLoader(self)
|
||||
self.mocked_modules = [] # type: List[str]
|
||||
self.mocked_modules: List[str] = []
|
||||
|
||||
def find_spec(self, fullname: str, path: Sequence[Union[bytes, str]],
|
||||
target: ModuleType = None) -> ModuleSpec:
|
||||
def find_spec(self, fullname: str, path: Optional[Sequence[Union[bytes, str]]],
|
||||
target: ModuleType = None) -> Optional[ModuleSpec]:
|
||||
for modname in self.modnames:
|
||||
# check if fullname is (or is a descendant of) one of our targets
|
||||
if modname == fullname or fullname.startswith(modname + '.'):
|
||||
|
88
sphinx/ext/autodoc/preserve_defaults.py
Normal file
88
sphinx/ext/autodoc/preserve_defaults.py
Normal file
@ -0,0 +1,88 @@
|
||||
"""
|
||||
sphinx.ext.autodoc.preserve_defaults
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Preserve the default argument values of function signatures in source code
|
||||
and keep them not evaluated for readability.
|
||||
|
||||
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import ast
|
||||
import inspect
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.locale import __
|
||||
from sphinx.pycode.ast import parse as ast_parse
|
||||
from sphinx.pycode.ast import unparse as ast_unparse
|
||||
from sphinx.util import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DefaultValue:
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return self.name
|
||||
|
||||
|
||||
def get_function_def(obj: Any) -> ast.FunctionDef:
|
||||
"""Get FunctionDef object from living object.
|
||||
This tries to parse original code for living object and returns
|
||||
AST node for given *obj*.
|
||||
"""
|
||||
try:
|
||||
source = inspect.getsource(obj)
|
||||
if source.startswith((' ', r'\t')):
|
||||
# subject is placed inside class or block. To read its docstring,
|
||||
# this adds if-block before the declaration.
|
||||
module = ast_parse('if True:\n' + source)
|
||||
return module.body[0].body[0] # type: ignore
|
||||
else:
|
||||
module = ast_parse(source)
|
||||
return module.body[0] # type: ignore
|
||||
except (OSError, TypeError): # failed to load source code
|
||||
return None
|
||||
|
||||
|
||||
def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
|
||||
"""Update defvalue info of *obj* using type_comments."""
|
||||
if not app.config.autodoc_preserve_defaults:
|
||||
return
|
||||
|
||||
try:
|
||||
function = get_function_def(obj)
|
||||
if function.args.defaults or function.args.kw_defaults:
|
||||
sig = inspect.signature(obj)
|
||||
defaults = list(function.args.defaults)
|
||||
kw_defaults = list(function.args.kw_defaults)
|
||||
parameters = list(sig.parameters.values())
|
||||
for i, param in enumerate(parameters):
|
||||
if param.default is not param.empty:
|
||||
if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
|
||||
value = DefaultValue(ast_unparse(defaults.pop(0))) # type: ignore
|
||||
parameters[i] = param.replace(default=value)
|
||||
else:
|
||||
value = DefaultValue(ast_unparse(kw_defaults.pop(0))) # type: ignore
|
||||
parameters[i] = param.replace(default=value)
|
||||
sig = sig.replace(parameters=parameters)
|
||||
obj.__signature__ = sig
|
||||
except (AttributeError, TypeError):
|
||||
# failed to update signature (ex. built-in or extension types)
|
||||
pass
|
||||
except NotImplementedError as exc: # failed to ast.unparse()
|
||||
logger.warning(__("Failed to parse a default argument value for %r: %s"), obj, exc)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value('autodoc_preserve_defaults', False, True)
|
||||
app.connect('autodoc-before-process-signature', update_defvalue)
|
||||
|
||||
return {
|
||||
'version': '1.0',
|
||||
'parallel_read_safe': True
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from typing import Any, Dict, Iterable, cast
|
||||
from typing import Any, Dict, Iterable, Set, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element
|
||||
@ -42,8 +42,6 @@ def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element
|
||||
return
|
||||
if app.config.autodoc_typehints != 'description':
|
||||
return
|
||||
if objtype == 'class' and app.config.autoclass_content not in ('init', 'both'):
|
||||
return
|
||||
|
||||
try:
|
||||
signature = cast(addnodes.desc_signature, contentnode.parent[0])
|
||||
@ -63,7 +61,10 @@ def merge_typehints(app: Sphinx, domain: str, objtype: str, contentnode: Element
|
||||
field_lists.append(field_list)
|
||||
|
||||
for field_list in field_lists:
|
||||
modify_field_list(field_list, annotations[fullname])
|
||||
if app.config.autodoc_typehints_description_target == "all":
|
||||
modify_field_list(field_list, annotations[fullname])
|
||||
else:
|
||||
augment_descriptions_with_types(field_list, annotations[fullname])
|
||||
|
||||
|
||||
def insert_field_list(node: Element) -> nodes.field_list:
|
||||
@ -80,7 +81,7 @@ def insert_field_list(node: Element) -> nodes.field_list:
|
||||
|
||||
|
||||
def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> None:
|
||||
arguments = {} # type: Dict[str, Dict[str, bool]]
|
||||
arguments: Dict[str, Dict[str, bool]] = {}
|
||||
fields = cast(Iterable[nodes.field], node)
|
||||
for field in fields:
|
||||
field_name = field[0].astext()
|
||||
@ -126,6 +127,52 @@ def modify_field_list(node: nodes.field_list, annotations: Dict[str, str]) -> No
|
||||
node += field
|
||||
|
||||
|
||||
def augment_descriptions_with_types(
|
||||
node: nodes.field_list,
|
||||
annotations: Dict[str, str],
|
||||
) -> None:
|
||||
fields = cast(Iterable[nodes.field], node)
|
||||
has_description = set() # type: Set[str]
|
||||
has_type = set() # type: Set[str]
|
||||
for field in fields:
|
||||
field_name = field[0].astext()
|
||||
parts = re.split(' +', field_name)
|
||||
if parts[0] == 'param':
|
||||
if len(parts) == 2:
|
||||
# :param xxx:
|
||||
has_description.add(parts[1])
|
||||
elif len(parts) > 2:
|
||||
# :param xxx yyy:
|
||||
name = ' '.join(parts[2:])
|
||||
has_description.add(name)
|
||||
has_type.add(name)
|
||||
elif parts[0] == 'type':
|
||||
name = ' '.join(parts[1:])
|
||||
has_type.add(name)
|
||||
elif parts[0] == 'return':
|
||||
has_description.add('return')
|
||||
elif parts[0] == 'rtype':
|
||||
has_type.add('return')
|
||||
|
||||
# Add 'type' for parameters with a description but no declared type.
|
||||
for name in annotations:
|
||||
if name == 'return':
|
||||
continue
|
||||
if name in has_description and name not in has_type:
|
||||
field = nodes.field()
|
||||
field += nodes.field_name('', 'type ' + name)
|
||||
field += nodes.field_body('', nodes.paragraph('', annotations[name]))
|
||||
node += field
|
||||
|
||||
# Add 'rtype' if 'return' is present and 'rtype' isn't.
|
||||
if 'return' in annotations:
|
||||
if 'return' in has_description and 'return' not in has_type:
|
||||
field = nodes.field()
|
||||
field += nodes.field_name('', 'rtype')
|
||||
field += nodes.field_body('', nodes.paragraph('', annotations['return']))
|
||||
node += field
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.connect('autodoc-process-signature', record_typehints)
|
||||
app.connect('object-description-transform', merge_typehints)
|
||||
|
@ -60,19 +60,19 @@ import sys
|
||||
import warnings
|
||||
from os import path
|
||||
from types import ModuleType
|
||||
from typing import Any, Dict, List, Tuple, cast
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, system_message
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.states import Inliner, RSTStateMachine, Struct, state_classes
|
||||
from docutils.parsers.rst.states import RSTStateMachine, Struct, state_classes
|
||||
from docutils.statemachine import StringList
|
||||
|
||||
import sphinx
|
||||
from sphinx import addnodes
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.ext.autodoc import INSTANCEATTR, Documenter
|
||||
@ -85,13 +85,9 @@ from sphinx.util import logging, rst
|
||||
from sphinx.util.docutils import (NullReporter, SphinxDirective, SphinxRole, new_document,
|
||||
switch_source_input)
|
||||
from sphinx.util.matching import Matcher
|
||||
from sphinx.util.typing import OptionSpec
|
||||
from sphinx.writers.html import HTMLTranslator
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -169,7 +165,7 @@ def autosummary_table_visit_html(self: HTMLTranslator, node: autosummary_table)
|
||||
# -- autodoc integration -------------------------------------------------------
|
||||
|
||||
# current application object (used in `get_documenter()`).
|
||||
_app = None # type: Sphinx
|
||||
_app: Sphinx = None
|
||||
|
||||
|
||||
class FakeDirective(DocumenterBridge):
|
||||
@ -182,7 +178,7 @@ class FakeDirective(DocumenterBridge):
|
||||
super().__init__(env, None, Options(), 0, state)
|
||||
|
||||
|
||||
def get_documenter(app: Sphinx, obj: Any, parent: Any) -> "Type[Documenter]":
|
||||
def get_documenter(app: Sphinx, obj: Any, parent: Any) -> Type[Documenter]:
|
||||
"""Get an autodoc.Documenter class suitable for documenting the given
|
||||
object.
|
||||
|
||||
@ -230,7 +226,7 @@ class Autosummary(SphinxDirective):
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
has_content = True
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'caption': directives.unchanged_required,
|
||||
'toctree': directives.unchanged,
|
||||
'nosignatures': directives.flag,
|
||||
@ -315,7 +311,7 @@ class Autosummary(SphinxDirective):
|
||||
"""
|
||||
prefixes = get_import_prefixes_from_env(self.env)
|
||||
|
||||
items = [] # type: List[Tuple[str, str, str, str]]
|
||||
items: List[Tuple[str, str, str, str]] = []
|
||||
|
||||
max_item_chars = 50
|
||||
|
||||
@ -435,29 +431,6 @@ class Autosummary(SphinxDirective):
|
||||
|
||||
return [table_spec, table]
|
||||
|
||||
def warn(self, msg: str) -> None:
|
||||
warnings.warn('Autosummary.warn() is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
logger.warning(msg)
|
||||
|
||||
@property
|
||||
def genopt(self) -> Options:
|
||||
warnings.warn('Autosummary.genopt is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self.bridge.genopt
|
||||
|
||||
@property
|
||||
def warnings(self) -> List[Node]:
|
||||
warnings.warn('Autosummary.warnings is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return []
|
||||
|
||||
@property
|
||||
def result(self) -> StringList:
|
||||
warnings.warn('Autosummary.result is deprecated',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return self.bridge.result
|
||||
|
||||
|
||||
def strip_arg_typehint(s: str) -> str:
|
||||
"""Strip a type hint from argument definition."""
|
||||
@ -488,8 +461,8 @@ def mangle_signature(sig: str, max_chars: int = 30) -> str:
|
||||
s = re.sub(r'{[^}]*}', '', s)
|
||||
|
||||
# Parse the signature to arguments + options
|
||||
args = [] # type: List[str]
|
||||
opts = [] # type: List[str]
|
||||
args: List[str] = []
|
||||
opts: List[str] = []
|
||||
|
||||
opt_re = re.compile(r"^(.*, |)([a-zA-Z0-9_*]+)\s*=\s*")
|
||||
while s:
|
||||
@ -606,7 +579,7 @@ def get_import_prefixes_from_env(env: BuildEnvironment) -> List[str]:
|
||||
Obtain current Python import prefixes (for `import_by_name`)
|
||||
from ``document.env``
|
||||
"""
|
||||
prefixes = [None] # type: List[str]
|
||||
prefixes: List[Optional[str]] = [None]
|
||||
|
||||
currmodule = env.ref_context.get('py:module')
|
||||
if currmodule:
|
||||
@ -700,33 +673,6 @@ def import_ivar_by_name(name: str, prefixes: List[str] = [None]) -> Tuple[str, A
|
||||
|
||||
# -- :autolink: (smart default role) -------------------------------------------
|
||||
|
||||
def autolink_role(typ: str, rawtext: str, etext: str, lineno: int, inliner: Inliner,
|
||||
options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
"""Smart linking role.
|
||||
|
||||
Expands to ':obj:`text`' if `text` is an object that can be imported;
|
||||
otherwise expands to '*text*'.
|
||||
"""
|
||||
warnings.warn('autolink_role() is deprecated.', RemovedInSphinx40Warning, stacklevel=2)
|
||||
env = inliner.document.settings.env
|
||||
pyobj_role = env.get_domain('py').role('obj')
|
||||
objects, msg = pyobj_role('obj', rawtext, etext, lineno, inliner, options, content)
|
||||
if msg != []:
|
||||
return objects, msg
|
||||
|
||||
assert len(objects) == 1
|
||||
pending_xref = cast(addnodes.pending_xref, objects[0])
|
||||
prefixes = get_import_prefixes_from_env(env)
|
||||
try:
|
||||
name, obj, parent, modname = import_by_name(pending_xref['reftarget'], prefixes)
|
||||
except ImportError:
|
||||
literal = cast(nodes.literal, pending_xref[0])
|
||||
objects[0] = nodes.emphasis(rawtext, literal.astext(), classes=literal['classes'])
|
||||
|
||||
return objects, msg
|
||||
|
||||
|
||||
class AutoLink(SphinxRole):
|
||||
"""Smart linking role.
|
||||
|
||||
@ -761,7 +707,7 @@ def get_rst_suffix(app: Sphinx) -> str:
|
||||
return ('restructuredtext',)
|
||||
return parser_class.supported
|
||||
|
||||
suffix = None # type: str
|
||||
suffix: str = None
|
||||
for suffix in app.config.source_suffix:
|
||||
if 'restructuredtext' in get_supported_format(suffix):
|
||||
return suffix
|
||||
@ -827,7 +773,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.connect('builder-inited', process_generate_options)
|
||||
app.add_config_value('autosummary_context', {}, True)
|
||||
app.add_config_value('autosummary_filename_map', {}, 'html')
|
||||
app.add_config_value('autosummary_generate', [], True, [bool])
|
||||
app.add_config_value('autosummary_generate', True, True, [bool])
|
||||
app.add_config_value('autosummary_generate_overwrite', True, False)
|
||||
app.add_config_value('autosummary_mock_imports',
|
||||
lambda config: config.autodoc_mock_imports, 'env')
|
||||
|
@ -28,7 +28,7 @@ import sys
|
||||
import warnings
|
||||
from gettext import NullTranslations
|
||||
from os import path
|
||||
from typing import Any, Callable, Dict, List, NamedTuple, Set, Tuple, Union
|
||||
from typing import Any, Dict, List, NamedTuple, Set, Tuple, Type, Union
|
||||
|
||||
from jinja2 import TemplateNotFound
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
@ -38,7 +38,7 @@ from sphinx import __display_version__, package_dir
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.ext.autodoc import Documenter
|
||||
from sphinx.ext.autodoc.importer import import_module
|
||||
from sphinx.ext.autosummary import get_documenter, import_by_name, import_ivar_by_name
|
||||
@ -50,11 +50,6 @@ from sphinx.util.inspect import safe_getattr
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.template import SphinxTemplateLoader
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -64,7 +59,7 @@ class DummyApplication:
|
||||
def __init__(self, translator: NullTranslations) -> None:
|
||||
self.config = Config()
|
||||
self.registry = SphinxComponentRegistry()
|
||||
self.messagelog = [] # type: List[str]
|
||||
self.messagelog: List[str] = []
|
||||
self.srcdir = "/"
|
||||
self.translator = translator
|
||||
self.verbosity = 0
|
||||
@ -79,10 +74,11 @@ class DummyApplication:
|
||||
pass
|
||||
|
||||
|
||||
AutosummaryEntry = NamedTuple('AutosummaryEntry', [('name', str),
|
||||
('path', str),
|
||||
('template', str),
|
||||
('recursive', bool)])
|
||||
class AutosummaryEntry(NamedTuple):
|
||||
name: str
|
||||
path: str
|
||||
template: str
|
||||
recursive: bool
|
||||
|
||||
|
||||
def setup_documenters(app: Any) -> None:
|
||||
@ -91,11 +87,11 @@ def setup_documenters(app: Any) -> None:
|
||||
FunctionDocumenter, MethodDocumenter, ModuleDocumenter,
|
||||
NewTypeAttributeDocumenter, NewTypeDataDocumenter,
|
||||
PropertyDocumenter)
|
||||
documenters = [
|
||||
documenters: List[Type[Documenter]] = [
|
||||
ModuleDocumenter, ClassDocumenter, ExceptionDocumenter, DataDocumenter,
|
||||
FunctionDocumenter, MethodDocumenter, NewTypeAttributeDocumenter,
|
||||
NewTypeDataDocumenter, AttributeDocumenter, DecoratorDocumenter, PropertyDocumenter,
|
||||
] # type: List[Type[Documenter]]
|
||||
]
|
||||
for documenter in documenters:
|
||||
app.registry.add_documenter(documenter.objtype, documenter)
|
||||
|
||||
@ -245,8 +241,8 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
|
||||
def get_members(obj: Any, types: Set[str], include_public: List[str] = [],
|
||||
imported: bool = True) -> Tuple[List[str], List[str]]:
|
||||
items = [] # type: List[str]
|
||||
public = [] # type: List[str]
|
||||
items: List[str] = []
|
||||
public: List[str] = []
|
||||
for name in dir(obj):
|
||||
try:
|
||||
value = safe_getattr(obj, name)
|
||||
@ -286,7 +282,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
return public, attrs
|
||||
|
||||
def get_modules(obj: Any) -> Tuple[List[str], List[str]]:
|
||||
items = [] # type: List[str]
|
||||
items: List[str] = []
|
||||
for _, modname, ispkg in pkgutil.iter_modules(obj.__path__):
|
||||
fullname = name + '.' + modname
|
||||
try:
|
||||
@ -300,7 +296,7 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
public = [x for x in items if not x.split('.')[-1].startswith('_')]
|
||||
return public, items
|
||||
|
||||
ns = {} # type: Dict[str, Any]
|
||||
ns: Dict[str, Any] = {}
|
||||
ns.update(context)
|
||||
|
||||
if doc.objtype == 'module':
|
||||
@ -352,25 +348,10 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
|
||||
|
||||
|
||||
def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||
suffix: str = '.rst', warn: Callable = None,
|
||||
info: Callable = None, base_path: str = None,
|
||||
suffix: str = '.rst', base_path: str = None,
|
||||
builder: Builder = None, template_dir: str = None,
|
||||
imported_members: bool = False, app: Any = None,
|
||||
overwrite: bool = True, encoding: str = 'utf-8') -> None:
|
||||
if info:
|
||||
warnings.warn('info argument for generate_autosummary_docs() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
_info = info
|
||||
else:
|
||||
_info = logger.info
|
||||
|
||||
if warn:
|
||||
warnings.warn('warn argument for generate_autosummary_docs() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
_warn = warn
|
||||
else:
|
||||
_warn = logger.warning
|
||||
|
||||
if builder:
|
||||
warnings.warn('builder argument for generate_autosummary_docs() is deprecated.',
|
||||
RemovedInSphinx50Warning, stacklevel=2)
|
||||
@ -382,11 +363,11 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||
showed_sources = list(sorted(sources))
|
||||
if len(showed_sources) > 20:
|
||||
showed_sources = showed_sources[:10] + ['...'] + showed_sources[-10:]
|
||||
_info(__('[autosummary] generating autosummary for: %s') %
|
||||
', '.join(showed_sources))
|
||||
logger.info(__('[autosummary] generating autosummary for: %s') %
|
||||
', '.join(showed_sources))
|
||||
|
||||
if output_dir:
|
||||
_info(__('[autosummary] writing to %s') % output_dir)
|
||||
logger.info(__('[autosummary] writing to %s') % output_dir)
|
||||
|
||||
if base_path is not None:
|
||||
sources = [os.path.join(base_path, filename) for filename in sources]
|
||||
@ -423,10 +404,10 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||
name, obj, parent, modname = import_ivar_by_name(entry.name)
|
||||
qualname = name.replace(modname + ".", "")
|
||||
except ImportError:
|
||||
_warn(__('[autosummary] failed to import %r: %s') % (entry.name, e))
|
||||
logger.warning(__('[autosummary] failed to import %r: %s') % (entry.name, e))
|
||||
continue
|
||||
|
||||
context = {}
|
||||
context: Dict[str, Any] = {}
|
||||
if app:
|
||||
context.update(app.config.autosummary_context)
|
||||
|
||||
@ -453,8 +434,8 @@ def generate_autosummary_docs(sources: List[str], output_dir: str = None,
|
||||
# descend recursively to new files
|
||||
if new_files:
|
||||
generate_autosummary_docs(new_files, output_dir=output_dir,
|
||||
suffix=suffix, warn=warn, info=info,
|
||||
base_path=base_path,
|
||||
suffix=suffix, base_path=base_path,
|
||||
builder=builder, template_dir=template_dir,
|
||||
imported_members=imported_members, app=app,
|
||||
overwrite=overwrite)
|
||||
|
||||
@ -466,7 +447,7 @@ def find_autosummary_in_files(filenames: List[str]) -> List[AutosummaryEntry]:
|
||||
|
||||
See `find_autosummary_in_lines`.
|
||||
"""
|
||||
documented = [] # type: List[AutosummaryEntry]
|
||||
documented: List[AutosummaryEntry] = []
|
||||
for filename in filenames:
|
||||
with open(filename, encoding='utf-8', errors='ignore') as f:
|
||||
lines = f.read().splitlines()
|
||||
@ -520,10 +501,10 @@ def find_autosummary_in_lines(lines: List[str], module: str = None, filename: st
|
||||
toctree_arg_re = re.compile(r'^\s+:toctree:\s*(.*?)\s*$')
|
||||
template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$')
|
||||
|
||||
documented = [] # type: List[AutosummaryEntry]
|
||||
documented: List[AutosummaryEntry] = []
|
||||
|
||||
recursive = False
|
||||
toctree = None # type: str
|
||||
toctree: str = None
|
||||
template = None
|
||||
current_module = module
|
||||
in_autosummary = False
|
||||
|
@ -53,19 +53,19 @@ class CoverageBuilder(Builder):
|
||||
'results in %(outdir)s' + path.sep + 'python.txt.')
|
||||
|
||||
def init(self) -> None:
|
||||
self.c_sourcefiles = [] # type: List[str]
|
||||
self.c_sourcefiles: List[str] = []
|
||||
for pattern in self.config.coverage_c_path:
|
||||
pattern = path.join(self.srcdir, pattern)
|
||||
self.c_sourcefiles.extend(glob.glob(pattern))
|
||||
|
||||
self.c_regexes = [] # type: List[Tuple[str, Pattern]]
|
||||
self.c_regexes: List[Tuple[str, Pattern]] = []
|
||||
for (name, exp) in self.config.coverage_c_regexes.items():
|
||||
try:
|
||||
self.c_regexes.append((name, re.compile(exp)))
|
||||
except Exception:
|
||||
logger.warning(__('invalid regex %r in coverage_c_regexes'), exp)
|
||||
|
||||
self.c_ignorexps = {} # type: Dict[str, List[Pattern]]
|
||||
self.c_ignorexps: Dict[str, List[Pattern]] = {}
|
||||
for (name, exps) in self.config.coverage_ignore_c_items.items():
|
||||
self.c_ignorexps[name] = compile_regex_list('coverage_ignore_c_items',
|
||||
exps)
|
||||
@ -82,11 +82,11 @@ class CoverageBuilder(Builder):
|
||||
return 'coverage overview'
|
||||
|
||||
def write(self, *ignored: Any) -> None:
|
||||
self.py_undoc = {} # type: Dict[str, Dict[str, Any]]
|
||||
self.py_undoc: Dict[str, Dict[str, Any]] = {}
|
||||
self.build_py_coverage()
|
||||
self.write_py_coverage()
|
||||
|
||||
self.c_undoc = {} # type: Dict[str, Set[Tuple[str, str]]]
|
||||
self.c_undoc: Dict[str, Set[Tuple[str, str]]] = {}
|
||||
self.build_c_coverage()
|
||||
self.write_c_coverage()
|
||||
|
||||
@ -94,7 +94,7 @@ class CoverageBuilder(Builder):
|
||||
# Fetch all the info from the header files
|
||||
c_objects = self.env.domaindata['c']['objects']
|
||||
for filename in self.c_sourcefiles:
|
||||
undoc = set() # type: Set[Tuple[str, str]]
|
||||
undoc: Set[Tuple[str, str]] = set()
|
||||
with open(filename) as f:
|
||||
for line in f:
|
||||
for key, regex in self.c_regexes:
|
||||
@ -161,7 +161,7 @@ class CoverageBuilder(Builder):
|
||||
continue
|
||||
|
||||
funcs = []
|
||||
classes = {} # type: Dict[str, List[str]]
|
||||
classes: Dict[str, List[str]] = {}
|
||||
|
||||
for name, obj in inspect.getmembers(mod):
|
||||
# diverse module attributes are ignored:
|
||||
@ -200,7 +200,7 @@ class CoverageBuilder(Builder):
|
||||
classes[name] = []
|
||||
continue
|
||||
|
||||
attrs = [] # type: List[str]
|
||||
attrs: List[str] = []
|
||||
|
||||
for attr_name in dir(obj):
|
||||
if attr_name not in obj.__dict__:
|
||||
|
@ -13,10 +13,10 @@ import doctest
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
from io import StringIO
|
||||
from os import path
|
||||
from typing import Any, Callable, Dict, Iterable, List, Sequence, Set, Tuple
|
||||
from typing import (TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Sequence, Set, Tuple,
|
||||
Type)
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, TextElement
|
||||
@ -26,17 +26,14 @@ from packaging.version import Version
|
||||
|
||||
import sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.osutil import relpath
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
@ -46,12 +43,6 @@ blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
|
||||
doctestopt_re = re.compile(r'#\s*doctest:.+$', re.MULTILINE)
|
||||
|
||||
|
||||
def doctest_encode(text: str, encoding: str) -> str:
|
||||
warnings.warn('doctest_encode() is deprecated.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
return text
|
||||
|
||||
|
||||
def is_allowed_version(spec: str, version: str) -> bool:
|
||||
"""Check `spec` satisfies `version` or not.
|
||||
|
||||
@ -96,7 +87,7 @@ class TestDirective(SphinxDirective):
|
||||
if not test:
|
||||
test = code
|
||||
code = doctestopt_re.sub('', code)
|
||||
nodetype = nodes.literal_block # type: Type[TextElement]
|
||||
nodetype: Type[TextElement] = nodes.literal_block
|
||||
if self.name in ('testsetup', 'testcleanup') or 'hide' in self.options:
|
||||
nodetype = nodes.comment
|
||||
if self.arguments:
|
||||
@ -160,15 +151,19 @@ class TestDirective(SphinxDirective):
|
||||
|
||||
|
||||
class TestsetupDirective(TestDirective):
|
||||
option_spec = {'skipif': directives.unchanged_required} # type: Dict
|
||||
option_spec: OptionSpec = {
|
||||
'skipif': directives.unchanged_required
|
||||
}
|
||||
|
||||
|
||||
class TestcleanupDirective(TestDirective):
|
||||
option_spec = {'skipif': directives.unchanged_required} # type: Dict
|
||||
option_spec: OptionSpec = {
|
||||
'skipif': directives.unchanged_required
|
||||
}
|
||||
|
||||
|
||||
class DoctestDirective(TestDirective):
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'hide': directives.flag,
|
||||
'no-trim-doctest-flags': directives.flag,
|
||||
'options': directives.unchanged,
|
||||
@ -179,7 +174,7 @@ class DoctestDirective(TestDirective):
|
||||
|
||||
|
||||
class TestcodeDirective(TestDirective):
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'hide': directives.flag,
|
||||
'no-trim-doctest-flags': directives.flag,
|
||||
'pyversion': directives.unchanged_required,
|
||||
@ -189,7 +184,7 @@ class TestcodeDirective(TestDirective):
|
||||
|
||||
|
||||
class TestoutputDirective(TestDirective):
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'hide': directives.flag,
|
||||
'no-trim-doctest-flags': directives.flag,
|
||||
'options': directives.unchanged,
|
||||
@ -207,9 +202,9 @@ parser = doctest.DocTestParser()
|
||||
class TestGroup:
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
self.setup = [] # type: List[TestCode]
|
||||
self.tests = [] # type: List[List[TestCode]]
|
||||
self.cleanup = [] # type: List[TestCode]
|
||||
self.setup: List[TestCode] = []
|
||||
self.tests: List[List[TestCode]] = []
|
||||
self.cleanup: List[TestCode] = []
|
||||
|
||||
def add_code(self, code: "TestCode", prepend: bool = False) -> None:
|
||||
if code.type == 'testsetup':
|
||||
@ -397,7 +392,7 @@ Doctest summary
|
||||
return False
|
||||
else:
|
||||
condition = node['skipif']
|
||||
context = {} # type: Dict[str, Any]
|
||||
context: Dict[str, Any] = {}
|
||||
if self.config.doctest_global_setup:
|
||||
exec(self.config.doctest_global_setup, context)
|
||||
should_skip = eval(condition, context)
|
||||
@ -406,7 +401,7 @@ Doctest summary
|
||||
return should_skip
|
||||
|
||||
def test_doc(self, docname: str, doctree: Node) -> None:
|
||||
groups = {} # type: Dict[str, TestGroup]
|
||||
groups: Dict[str, TestGroup] = {}
|
||||
add_to_all_groups = []
|
||||
self.setup_runner = SphinxDocTestRunner(verbose=False,
|
||||
optionflags=self.opt)
|
||||
@ -487,7 +482,7 @@ Doctest summary
|
||||
return compile(code, name, self.type, flags, dont_inherit)
|
||||
|
||||
def test_group(self, group: TestGroup) -> None:
|
||||
ns = {} # type: Dict
|
||||
ns: Dict = {}
|
||||
|
||||
def run_setup_cleanup(runner: Any, testcodes: List[TestCode], what: Any) -> bool:
|
||||
examples = []
|
||||
|
@ -30,6 +30,7 @@ from sphinx.util.fileutil import copy_asset
|
||||
from sphinx.util.i18n import search_image_for_language
|
||||
from sphinx.util.nodes import set_source_info
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.typing import OptionSpec
|
||||
from sphinx.writers.html import HTMLTranslator
|
||||
from sphinx.writers.latex import LaTeXTranslator
|
||||
from sphinx.writers.manpage import ManualPageTranslator
|
||||
@ -49,10 +50,10 @@ class ClickableMapDefinition:
|
||||
href_re = re.compile('href=".*?"')
|
||||
|
||||
def __init__(self, filename: str, content: str, dot: str = '') -> None:
|
||||
self.id = None # type: str
|
||||
self.id: str = None
|
||||
self.filename = filename
|
||||
self.content = content.splitlines()
|
||||
self.clickable = [] # type: List[str]
|
||||
self.clickable: List[str] = []
|
||||
|
||||
self.parse(dot=dot)
|
||||
|
||||
@ -113,7 +114,7 @@ class Graphviz(SphinxDirective):
|
||||
required_arguments = 0
|
||||
optional_arguments = 1
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'alt': directives.unchanged,
|
||||
'align': align_spec,
|
||||
'caption': directives.unchanged,
|
||||
@ -181,7 +182,7 @@ class GraphvizSimple(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'alt': directives.unchanged,
|
||||
'align': align_spec,
|
||||
'caption': directives.unchanged,
|
||||
|
@ -28,6 +28,7 @@ import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import nested_parse_with_titles
|
||||
from sphinx.util.typing import OptionSpec
|
||||
|
||||
|
||||
class ifconfig(nodes.Element):
|
||||
@ -40,7 +41,7 @@ class IfConfig(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {} # type: Dict
|
||||
option_spec: OptionSpec = {}
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
node = ifconfig()
|
||||
|
@ -37,10 +37,10 @@ class ImagemagickConverter(ImageConverter):
|
||||
logger.debug('Invoking %r ...', args)
|
||||
subprocess.run(args, stdout=PIPE, stderr=PIPE, check=True)
|
||||
return True
|
||||
except OSError:
|
||||
except OSError as exc:
|
||||
logger.warning(__('convert command %r cannot be run, '
|
||||
'check the image_converter setting'),
|
||||
self.config.image_converter)
|
||||
'check the image_converter setting: %s'),
|
||||
self.config.image_converter, exc)
|
||||
return False
|
||||
except CalledProcessError as exc:
|
||||
logger.warning(__('convert exited with error:\n'
|
||||
|
@ -26,7 +26,6 @@ from sphinx import package_dir
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging, sha1
|
||||
@ -58,35 +57,8 @@ class InvokeError(SphinxError):
|
||||
|
||||
SUPPORT_FORMAT = ('png', 'svg')
|
||||
|
||||
DOC_HEAD = r'''
|
||||
\documentclass[12pt]{article}
|
||||
\usepackage[utf8x]{inputenc}
|
||||
\usepackage{amsmath}
|
||||
\usepackage{amsthm}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{amsfonts}
|
||||
\usepackage{anyfontsize}
|
||||
\usepackage{bm}
|
||||
\pagestyle{empty}
|
||||
'''
|
||||
|
||||
DOC_BODY = r'''
|
||||
\begin{document}
|
||||
\fontsize{%d}{%d}\selectfont %s
|
||||
\end{document}
|
||||
'''
|
||||
|
||||
DOC_BODY_PREVIEW = r'''
|
||||
\usepackage[active]{preview}
|
||||
\begin{document}
|
||||
\begin{preview}
|
||||
\fontsize{%s}{%s}\selectfont %s
|
||||
\end{preview}
|
||||
\end{document}
|
||||
'''
|
||||
|
||||
depth_re = re.compile(br'\[\d+ depth=(-?\d+)\]')
|
||||
depthsvg_re = re.compile(br'.*, depth=(.*)pt')
|
||||
depth_re = re.compile(r'\[\d+ depth=(-?\d+)\]')
|
||||
depthsvg_re = re.compile(r'.*, depth=(.*)pt')
|
||||
depthsvgcomment_re = re.compile(r'<!-- DEPTH=(-?\d+) -->')
|
||||
|
||||
|
||||
@ -174,10 +146,10 @@ def compile_math(latex: str, builder: Builder) -> str:
|
||||
raise MathExtError('latex exited with error', exc.stderr, exc.stdout) from exc
|
||||
|
||||
|
||||
def convert_dvi_to_image(command: List[str], name: str) -> Tuple[bytes, bytes]:
|
||||
def convert_dvi_to_image(command: List[str], name: str) -> Tuple[str, str]:
|
||||
"""Convert DVI file to specific image format."""
|
||||
try:
|
||||
ret = subprocess.run(command, stdout=PIPE, stderr=PIPE, check=True)
|
||||
ret = subprocess.run(command, stdout=PIPE, stderr=PIPE, check=True, encoding='ascii')
|
||||
return ret.stdout, ret.stderr
|
||||
except OSError as exc:
|
||||
logger.warning(__('%s command %r cannot be run (needed for math '
|
||||
@ -370,15 +342,6 @@ def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None
|
||||
raise nodes.SkipNode
|
||||
|
||||
|
||||
deprecated_alias('sphinx.ext.imgmath',
|
||||
{
|
||||
'DOC_BODY': DOC_BODY,
|
||||
'DOC_BODY_PREVIEW': DOC_BODY_PREVIEW,
|
||||
'DOC_HEAD': DOC_HEAD,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_html_math_renderer('imgmath',
|
||||
(html_visit_math, None),
|
||||
|
@ -53,6 +53,7 @@ from sphinx.ext.graphviz import (figure_wrapper, graphviz, render_dot_html, rend
|
||||
render_dot_texinfo)
|
||||
from sphinx.util import md5
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.typing import OptionSpec
|
||||
from sphinx.writers.html import HTMLTranslator
|
||||
from sphinx.writers.latex import LaTeXTranslator
|
||||
from sphinx.writers.texinfo import TexinfoTranslator
|
||||
@ -154,7 +155,7 @@ class InheritanceGraph:
|
||||
|
||||
def _import_classes(self, class_names: List[str], currmodule: str) -> List[Any]:
|
||||
"""Import a list of classes."""
|
||||
classes = [] # type: List[Any]
|
||||
classes: List[Any] = []
|
||||
for name in class_names:
|
||||
classes.extend(import_classes(name, currmodule))
|
||||
return classes
|
||||
@ -198,7 +199,7 @@ class InheritanceGraph:
|
||||
except Exception: # might raise AttributeError for strange classes
|
||||
pass
|
||||
|
||||
baselist = [] # type: List[str]
|
||||
baselist: List[str] = []
|
||||
all_classes[cls] = (nodename, fullname, baselist, tooltip)
|
||||
|
||||
if fullname in top_classes:
|
||||
@ -292,7 +293,7 @@ class InheritanceGraph:
|
||||
n_attrs.update(env.config.inheritance_node_attrs)
|
||||
e_attrs.update(env.config.inheritance_edge_attrs)
|
||||
|
||||
res = [] # type: List[str]
|
||||
res: List[str] = []
|
||||
res.append('digraph %s {\n' % name)
|
||||
res.append(self._format_graph_attrs(g_attrs))
|
||||
|
||||
@ -331,7 +332,7 @@ class InheritanceDiagram(SphinxDirective):
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
option_spec: OptionSpec = {
|
||||
'parts': int,
|
||||
'private-bases': directives.flag,
|
||||
'caption': directives.unchanged,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user