Merge branch '3.x' into 7774_remove_develop.rst

This commit is contained in:
Takeshi KOMIYA 2021-01-24 16:34:47 +09:00
commit 51d500833e
610 changed files with 17988 additions and 4879 deletions

View File

@ -3,12 +3,14 @@ jobs:
build: build:
docker: docker:
- image: sphinxdoc/docker-ci - image: sphinxdoc/docker-ci
environment:
DO_EPUBCHECK: 1
working_directory: /sphinx working_directory: /sphinx
steps: steps:
- checkout - checkout
- run: /python3.6/bin/pip install -U pip setuptools - run: /python3.6/bin/pip install -U pip setuptools
- run: /python3.6/bin/pip install -U .[test] - run: /python3.6/bin/pip install -U .[test]
- run: mkdir -p test-reports/pytest - run: mkdir -p test-reports/pytest
- run: make test PYTHON=/python3.6/bin/python TEST=--junitxml=test-reports/pytest/results.xml - run: make test PYTHON=/python3.6/bin/python TEST="--junitxml=test-reports/pytest/results.xml -vv"
- store_test_results: - store_test_results:
path: test-reports path: test-reports

View File

@ -2,5 +2,8 @@
blank_issues_enabled: false # default: true blank_issues_enabled: false # default: true
contact_links: contact_links:
- name: Question - name: Question
url: https://stackoverflow.com/questions/tagged/python-sphinx
about: For Q&A purpose, please use Stackoverflow with the tag python-sphinx
- name: Discussion
url: https://groups.google.com/forum/#!forum/sphinx-users url: https://groups.google.com/forum/#!forum/sphinx-users
about: For Q&A purpose, please use sphinx-users mailing list. about: For general discussion, please use sphinx-users mailing list.

View File

@ -7,7 +7,7 @@ Subject: <short purpose of this pull request>
- Critical or severe bugs: X.Y.Z - Critical or severe bugs: X.Y.Z
- Others: X.Y - Others: X.Y
For more details, see https://www.sphinx-doc.org/en/master/devguide.html#branch-model For more details, see https://www.sphinx-doc.org/en/master/internals/release-process.html#branch-model
--> -->
### Feature or Bugfix ### Feature or Bugfix

21
.github/workflows/builddoc.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Build document
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y graphviz
pip install -U tox
- name: Run Tox
run: tox -e docs

22
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Lint source code
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
tool: [docslint, flake8, isort, mypy, twine]
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Install dependencies
run: pip install -U tox
- name: Run Tox
run: tox -e ${{ matrix.tool }}

View File

@ -1,9 +1,64 @@
name: CI on Windows name: CI
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: ubuntu:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
name: [py35, py36, py37, py38, py39]
os: [ubuntu-16.04]
include:
- name: py35
python: 3.5
docutils: du12
- name: py36
python: 3.6
docutils: du13
- name: py37
python: 3.7
docutils: du14
- name: py38
python: 3.8
docutils: du15
- name: py39
python: 3.9
docutils: du16
coverage: "--cov ./ --cov-append --cov-config setup.cfg"
- name: py310-dev
python: 3.10-dev
docutils: du16
os: ubuntu-latest # required
env:
PYTEST_ADDOPTS: ${{ matrix.coverage }}
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v2
if: "!endsWith(matrix.python, '-dev')"
with:
python-version: ${{ matrix.python }}
- name: Set up Python ${{ matrix.python }} (deadsnakes)
uses: deadsnakes/action@v2.0.1
if: endsWith(matrix.python, '-dev')
with:
python-version: ${{ matrix.python }}
- name: Check Python version
run: python --version
- name: Install graphviz
run: sudo apt-get install graphviz
- name: Install dependencies
run: pip install -U tox codecov
- name: Run Tox
run: tox -e ${{ matrix.docutils }} -- -vv
- name: codecov
uses: codecov/codecov-action@v1
if: matrix.coverage
windows:
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
matrix: matrix:
@ -18,4 +73,4 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: pip install -U tox run: pip install -U tox
- name: Run Tox - name: Run Tox
run: tox -e py run: tox -e py -- -vv

21
.github/workflows/nodejs.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: CI (node.js)
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
env:
node-version: 10.7
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ env.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ env.node-version }}
- run: npm install
- name: Run headless test
uses: GabrielBB/xvfb-action@v1
with:
run: npm test

8
.readthedocs.yml Normal file
View File

@ -0,0 +1,8 @@
version: 2
python:
version: 3
install:
- method: pip
path: .
extra_requirements:
- docs

View File

@ -1,54 +0,0 @@
os: linux
dist: xenial
language: python
cache: pip
env:
global:
- PYTHONFAULTHANDLER=x
- SKIP_LATEX_BUILD=1
- IS_PYTHON=true
jobs:
include:
- python: '3.5'
env:
- TOXENV=du12
- python: '3.6'
env:
- TOXENV=du13
- python: '3.7'
env:
- TOXENV=du14
- python: '3.8'
env:
- TOXENV=du15
- PYTEST_ADDOPTS="--cov ./ --cov-append --cov-config setup.cfg"
- python: 'nightly'
env:
- TOXENV=du16
- python: '3.6'
env: TOXENV=docs
- python: '3.6'
env: TOXENV=docslint
- python: '3.6'
env: TOXENV=mypy
- python: '3.6'
env: TOXENV=flake8
- language: node_js
node_js: '10.7'
env: IS_PYTHON=false
services: xvfb
install:
- "sudo apt-get install graphviz"
- if [ $IS_PYTHON = true ]; then pip install -U tox codecov; fi
- if [ $IS_PYTHON = false ]; then npm install; fi
script:
- if [ $IS_PYTHON = true ]; then tox -- -v; fi
- if [ $IS_PYTHON = false ]; then npm test; fi
after_success:
- if [[ -e .coverage ]]; then codecov -e $TOXENV; fi

596
CHANGES
View File

@ -1,9 +1,555 @@
Release 3.1.0 (in development) Release 3.5.0 (in development)
============================== ==============================
Dependencies Dependencies
------------ ------------
Incompatible changes
--------------------
* Update Underscore.js to 1.12.0
* #6550: html: The config variable ``html_add_permalinks`` is replaced by
:confval:`html_permalinks` and :confval:`html_permalinks_icon`
Deprecated
----------
* pending_xref node for viewcode extension
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken``
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.good``
* ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.redirected``
* ``sphinx.builders.linkcheck.node_line_or_0()``
* ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()``
* ``sphinx.ext.autodoc.directive.DocumenterBridge.reporter``
* ``sphinx.ext.autodoc.importer.get_module_members()``
* ``sphinx.ext.autosummary.generate._simple_info()``
* ``sphinx.ext.autosummary.generate._simple_warn()``
* ``sphinx.writers.html.HTMLTranslator.permalink_text``
* ``sphinx.writers.html5.HTML5Translator.permalink_text``
Features added
--------------
* #8022: autodoc: autodata and autoattribute directives does not show right-hand
value of the variable if docstring contains ``:meta hide-value:`` in
info-field-list
* #8514: autodoc: Default values of overloaded functions are taken from actual
implementation if they're ellipsis
* #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()`
* #6241: html: Allow to add JS/CSS files to the specific page when an extension
calls ``app.add_js_file()`` or ``app.add_css_file()`` on
:event:`html-page-context` event
* #6550: html: Allow to use HTML permalink texts via
:confval:`html_permalinks_icon`
* #8649: imgconverter: Skip availability check if builder supports the image
type
* #8573: napoleon: Allow to change the style of custom sections using
:confval:`napoleon_custom_styles`
* #8004: napoleon: Type definitions in Google style docstrings are rendered as
references when :confval:`napoleon_preprocess_types` enabled
* #6241: mathjax: Include mathjax.js only on the document using equations
* #8651: std domain: cross-reference for a rubric having inline item is broken
* #8681: viewcode: Support incremental build
* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright`
* #207: Now :confval:`highlight_language` supports multiple languages
* #2030: :rst:dir:`code-block` and :rst:dir:`literalinclude` supports automatic
dedent via no-argument ``:dedent:`` option
* C++, also hyperlink operator overloads in expressions and alias declarations.
* #8247: Allow production lists to refer to tokens from other production groups
Bugs fixed
----------
* #8727: apidoc: namespace module file is not generated if no submodules there
* #741: autodoc: inherited-members doesn't work for instance attributes on super
class
* #8592: autodoc: ``:meta public:`` does not effect to variables
* #8594: autodoc: empty __all__ attribute is ignored
* #8315: autodoc: Failed to resolve struct.Struct type annotation
* #8652: autodoc: All variable comments in the module are ignored if the module
contains invalid type comments
* #8693: autodoc: Default values for overloaded functions are rendered as string
* #8306: autosummary: mocked modules are documented as empty page when using
:recursive: option
* #8618: html: kbd role produces incorrect HTML when compound-key separators (-,
+ or ^) are used as keystrokes
* #8629: html: A type warning for html_use_opensearch is shown twice
* #8714: html: kbd role with "Caps Lock" rendered incorrectly
* #8665: html theme: Could not override globaltoc_maxdepth in theme.conf
* #4304: linkcheck: Fix race condition that could lead to checking the
availability of the same URL twice
* #8094: texinfo: image files on the different directory with document are not
copied
* #8720: viewcode: module pages are generated for epub on incremental build
* #8704: viewcode: anchors are generated in incremental build after singlehtml
* #8671: :confval:`highlight_options` is not working
* #8341: C, fix intersphinx lookup types for names in declarations.
* C, C++: in general fix intersphinx and role lookup types.
* #8683: :confval:`html_last_updated_fmt` does not support UTC offset (%z)
* #8683: :confval:`html_last_updated_fmt` generates wrong time zone for %Z
* #1112: ``download`` role creates duplicated copies when relative path is
specified
* #8735: LaTeX: wrong internal links in pdf to captioned code-blocks when
:confval:`numfig` is not True
Testing
--------
Release 3.4.4 (in development)
==============================
Dependencies
------------
Incompatible changes
--------------------
Deprecated
----------
Features added
--------------
Bugs fixed
----------
* #8655: autodoc: Failed to generate document if target module contains an
object that raises an exception on ``hasattr()``
* C, ``expr`` role should start symbol lookup in the current scope.
Testing
--------
Release 3.4.3 (released Jan 08, 2021)
=====================================
Bugs fixed
----------
* #8655: autodoc: Failed to generate document if target module contains an
object that raises an exception on ``hasattr()``
Release 3.4.2 (released Jan 04, 2021)
=====================================
Bugs fixed
----------
* #8164: autodoc: Classes that inherit mocked class are not documented
* #8602: autodoc: The ``autodoc-process-docstring`` event is emitted to the
non-datadescriptors unexpectedly
* #8616: autodoc: AttributeError is raised on non-class object is passed to
autoclass directive
Release 3.4.1 (released Dec 25, 2020)
=====================================
Bugs fixed
----------
* #8559: autodoc: AttributeError is raised when using forward-reference type
annotations
* #8568: autodoc: TypeError is raised on checking slots attribute
* #8567: autodoc: Instance attributes are incorrectly added to Parent class
* #8566: autodoc: The ``autodoc-process-docstring`` event is emitted to the
alias classes unexpectedly
* #8583: autodoc: Unnecessary object comparision via ``__eq__`` method
* #8565: linkcheck: Fix PriorityQueue crash when link tuples are not
comparable
Release 3.4.0 (released Dec 20, 2020)
=====================================
Incompatible changes
--------------------
* #8105: autodoc: the signature of class constructor will be shown for decorated
classes, not a signature of decorator
Deprecated
----------
* The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()``
* The ``no_docstring`` argument of
``sphinx.ext.autodoc.Documenter.add_content()``
* ``sphinx.ext.autodoc.Documenter.get_object_members()``
* ``sphinx.ext.autodoc.DataDeclarationDocumenter``
* ``sphinx.ext.autodoc.GenericAliasDocumenter``
* ``sphinx.ext.autodoc.InstanceAttributeDocumenter``
* ``sphinx.ext.autodoc.SlotsAttributeDocumenter``
* ``sphinx.ext.autodoc.TypeVarDocumenter``
* ``sphinx.ext.autodoc.importer._getannotations()``
* ``sphinx.ext.autodoc.importer._getmro()``
* ``sphinx.pycode.ModuleAnalyzer.parse()``
* ``sphinx.util.osutil.movefile()``
* ``sphinx.util.requests.is_ssl_error()``
Features added
--------------
* #8119: autodoc: Allow to determine whether a member not included in
``__all__`` attribute of the module should be documented or not via
:event:`autodoc-skip-member` event
* #8219: autodoc: Parameters for generic class are not shown when super class is
a generic class and show-inheritance option is given (in Python 3.7 or above)
* autodoc: Add ``Documenter.config`` as a shortcut to access the config object
* autodoc: Add Optional[t] to annotation of function and method if a default
value equal to None is set.
* #8209: autodoc: Add ``:no-value:`` option to :rst:dir:`autoattribute` and
:rst:dir:`autodata` directive to suppress the default value of the variable
* #8460: autodoc: Support custom types defined by typing.NewType
* #8285: napoleon: Add :confval:`napoleon_attr_annotations` to merge type hints
on source code automatically if any type is specified in docstring
* #8236: napoleon: Support numpydoc's "Receives" section
* #6914: Add a new event :event:`warn-missing-reference` to custom warning
messages when failed to resolve a cross-reference
* #6914: Emit a detailed warning when failed to resolve a ``:ref:`` reference
* #6629: linkcheck: The builder now handles rate limits. See
:confval:`linkcheck_retry_on_rate_limit` for details.
Bugs fixed
----------
* #7613: autodoc: autodoc does not respect __signature__ of the class
* #4606: autodoc: the location of the warning is incorrect for inherited method
* #8105: autodoc: the signature of class constructor is incorrect if the class
is decorated
* #8434: autodoc: :confval:`autodoc_type_aliases` does not effect to variables
and attributes
* #8443: autodoc: autodata directive can't create document for PEP-526 based
type annotated variables
* #8443: autodoc: autoattribute directive can't create document for PEP-526
based uninitalized variables
* #8480: autodoc: autoattribute could not create document for __slots__
attributes
* #8503: autodoc: autoattribute could not create document for a GenericAlias as
class attributes correctly
* #8534: autodoc: autoattribute could not create document for a commented
attribute in alias class
* #8452: autodoc: autodoc_type_aliases doesn't work when autodoc_typehints is
set to "description"
* #8541: autodoc: autodoc_type_aliases doesn't work for the type annotation to
instance attributes
* #8460: autodoc: autodata and autoattribute directives do not display type
information of TypeVars
* #8493: autodoc: references to builtins not working in class aliases
* #8522: autodoc: ``__bool__`` method could be called
* #8067: autodoc: A typehint for the instance variable having type_comment on
super class is not displayed
* #8545: autodoc: a __slots__ attribute is not documented even having docstring
* #741: autodoc: inherited-members doesn't work for instance attributes on super
class
* #8477: autosummary: non utf-8 reST files are generated when template contains
multibyte characters
* #8501: autosummary: summary extraction splits text after "el at." unexpectedly
* #8524: html: Wrong url_root has been generated on a document named "index"
* #8419: html search: Do not load ``language_data.js`` in non-search pages
* #8549: i18n: ``-D gettext_compact=0`` is no longer working
* #8454: graphviz: The layout option for graph and digraph directives don't work
* #8131: linkcheck: Use GET when HEAD requests cause Too Many Redirects, to
accommodate infinite redirect loops on HEAD
* #8437: Makefile: ``make clean`` with empty BUILDDIR is dangerous
* #8365: py domain: ``:type:`` and ``:rtype:`` gives false ambiguous class
lookup warnings
* #8352: std domain: Failed to parse an option that starts with bracket
* #8519: LaTeX: Prevent page brake in the middle of a seealso
* #8520: C, fix copying of AliasNode.
Release 3.3.1 (released Nov 12, 2020)
=====================================
Bugs fixed
----------
* #8372: autodoc: autoclass directive became slower than Sphinx-3.2
* #7727: autosummary: raise PycodeError when documenting python package
without __init__.py
* #8350: autosummary: autosummary_mock_imports causes slow down builds
* #8364: C, properly initialize attributes in empty symbols.
* #8399: i18n: Put system locale path after the paths specified by configuration
Release 3.3.0 (released Nov 02, 2020)
=====================================
Deprecated
----------
* ``sphinx.builders.latex.LaTeXBuilder.usepackages``
* ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref``
* ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter``
* ``sphinx.ext.autodoc.SingledispatchMethodDocumenter``
Features added
--------------
* #8100: html: Show a better error message for failures on copying
html_static_files
* #8141: C: added a ``maxdepth`` option to :rst:dir:`c:alias` to insert
nested declarations.
* #8081: LaTeX: Allow to add LaTeX package via ``app.add_latex_package()`` until
just before writing .tex file
* #7996: manpage: Add :confval:`man_make_section_directory` to make a section
directory on build man page
* #8289: epub: Allow to suppress "duplicated ToC entry found" warnings from epub
builder using :confval:`suppress_warnings`.
* #8298: sphinx-quickstart: Add :option:`sphinx-quickstart --no-sep` option
* #8304: sphinx.testing: Register public markers in sphinx.testing.fixtures
* #8051: napoleon: use the obj role for all See Also items
* #8050: napoleon: Apply :confval:`napoleon_preprocess_types` to every field
* C and C++, show line numbers for previous declarations when duplicates are
detected.
* #8183: Remove substitution_reference nodes from doctree only on LaTeX builds
Bugs fixed
----------
* #8085: i18n: Add support for having single text domain
* #6640: i18n: Failed to override system message translation
* #8143: autodoc: AttributeError is raised when False value is passed to
autodoc_default_options
* #8103: autodoc: functools.cached_property is not considered as a property
* #8190: autodoc: parsing error is raised if some extension replaces docstring
by string not ending with blank lines
* #8142: autodoc: Wrong constructor signature for the class derived from
typing.Generic
* #8157: autodoc: TypeError is raised when annotation has invalid __args__
* #7964: autodoc: Tuple in default value is wrongly rendered
* #8200: autodoc: type aliases break type formatting of autoattribute
* #7786: autodoc: can't detect overloaded methods defined in other file
* #8294: autodoc: single-string __slots__ is not handled correctly
* #7785: autodoc: autodoc_typehints='none' does not effect to overloaded functions
* #8192: napoleon: description is disappeared when it contains inline literals
* #8142: napoleon: Potential of regex denial of service in google style docs
* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex
* #8215: LaTeX: 'oneside' classoption causes build warning
* #8175: intersphinx: Potential of regex denial of service by broken inventory
* #8277: sphinx-build: missing and redundant spacing (and etc) for console
output on building
* #7973: imgconverter: Check availability of imagemagick many times
* #8255: py domain: number in default argument value is changed from hexadecimal
to decimal
* #8316: html: Prevent arrow keys changing page when button elements are focused
* #8343: html search: Fix unnecessary load of images when parsing the document
* #8254: html theme: Line numbers misalign with code lines
* #8093: The highlight warning has wrong location in some builders (LaTeX,
singlehtml and so on)
* #8215: Eliminate Fancyhdr build warnings for oneside documents
* #8239: Failed to refer a token in productionlist if it is indented
* #8268: linkcheck: Report HTTP errors when ``linkcheck_anchors`` is ``True``
* #8245: linkcheck: take source directory into account for local files
* #8321: linkcheck: ``tel:`` schema hyperlinks are detected as errors
* #8323: linkcheck: An exit status is incorrect when links having unsupported
schema found
* #8188: C, add missing items to internal object types dictionary,
e.g., preventing intersphinx from resolving them.
* C, fix anon objects in intersphinx.
* #8270, C++, properly reject functions as duplicate declarations if a
non-function declaration of the same name already exists.
* C, fix references to function parameters.
Link to the function instead of a non-existing anchor.
* #6914: figure numbers are unexpectedly assigned to uncaptioned items
* #8320: make "inline" line numbers un-selectable
Testing
--------
* #8257: Support parallel build in sphinx.testing
Release 3.2.1 (released Aug 14, 2020)
=====================================
Features added
--------------
* #8095: napoleon: Add :confval:`napoleon_preprocess_types` to enable the type
preprocessor for numpy style docstrings
* #8114: C and C++, parse function attributes after parameters and qualifiers.
Bugs fixed
----------
* #8074: napoleon: Crashes during processing C-ext module
* #8088: napoleon: "Inline literal start-string without end-string" warning in
Numpy style Parameters section
* #8084: autodoc: KeyError is raised on documenting an attribute of the broken
class
* #8091: autodoc: AttributeError is raised on documenting an attribute on Python
3.5.2
* #8099: autodoc: NameError is raised when target code uses ``TYPE_CHECKING``
* C++, fix parsing of template template paramters, broken by the fix of #7944
Release 3.2.0 (released Aug 08, 2020)
=====================================
Deprecated
----------
* ``sphinx.ext.autodoc.members_set_option()``
* ``sphinx.ext.autodoc.merge_special_members_option()``
* ``sphinx.writers.texinfo.TexinfoWriter.desc``
* C, parsing of pre-v3 style type directives and roles, along with the options
:confval:`c_allow_pre_v3` and :confval:`c_warn_on_allowed_pre_v3`.
Features added
--------------
* #2076: autodoc: Allow overriding of exclude-members in skip-member function
* #8034: autodoc: ``:private-member:`` can take an explicit list of member names
to be documented
* #2024: autosummary: Add :confval:`autosummary_filename_map` to avoid conflict
of filenames between two object with different case
* #8011: autosummary: Support instance attributes as a target of autosummary
directive
* #7849: html: Add :confval:`html_codeblock_linenos_style` to change the style
of line numbers for code-blocks
* #7853: C and C++, support parameterized GNU style attributes.
* #7888: napoleon: Add aliases Warn and Raise.
* #7690: napoleon: parse type strings and make them hyperlinks as possible. The
conversion rule can be updated via :confval:`napoleon_type_aliases`
* #8049: napoleon: Create a hyperlink for each the type of parameter when
:confval:`napoleon_use_params` is False
* C, added :rst:dir:`c:alias` directive for inserting copies
of existing declarations.
* #7745: html: inventory is broken if the docname contains a space
* #7991: html search: Allow searching for numbers
* #7902: html theme: Add a new option :confval:`globaltoc_maxdepth` to control
the behavior of globaltoc in sidebar
* #7840: i18n: Optimize the dependencies check on bootstrap
* #7768: i18n: :confval:`figure_language_filename` supports ``docpath`` token
* #5208: linkcheck: Support checks for local links
* #5090: setuptools: Link verbosity to distutils' -v and -q option
* #6698: doctest: Add ``:trim-doctest-flags:`` and ``:no-trim-doctest-flags:``
options to doctest, testcode and testoutput directives
* #7052: add ``:noindexentry:`` to the Python, C, C++, and Javascript domains.
Update the documentation to better reflect the relationship between this option
and the ``:noindex:`` option.
* #7899: C, add possibility of parsing of some pre-v3 style type directives and
roles and try to convert them to equivalent v3 directives/roles.
Set the new option :confval:`c_allow_pre_v3` to ``True`` to enable this.
The warnings printed from this functionality can be suppressed by setting
:confval:`c_warn_on_allowed_pre_v3`` to ``True``.
The functionality is immediately deprecated.
* #7999: C, add support for named variadic macro arguments.
* #8071: Allow to suppress "self referenced toctrees" warning
Bugs fixed
----------
* #7886: autodoc: TypeError is raised on mocking generic-typed classes
* #7935: autodoc: function signature is not shown when the function has a
parameter having ``inspect._empty`` as its default value
* #7901: autodoc: type annotations for overloaded functions are not resolved
* #904: autodoc: An instance attribute cause a crash of autofunction directive
* #1362: autodoc: ``private-members`` option does not work for class attributes
* #7983: autodoc: Generator type annotation is wrongly rendered in py36
* #8030: autodoc: An uninitialized annotated instance variable is not documented
when ``:inherited-members:`` option given
* #8032: autodoc: A type hint for the instance variable defined at parent class
is not shown in the document of the derived class
* #8041: autodoc: An annotated instance variable on super class is not
documented when derived class has other annotated instance variables
* #7839: autosummary: cannot handle umlauts in function names
* #7865: autosummary: Failed to extract summary line when abbreviations found
* #7866: autosummary: Failed to extract correct summary line when docstring
contains a hyperlink target
* #7469: autosummary: "Module attributes" header is not translatable
* #7940: apidoc: An extra newline is generated at the end of the rst file if a
module has submodules
* #4258: napoleon: decorated special methods are not shown
* #7799: napoleon: parameters are not escaped for combined params in numpydoc
* #7780: napoleon: multiple paramaters declaration in numpydoc was wrongly
recognized when napoleon_use_params=True
* #7715: LaTeX: ``numfig_secnum_depth > 1`` leads to wrong figure links
* #7846: html theme: XML-invalid files were generated
* #7894: gettext: Wrong source info is shown when using rst_epilog
* #7691: linkcheck: HEAD requests are not used for checking
* #4888: i18n: Failed to add an explicit title to ``:ref:`` role on translation
* #7928: py domain: failed to resolve a type annotation for the attribute
* #8008: py domain: failed to parse a type annotation containing ellipsis
* #7994: std domain: option directive does not generate old node_id compatible
with 2.x or older
* #7968: i18n: The content of ``math`` directive is interpreted as reST on
translation
* #7768: i18n: The ``root`` element for :confval:`figure_language_filename` is
not a path that user specifies in the document
* #7993: texinfo: TypeError is raised for nested object descriptions
* #7993: texinfo: a warning not supporting desc_signature_line node is shown
* #7869: :rst:role:`abbr` role without an explanation will show the explanation
from the previous abbr role
* #8048: graphviz: graphviz.css was copied on building non-HTML document
* C and C++, removed ``noindex`` directive option as it did
nothing.
* #7619: Duplicated node IDs are generated if node has multiple IDs
* #2050: Symbols sections are appeared twice in the index page
* #8017: Fix circular import in sphinx.addnodes
* #7986: CSS: make "highlight" selector more robust
* #7944: C++, parse non-type template parameters starting with
a dependent qualified name.
* C, don't deepcopy the entire symbol table and make a mess every time an
enumerator is handled.
Release 3.1.2 (released Jul 05, 2020)
=====================================
Incompatible changes
--------------------
* #7650: autodoc: the signature of base function will be shown for decorated
functions, not a signature of decorator
Bugs fixed
----------
* #7844: autodoc: Failed to detect module when relative module name given
* #7856: autodoc: AttributeError is raised when non-class object is given to
the autoclass directive
* #7850: autodoc: KeyError is raised for invalid mark up when autodoc_typehints
is 'description'
* #7812: autodoc: crashed if the target name matches to both an attribute and
module that are same name
* #7650: autodoc: function signature becomes ``(*args, **kwargs)`` if the
function is decorated by generic decorator
* #7812: autosummary: generates broken stub files if the target code contains
an attribute and module that are same name
* #7806: viewcode: Failed to resolve viewcode references on 3rd party builders
* #7838: html theme: List items have extra vertical space
* #7878: html theme: Undesired interaction between "overflow" and "float"
Release 3.1.1 (released Jun 14, 2020)
=====================================
Incompatible changes
--------------------
* #7808: napoleon: a type for attribute are represented as typed field
Features added
--------------
* #7807: autodoc: Show detailed warning when type_comment is mismatched with its
signature
Bugs fixed
----------
* #7808: autodoc: Warnings raised on variable and attribute type annotations
* #7802: autodoc: EOFError is raised on parallel build
* #7821: autodoc: TypeError is raised for overloaded C-ext function
* #7805: autodoc: an object which descriptors returns is unexpectedly documented
* #7807: autodoc: wrong signature is shown for the function using contextmanager
* #7812: autosummary: generates broken stub files if the target code contains
an attribute and module that are same name
* #7808: napoleon: Warnings raised on variable and attribute type annotations
* #7811: sphinx.util.inspect causes circular import problem
Release 3.1.0 (released Jun 08, 2020)
=====================================
Dependencies
------------
* #7746: mathjax: Update to 2.7.5 * #7746: mathjax: Update to 2.7.5
Incompatible changes Incompatible changes
@ -51,6 +597,8 @@ Features added
builtin base classes builtin base classes
* #2106: autodoc: Support multiple signatures on docstring * #2106: autodoc: Support multiple signatures on docstring
* #4422: autodoc: Support GenericAlias in Python 3.7 or above * #4422: autodoc: Support GenericAlias in Python 3.7 or above
* #3610: autodoc: Support overloaded functions
* #7722: autodoc: Support TypeVar
* #7466: autosummary: headings in generated documents are not translated * #7466: autosummary: headings in generated documents are not translated
* #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a * #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a
caption to the toctree caption to the toctree
@ -61,7 +609,8 @@ Features added
variables for custom templates variables for custom templates
* #7530: html: Support nested <kbd> elements * #7530: html: Support nested <kbd> elements
* #7481: html theme: Add right margin to footnote/citation labels * #7481: html theme: Add right margin to footnote/citation labels
* #7482: html theme: CSS spacing for code blocks with captions and line numbers * #7482, #7717: html theme: CSS spacing for code blocks with captions and line
numbers
* #7443: html theme: Add new options :confval:`globaltoc_collapse` and * #7443: html theme: Add new options :confval:`globaltoc_collapse` and
:confval:`globaltoc_includehidden` to control the behavior of globaltoc in :confval:`globaltoc_includehidden` to control the behavior of globaltoc in
sidebar sidebar
@ -73,6 +622,8 @@ Features added
* #7542: html theme: Make admonition/topic/sidebar scrollable * #7542: html theme: Make admonition/topic/sidebar scrollable
* #7543: html theme: Add top and bottom margins to tables * #7543: html theme: Add top and bottom margins to tables
* #7695: html theme: Add viewport meta tag for basic theme * #7695: html theme: Add viewport meta tag for basic theme
* #7721: html theme: classic: default codetextcolor/codebgcolor doesn't override
Pygments
* C and C++: allow semicolon in the end of declarations. * C and C++: allow semicolon in the end of declarations.
* C++, parse parameterized noexcept specifiers. * C++, parse parameterized noexcept specifiers.
* #7294: C++, parse expressions with user-defined literals. * #7294: C++, parse expressions with user-defined literals.
@ -80,8 +631,13 @@ Features added
* #7143: py domain: Add ``:final:`` option to :rst:dir:`py:class:`, * #7143: py domain: Add ``:final:`` option to :rst:dir:`py:class:`,
:rst:dir:`py:exception:` and :rst:dir:`py:method:` directives :rst:dir:`py:exception:` and :rst:dir:`py:method:` directives
* #7596: py domain: Change a type annotation for variables to a hyperlink * #7596: py domain: Change a type annotation for variables to a hyperlink
* #7770: std domain: :rst:dir:`option` directive support arguments in the form
of ``foo[=bar]``
* #7582: napoleon: a type for attribute are represented like type annotation * #7582: napoleon: a type for attribute are represented like type annotation
* #7734: napoleon: overescaped trailing underscore on attribute * #7734: napoleon: overescaped trailing underscore on attribute
* #7247: linkcheck: Add :confval:`linkcheck_request_headers` to send custom HTTP
headers for specific host
* #7792: setuptools: Support ``--verbosity`` option
* #7683: Add ``allowed_exceptions`` parameter to ``Sphinx.emit()`` to allow * #7683: Add ``allowed_exceptions`` parameter to ``Sphinx.emit()`` to allow
handlers to raise specified exceptions handlers to raise specified exceptions
* #7295: C++, parse (trailing) requires clauses. * #7295: C++, parse (trailing) requires clauses.
@ -113,6 +669,7 @@ Bugs fixed
* #7668: autodoc: wrong retann value is passed to a handler of * #7668: autodoc: wrong retann value is passed to a handler of
autodoc-proccess-signature autodoc-proccess-signature
* #7711: autodoc: fails with ValueError when processing numpy objects * #7711: autodoc: fails with ValueError when processing numpy objects
* #7791: autodoc: TypeError is raised on documenting singledispatch function
* #7551: autosummary: a nested class is indexed as non-nested class * #7551: autosummary: a nested class is indexed as non-nested class
* #7661: autosummary: autosummary directive emits warnings twices if failed to * #7661: autosummary: autosummary directive emits warnings twices if failed to
import the target module import the target module
@ -121,8 +678,12 @@ Bugs fixed
* #7671: autosummary: The location of import failure warning is missing * #7671: autosummary: The location of import failure warning is missing
* #7535: sphinx-autogen: crashes when custom template uses inheritance * #7535: sphinx-autogen: crashes when custom template uses inheritance
* #7536: sphinx-autogen: crashes when template uses i18n feature * #7536: sphinx-autogen: crashes when template uses i18n feature
* #7781: sphinx-build: Wrong error message when outdir is not directory
* #7653: sphinx-quickstart: Fix multiple directory creation for nested relpath * #7653: sphinx-quickstart: Fix multiple directory creation for nested relpath
* #2785: html: Bad alignment of equation links * #2785: html: Bad alignment of equation links
* #7718: html theme: some themes does not respect background color of Pygments
style (agogo, haiku, nature, pyramid, scrolls, sphinxdoc and traditional)
* #7544: html theme: inconsistent padding in admonitions
* #7581: napoleon: bad parsing of inline code in attribute docstrings * #7581: napoleon: bad parsing of inline code in attribute docstrings
* #7628: imgconverter: runs imagemagick once unnecessary for builders not * #7628: imgconverter: runs imagemagick once unnecessary for builders not
supporting images supporting images
@ -130,7 +691,10 @@ Bugs fixed
* #7646: handle errors on event handlers * #7646: handle errors on event handlers
* #4187: LaTeX: EN DASH disappears from PDF bookmarks in Japanese documents * #4187: LaTeX: EN DASH disappears from PDF bookmarks in Japanese documents
* #7701: LaTeX: Anonymous indirect hyperlink target causes duplicated labels * #7701: LaTeX: Anonymous indirect hyperlink target causes duplicated labels
* #7723: LaTeX: pdflatex crashed when URL contains a single quote
* #7756: py domain: The default value for positional only argument is not shown * #7756: py domain: The default value for positional only argument is not shown
* #7760: coverage: Add :confval:`coverage_show_missing_items` to show coverage
result to console
* C++, fix rendering and xrefs in nested names explicitly starting * C++, fix rendering and xrefs in nested names explicitly starting
in global scope, e.g., ``::A::B``. in global scope, e.g., ``::A::B``.
* C, fix rendering and xrefs in nested names explicitly starting * C, fix rendering and xrefs in nested names explicitly starting
@ -138,30 +702,6 @@ Bugs fixed
* #7763: C and C++, don't crash during display stringification of unary * #7763: C and C++, don't crash during display stringification of unary
expressions and fold expressions. expressions and fold expressions.
Testing
--------
Release 3.0.5 (in development)
==============================
Dependencies
------------
Incompatible changes
--------------------
Deprecated
----------
Features added
--------------
Bugs fixed
----------
Testing
--------
Release 3.0.4 (released May 27, 2020) Release 3.0.4 (released May 27, 2020)
===================================== =====================================
@ -470,7 +1010,7 @@ Release 2.4.1 (released Feb 11, 2020)
Bugs fixed Bugs fixed
---------- ----------
* #7120: html: crashed when on scaling SVG images which have float dimentions * #7120: html: crashed when on scaling SVG images which have float dimensions
* #7126: autodoc: TypeError: 'getset_descriptor' object is not iterable * #7126: autodoc: TypeError: 'getset_descriptor' object is not iterable
Release 2.4.0 (released Feb 09, 2020) Release 2.4.0 (released Feb 09, 2020)
@ -616,7 +1156,7 @@ Features added
* #6548: html: Use favicon for OpenSearch if available * #6548: html: Use favicon for OpenSearch if available
* #6729: html theme: agogo theme now supports ``rightsidebar`` option * #6729: html theme: agogo theme now supports ``rightsidebar`` option
* #6780: Add PEP-561 Support * #6780: Add PEP-561 Support
* #6762: latex: Allow to load additonal LaTeX packages via ``extrapackages`` key * #6762: latex: Allow to load additional LaTeX packages via ``extrapackages`` key
of :confval:`latex_elements` of :confval:`latex_elements`
* #1331: Add new config variable: :confval:`user_agent` * #1331: Add new config variable: :confval:`user_agent`
* #6000: LaTeX: have backslash also be an inline literal word wrap break * #6000: LaTeX: have backslash also be an inline literal word wrap break

View File

@ -8,10 +8,11 @@ reports/feature requests.
Our contributing guide can be found online at: Our contributing guide can be found online at:
https://www.sphinx-doc.org/en/master/internals/contributing/ https://www.sphinx-doc.org/en/master/internals/contributing.html
You can also browse it from this repository from You can also browse it from this repository from
``doc/internals/contributing/`` ``doc/internals/contributing.rst``
Sphinx uses GitHub to host source code, track patches and bugs, and more. Sphinx uses GitHub to host source code, track patches and bugs, and more.
Please make an effort to provide as much possible when filing bugs. Please make an effort to provide as much detail as possible when filing
bugs.

View File

@ -230,6 +230,7 @@ Documentation using sphinx_rtd_theme
* `MyHDL <http://docs.myhdl.org/>`__ * `MyHDL <http://docs.myhdl.org/>`__
* `Nextflow <https://www.nextflow.io/docs/latest/index.html>`__ * `Nextflow <https://www.nextflow.io/docs/latest/index.html>`__
* `NICOS <https://forge.frm2.tum.de/nicos/doc/nicos-master/>`__ (customized) * `NICOS <https://forge.frm2.tum.de/nicos/doc/nicos-master/>`__ (customized)
* `OpenFAST <https://openfast.readthedocs.io/>`__
* `Pelican <http://docs.getpelican.com/>`__ * `Pelican <http://docs.getpelican.com/>`__
* `picamera <https://picamera.readthedocs.io/>`__ * `picamera <https://picamera.readthedocs.io/>`__
* `Pillow <https://pillow.readthedocs.io/>`__ * `Pillow <https://pillow.readthedocs.io/>`__
@ -317,6 +318,7 @@ Documentation using a custom theme or integrated in a website
* `Django <https://docs.djangoproject.com/>`__ * `Django <https://docs.djangoproject.com/>`__
* `Doctrine <https://www.doctrine-project.org/>`__ * `Doctrine <https://www.doctrine-project.org/>`__
* `Enterprise Toolkit for Acrobat products <https://www.adobe.com/devnet-docs/acrobatetk/>`__ * `Enterprise Toolkit for Acrobat products <https://www.adobe.com/devnet-docs/acrobatetk/>`__
* `FreeFEM <https://doc.freefem.org/introduction/>`__
* `Gameduino <http://excamera.com/sphinx/gameduino/>`__ * `Gameduino <http://excamera.com/sphinx/gameduino/>`__
* `gensim <https://radimrehurek.com/gensim/>`__ * `gensim <https://radimrehurek.com/gensim/>`__
* `GeoServer <http://docs.geoserver.org/>`__ * `GeoServer <http://docs.geoserver.org/>`__
@ -330,6 +332,7 @@ Documentation using a custom theme or integrated in a website
* `Lasso <http://lassoguide.com/>`__ * `Lasso <http://lassoguide.com/>`__
* `Mako <http://docs.makotemplates.org/>`__ * `Mako <http://docs.makotemplates.org/>`__
* `MirrorBrain <http://mirrorbrain.org/docs/>`__ * `MirrorBrain <http://mirrorbrain.org/docs/>`__
* `Mitiq <https://mitiq.readthedocs.io/>`__
* `MongoDB <https://docs.mongodb.com/>`__ * `MongoDB <https://docs.mongodb.com/>`__
* `Music21 <https://web.mit.edu/music21/doc/>`__ * `Music21 <https://web.mit.edu/music21/doc/>`__
* `MyHDL <http://docs.myhdl.org/>`__ * `MyHDL <http://docs.myhdl.org/>`__
@ -355,7 +358,7 @@ Documentation using a custom theme or integrated in a website
* `Roundup <http://www.roundup-tracker.org/>`__ * `Roundup <http://www.roundup-tracker.org/>`__
* `SaltStack <https://docs.saltstack.com/>`__ * `SaltStack <https://docs.saltstack.com/>`__
* `scikit-learn <http://scikit-learn.org/stable/>`__ * `scikit-learn <http://scikit-learn.org/stable/>`__
* `SciPy <https://docs.scipy.org/doc/scipy/refrence/>`__ * `SciPy <https://docs.scipy.org/doc/scipy/reference/>`__
* `Scrapy <https://doc.scrapy.org/>`__ * `Scrapy <https://doc.scrapy.org/>`__
* `Seaborn <https://seaborn.pydata.org/>`__ * `Seaborn <https://seaborn.pydata.org/>`__
* `Selenium <https://docs.seleniumhq.org/docs/>`__ * `Selenium <https://docs.seleniumhq.org/docs/>`__
@ -382,6 +385,7 @@ Homepages and other non-documentation sites
* `Pylearn2 <http://www.deeplearning.net/software/pylearn2/>`__ (sphinxdoc, customized) * `Pylearn2 <http://www.deeplearning.net/software/pylearn2/>`__ (sphinxdoc, customized)
* `PyXLL <https://www.pyxll.com/>`__ (sphinx_bootstrap_theme, customized) * `PyXLL <https://www.pyxll.com/>`__ (sphinx_bootstrap_theme, customized)
* `SciPy Cookbook <https://scipy-cookbook.readthedocs.io/>`__ (sphinx_rtd_theme) * `SciPy Cookbook <https://scipy-cookbook.readthedocs.io/>`__ (sphinx_rtd_theme)
* `Tech writer at work blog <https://blog.documatt.com/>`__ (custom theme)
* `The Wine Cellar Book <https://www.thewinecellarbook.com/doc/en/>`__ (sphinxdoc) * `The Wine Cellar Book <https://www.thewinecellarbook.com/doc/en/>`__ (sphinxdoc)
* `Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials <https://thomas-cokelaer.info/tutorials/>`__ (standard) * `Thomas Cokelaer's Python, Sphinx and reStructuredText tutorials <https://thomas-cokelaer.info/tutorials/>`__ (standard)
* `UC Berkeley ME233 Advanced Control Systems II course <https://berkeley-me233.github.io/>`__ (sphinxdoc) * `UC Berkeley ME233 Advanced Control Systems II course <https://berkeley-me233.github.io/>`__ (sphinxdoc)

View File

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

View File

@ -64,17 +64,13 @@ type-check:
doclinter: doclinter:
python utils/doclinter.py CHANGES *.rst doc/ python utils/doclinter.py CHANGES *.rst doc/
.PHONY: pylint
pylint:
@pylint --rcfile utils/pylintrc sphinx
.PHONY: test .PHONY: test
test: test:
@$(PYTHON) -m pytest -v $(TEST) @$(PYTHON) -X dev -m pytest -v $(TEST)
.PHONY: covertest .PHONY: covertest
covertest: covertest:
@$(PYTHON) -m pytest -v --cov=sphinx --junitxml=.junit.xml $(TEST) @$(PYTHON) -X dev -m pytest -v --cov=sphinx --junitxml=.junit.xml $(TEST)
.PHONY: build .PHONY: build
build: build:
@ -83,6 +79,6 @@ build:
.PHONY: docs .PHONY: docs
docs: docs:
ifndef target ifndef target
$(info You need to give a provide a target variable, e.g. `make docs target=html`.) $(info You need to provide a target variable, e.g. `make docs target=html`.)
endif endif
$(MAKE) -C doc $(target) $(MAKE) -C doc $(target)

View File

@ -30,6 +30,10 @@
:target: https://opensource.org/licenses/BSD-3-Clause :target: https://opensource.org/licenses/BSD-3-Clause
:alt: BSD 3 Clause :alt: BSD 3 Clause
.. image:: https://codetriage.com/sphinx-doc/sphinx/badges/users.svg
:target: https://codetriage.com/sphinx-doc/sphinx
:alt: Open Source Helpers badge
Sphinx is a tool that makes it easy to create intelligent and beautiful Sphinx is a tool that makes it easy to create intelligent and beautiful
documentation for Python projects (or other documents consisting of multiple documentation for Python projects (or other documents consisting of multiple
reStructuredText sources), written by Georg Brandl. It was originally created reStructuredText sources), written by Georg Brandl. It was originally created

View File

@ -13,3 +13,9 @@ texlive-anyfontsize [platform:rpm]
texlive-ctablestack [platform:rpm] texlive-ctablestack [platform:rpm]
texlive-gnu-freefont [platform:rpm] texlive-gnu-freefont [platform:rpm]
latexmk [platform:rpm] latexmk [platform:rpm]
texlive-latex-recommended [platform:dpkg]
texlive-fonts-recommended [platform:dpkg]
texlive-latex-extra [platform:dpkg]
texlive-luatex [platform:dpkg]
latexmk [platform:dpkg]

View File

@ -1,4 +1,6 @@
translation.png: translation.puml
plantuml -tpng $<
translation.svg: translation.puml translation.svg: translation.puml
plantuml -tsvg $< plantuml -tsvg $<
clean: clean:
rm translation.svg rm -f translation.png translation.svg

8
doc/_static/favicon.svg vendored Normal file
View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<style>
@media (prefers-color-scheme: dark) {
svg { fill: white; }
}
</style>
<path d="m 67.780707,71.526216 c 0,-2.720856 0.735772,-7.633735 1.635035,-10.917507 2.076574,-7.582764 3.222746,-16.97568 2.071477,-16.97568 -0.485619,0 -3.994408,3.173002 -7.797313,7.051115 -14.448869,14.734603 -29.952812,23.068339 -42.915946,23.068339 -7.400211,0 -12.4298817,-1.871115 -17.2867007,-6.430912 -2.94436186,-2.764297 -3.47532146,-4.129685 -3.47532146,-8.936928 0,-4.94488 0.4862322,-6.108589 3.78321146,-9.054437 2.987989,-2.669773 4.875111,-3.380296 8.9779137,-3.380296 3.163221,0.711278 5.032659,0.664017 6.063532,1.917191 1.045041,1.231842 1.406892,5.262673 0.143323,7.623675 -0.674746,1.260763 -2.435471,2.043539 -4.5966,2.043539 -2.040303,0 -3.203991,-0.483702 -2.786976,-1.15844 1.31395,-2.126021 -0.560952,-3.566616 -2.9664067,-2.279256 -2.907025,1.555792 -2.957418,7.069066 -0.08839,9.665535 4.0345357,3.651203 15.1912207,5.023925 21.9019857,2.694828 7.250749,-2.516503 16.739014,-8.578986 24.30831,-15.531674 l 6.657407,-6.115083 -8.688303,-0.05007 C 43.622519,44.707714 37.702703,43.621524 18.54695,38.489741 12.175528,36.782852 6.0502733,35.306342 4.9352743,35.208608 3.6710803,35.097791 2.841723,34.067882 2.9080043,32.476074 3.0199286,29.788108 4.4800823,27.78768 6.2067673,27.033038 7.2437505,26.579828 14.43583,25.894406 22.0605,23.866486 c 29.699148,-7.899023 31.502043,-6.781254 51.28707,-1.772167 6.461504,1.635896 13.942408,3.414988 17.256961,3.474566 5.106245,0.09178 6.211825,0.514653 7.240255,2.76932 0.66758,1.46355 1.21378,2.858905 1.21378,3.10079 0,0.241884 -2.89333,1.764397 -6.429613,3.383363 -12.984983,5.944723 -17.083271,9.093943 -12.855172,15.130399 1.753219,2.503069 1.718037,2.768923 -0.57922,4.37799 -1.345193,0.942203 -2.457238,2.856456 -2.471232,4.253898 -0.03777,3.776976 -2.424786,11.884847 -5.893734,15.080164 l -3.048923,2.808424 z m 6.632814,-34.658372 c 5.169656,-1.440693 8.302047,-3.07045 14.72913,-6.500861 -5.292267,-1.548658 -18.570782,-3.724097 -18.570782,-3.724097 -9.796513,-1.964547 -8.76916,-1.865132 -9.21348,0.29669 -0.176673,0.859598 -0.702644,2.763948 -1.872329,4.596663 -2.251474,3.527711 -10.489307,4.271075 -15.214327,2.009703 -1.482367,-0.709454 -2.971272,-3.416276 -2.950606,-5.336922 0.02911,-2.705486 -1.505386,-3.336055 -2.486689,-2.975309 -0.796428,0.292781 -3.384665,0.330004 -9.071284,1.864262 -18.784765,5.068157 -21.3552119,4.487473 -9.110967,6.223299 1.472409,0.208739 9.252992,2.381926 13.052028,3.39412 9.318588,2.482796 11.064717,2.665087 23.125496,2.414247 8.385835,-0.174409 11.891174,-0.675356 17.58381,-2.261795 z M 3.0589449,14.916483 C 3.2921927,12.514245 3.424378,11.992797 10.100599,10.647894 13.924923,9.8774962 23.355266,7.3808108 31.056903,5.0997052 c 17.703937,-5.2436279 22.73392,-5.2565016 41.092202,-0.105175 7.923233,2.2232606 16.798382,4.047803 19.72254,4.054541 4.567242,0.01054 6.941892,2.0284768 6.941892,2.0284768 2.101843,4.825342 1.718463,5.158474 -6.484103,5.158474 -5.714193,0 -10.641875,-0.963081 -18.245438,-3.565943 C 68.300078,10.69012 60.060462,8.8316882 55.557963,8.4915615 47.342337,7.8709375 47.353713,7.8687835 21.963188,14.855617 17.503192,16.082896 11.34213,17.454164 8.2719268,17.902883 l -5.5821654,0.81585 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
doc/_static/translation.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -12,5 +12,5 @@ SphinxProject -r-> .rst
.pot -r-> .po : Pootle .pot -r-> .po : Pootle
.po -d-> .mo : msgfmt .po -d-> .mo : msgfmt
.mo -l-> TranslatedBuild .mo -l-> TranslatedBuild
.rst -d-> TranslatedBuild : "sphinx-buid -Dlanguage=" .rst -d-> TranslatedBuild : "sphinx-build -Dlanguage="
@enduml @enduml

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -239,7 +239,7 @@ div.footer a {
/* -- body styles ----------------------------------------------------------- */ /* -- body styles ----------------------------------------------------------- */
p { p {
margin: 0.8em 0 0.5em 0; margin: 0.8em 0 0.5em 0;
} }

View File

@ -4,7 +4,6 @@ import re
import sphinx import sphinx
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
'sphinx.ext.autosummary', 'sphinx.ext.extlinks', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks',
'sphinx.ext.intersphinx', 'sphinx.ext.intersphinx',
@ -15,7 +14,7 @@ templates_path = ['_templates']
exclude_patterns = ['_build'] exclude_patterns = ['_build']
project = 'Sphinx' project = 'Sphinx'
copyright = '2007-2020, Georg Brandl and the Sphinx team' copyright = '2007-2021, Georg Brandl and the Sphinx team'
version = sphinx.__display_version__ version = sphinx.__display_version__
release = version release = version
show_authors = True show_authors = True
@ -28,6 +27,7 @@ html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']}
html_additional_pages = {'index': 'index.html'} html_additional_pages = {'index': 'index.html'}
html_use_opensearch = 'https://www.sphinx-doc.org/en/master' html_use_opensearch = 'https://www.sphinx-doc.org/en/master'
html_baseurl = 'https://www.sphinx-doc.org/en/master/' html_baseurl = 'https://www.sphinx-doc.org/en/master/'
html_favicon = '_static/favicon.svg'
htmlhelp_basename = 'Sphinxdoc' htmlhelp_basename = 'Sphinxdoc'
@ -110,9 +110,10 @@ texinfo_documents = [
1), 1),
] ]
# We're not using intersphinx right now, but if we did, this would be part of intersphinx_mapping = {
# the mapping: 'python': ('https://docs.python.org/3/', None),
intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} 'requests': ('https://requests.readthedocs.io/en/master', None),
}
# Sphinx document translation with sphinx gettext feature uses these settings: # Sphinx document translation with sphinx gettext feature uses these settings:
locale_dirs = ['locale/'] locale_dirs = ['locale/']

View File

@ -10,7 +10,6 @@ Sphinx documentation contents
development/index development/index
man/index man/index
theming
templating templating
latex latex
extdev/index extdev/index

View File

@ -0,0 +1,34 @@
Configuring builders
====================
Discover builders by entry point
--------------------------------
.. versionadded:: 1.6
:term:`builder` extensions can be discovered by means of `entry points`_ so
that they do not have to be listed in the :confval:`extensions` configuration
value.
Builder extensions should define an entry point in the ``sphinx.builders``
group. The name of the entry point needs to match your builder's
:attr:`~.Builder.name` attribute, which is the name passed to the
:option:`sphinx-build -b` option. The entry point value should equal the
dotted name of the extension module. Here is an example of how an entry point
for 'mybuilder' can be defined in the extension's ``setup.py``
.. code-block:: python
setup(
# ...
entry_points={
'sphinx.builders': [
'mybuilder = my.extension.module',
],
}
)
Note that it is still necessary to register the builder using
:meth:`~.Sphinx.add_builder` in the extension's :func:`setup` function.
.. _entry points: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins

View File

@ -2,12 +2,22 @@
Extending Sphinx Extending Sphinx
================ ================
This guide is aimed at those wishing to develop their own extensions for This guide is aimed at giving a quick introduction for those wishing to
Sphinx. Sphinx possesses significant extensibility capabilities including the develop their own extensions for Sphinx. Sphinx possesses significant
ability to hook into almost every point of the build process. If you simply extensibility capabilities including the ability to hook into almost every
wish to use Sphinx with existing extensions, refer to :doc:`/usage/index`. point of the build process. If you simply wish to use Sphinx with existing
extensions, refer to :doc:`/usage/index`. For a more detailed discussion of
the extension interface see :doc:`/extdev/index`.
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
overview
tutorials/index tutorials/index
builders
.. toctree::
:caption: Theming
:maxdepth: 2
theming

View File

@ -0,0 +1,32 @@
Developing extensions overview
==============================
This page contains general information about developing Sphinx extensions.
Make an extension depend on another extension
---------------------------------------------
Sometimes your extension depends on the functionality of another
Sphinx extension. Most Sphinx extensions are activated in a
project's :file:`conf.py` file, but this is not available to you as an
extension developer.
.. module:: sphinx.application
:noindex:
To ensure that another extension is activated as a part of your own extension,
use the :meth:`Sphinx.setup_extension` method. This will
activate another extension at run-time, ensuring that you have access to its
functionality.
For example, the following code activates the ``recommonmark`` extension:
.. code-block:: python
def setup(app):
app.setup_extension("recommonmark")
.. note::
Since your extension will depend on another, make sure to include
it as a part of your extension's installation requirements.

336
doc/development/theming.rst Normal file
View File

@ -0,0 +1,336 @@
HTML theme development
======================
.. versionadded:: 0.6
.. note::
This document provides information about creating your own theme. If you
simply wish to use a pre-existing HTML themes, refer to
:doc:`/usage/theming`.
Sphinx supports changing the appearance of its HTML output via *themes*. A
theme is a collection of HTML templates, stylesheet(s) and other static files.
Additionally, it has a configuration file which specifies from which theme to
inherit, which highlighting style to use, and what options exist for customizing
the theme's look and feel.
Themes are meant to be project-unaware, so they can be used for different
projects without change.
.. note::
See :ref:`dev-extensions` for more information that may
be helpful in developing themes.
Creating themes
---------------
Themes take the form of either a directory or a zipfile (whose name is the
theme name), containing the following:
* A :file:`theme.conf` file.
* HTML templates, if needed.
* A ``static/`` directory containing any static files that will be copied to the
output static directory on build. These can be images, styles, script files.
The :file:`theme.conf` file is in INI format [1]_ (readable by the standard
Python :mod:`ConfigParser` module) and has the following structure:
.. sourcecode:: ini
[theme]
inherit = base theme
stylesheet = main CSS name
pygments_style = stylename
sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html
[options]
variable = default value
* The **inherit** setting gives the name of a "base theme", or ``none``. The
base theme will be used to locate missing templates (most themes will not have
to supply most templates if they use ``basic`` as the base theme), its options
will be inherited, and all of its static files will be used as well. If you
want to also inherit the stylesheet, include it via CSS' ``@import`` in your
own.
* The **stylesheet** setting gives the name of a CSS file which will be
referenced in the HTML header. If you need more than one CSS file, either
include one from the other via CSS' ``@import``, or use a custom HTML template
that adds ``<link rel="stylesheet">`` tags as necessary. Setting the
:confval:`html_style` config value will override this setting.
* The **pygments_style** setting gives the name of a Pygments style to use for
highlighting. This can be overridden by the user in the
:confval:`pygments_style` config value.
* The **pygments_dark_style** setting gives the name of a Pygments style to use
for highlighting when the CSS media query ``(prefers-color-scheme: dark)``
evaluates to true. It is injected into the page using
:meth:`~Sphinx.add_css_file()`.
* The **sidebars** setting gives the comma separated list of sidebar templates
for constructing sidebars. This can be overridden by the user in the
:confval:`html_sidebars` config value.
* The **options** section contains pairs of variable names and default values.
These options can be overridden by the user in :confval:`html_theme_options`
and are accessible from all templates as ``theme_<name>``.
.. versionadded:: 1.7
sidebar settings
.. _distribute-your-theme:
Distribute your theme as a Python package
-----------------------------------------
As a way to distribute your theme, you can use Python package. Python package
brings to users easy setting up ways.
To distribute your theme as a Python package, please define an entry point
called ``sphinx.html_themes`` in your ``setup.py`` file, and write a ``setup()``
function to register your themes using ``add_html_theme()`` API in it::
# 'setup.py'
setup(
...
entry_points = {
'sphinx.html_themes': [
'name_of_theme = your_package',
]
},
...
)
# 'your_package.py'
from os import path
def setup(app):
app.add_html_theme('name_of_theme', path.abspath(path.dirname(__file__)))
If your theme package contains two or more themes, please call
``add_html_theme()`` twice or more.
.. versionadded:: 1.2
'sphinx_themes' entry_points feature.
.. deprecated:: 1.6
``sphinx_themes`` entry_points has been deprecated.
.. versionadded:: 1.6
``sphinx.html_themes`` entry_points feature.
Templating
----------
The :doc:`guide to templating </templating>` is helpful if you want to write your
own templates. What is important to keep in mind is the order in which Sphinx
searches for templates:
* First, in the user's ``templates_path`` directories.
* Then, in the selected theme.
* Then, in its base theme, its base's base theme, etc.
When extending a template in the base theme with the same name, use the theme
name as an explicit directory: ``{% extends "basic/layout.html" %}``. From a
user ``templates_path`` template, you can still use the "exclamation mark"
syntax as described in the templating document.
.. _theming-static-templates:
Static templates
~~~~~~~~~~~~~~~~
Since theme options are meant for the user to configure a theme more easily,
without having to write a custom stylesheet, it is necessary to be able to
template static files as well as HTML files. Therefore, Sphinx supports
so-called "static templates", like this:
If the name of a file in the ``static/`` directory of a theme (or in the user's
static path, for that matter) ends with ``_t``, it will be processed by the
template engine. The ``_t`` will be left from the final file name. For
example, the *classic* theme has a file ``static/classic.css_t`` which uses
templating to put the color options into the stylesheet. When a documentation
is built with the classic theme, the output directory will contain a
``_static/classic.css`` file where all template tags have been processed.
Use custom page metadata in HTML templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Any key / value pairs in :doc:`field lists </usage/restructuredtext/field-lists>`
that are placed *before* the page's title will be available to the Jinja
template when building the page within the :data:`meta` attribute. For example,
if a page had the following text before its first title:
.. code-block:: rst
:mykey: My value
My first title
--------------
Then it could be accessed within a Jinja template like so:
.. code-block:: jinja
{%- if meta is mapping %}
{{ meta.get("mykey") }}
{%- endif %}
Note the check that ``meta`` is a dictionary ("mapping" in Jinja
terminology) to ensure that using it in this way is valid.
Defining custom template functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes it is useful to define your own function in Python that you wish to
then use in a template. For example, if you'd like to insert a template value
with logic that depends on the user's configuration in the project, or if you'd
like to include non-trivial checks and provide friendly error messages for
incorrect configuration in the template.
To define your own template function, you'll need to define two functions
inside your module:
* A **page context event handler** (or **registration**) function. This is
connected to the :class:`.Sphinx` application via an event callback.
* A **template function** that you will use in your Jinja template.
First, define the registration function, which accepts the arguments for
:event:`html-page-context`.
Within the registration function, define the template function that you'd like to use
within Jinja. The template function should return a string or Python objects (lists,
dictionaries) with strings inside that Jinja uses in the templating process
.. note::
The template function will have access to all of the variables that
are passed to the registration function.
At the end of the registration function, add the template function to the
Sphinx application's context with ``context['template_func'] = template_func``.
Finally, in your extension's ``setup()`` function, add your registration
function as a callback for :event:`html-page-context`.
.. code-block:: python
# The registration function
def setup_my_func(app, pagename, templatename, context, doctree):
# The template function
def my_func(mystring):
return "Your string is %s" % mystring
# Add it to the page's context
context['my_func'] = my_func
# Your extension's setup function
def setup(app):
app.connect("html-page-context", setup_my_func)
Now, you will have access to this function in jinja like so:
.. code-block:: jinja
<div>
{{ my_func("some string") }}
</div>
Add your own static files to the build assets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are packaging your own build assets with an extension
(e.g., a CSS or JavaScript file), you need to ensure that they are placed
in the ``_static/`` folder of HTML outputs. To do so, you may copy them directly
into a build's ``_static/`` folder at build time, generally via an event hook.
Here is some sample code to accomplish this:
.. code-block:: python
def copy_custom_files(app, exc):
if app.builder.format == 'html' and not exc:
staticdir = path.join(app.builder.outdir, '_static')
copy_asset_file('path/to/myextension/_static/myjsfile.js', staticdir)
def setup(app):
app.connect('builder-inited', copy_custom_files)
Inject JavaScript based on user configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If your extension makes use of JavaScript, it can be useful to allow users
to control its behavior using their Sphinx configuration. However, this can
be difficult to do if your JavaScript comes in the form of a static library
(which will not be built with Jinja).
There are two ways to inject variables into the JavaScript space based on user
configuration.
First, you may append ``_t`` to the end of any static files included with your
extension. This will cause Sphinx to process these files with the templating
engine, allowing you to embed variables and control behavior.
For example, the following JavaScript structure:
.. code-block:: bash
mymodule/
├── _static
│   └── myjsfile.js_t
└── mymodule.py
Will result in the following static file placed in your HTML's build output:
.. code-block:: bash
_build/
└── html
└── _static
   └── myjsfile.js
See :ref:`theming-static-templates` for more information.
Second, you may use the :meth:`Sphinx.add_js_file` method without pointing it
to a file. Normally, this method is used to insert a new JavaScript file
into your site. However, if you do *not* pass a file path, but instead pass
a string to the "body" argument, then this text will be inserted as JavaScript
into your site's head. This allows you to insert variables into your project's
JavaScript from Python.
For example, the following code will read in a user-configured value and then
insert this value as a JavaScript variable, which your extension's JavaScript
code may use:
.. code-block:: python
# This function reads in a variable and inserts it into JavaScript
def add_js_variable(app):
# This is a configuration that you've specified for users in `conf.py`
js_variable = app.config['my_javascript_variable']
js_text = "var my_variable = '%s';" % js_variable
app.add_js_file(None, body=js_text)
# We connect this function to the step after the builder is initialized
def setup(app):
# Tell Sphinx about this configuration variable
app.add_config_value('my_javascript_variable')
# Run the function after the builder is initialized
app.connect('builder-inited', add_js_variable)
As a result, in your theme you can use code that depends on the presence of
this variable. Users can control the variable's value by defining it in their
:file:`conf.py` file.
.. [1] It is not an executable Python file, as opposed to :file:`conf.py`,
because that would pose an unnecessary security risk if themes are
shared.

View File

@ -4,8 +4,7 @@ from docutils.parsers.rst import directives
from sphinx import addnodes from sphinx import addnodes
from sphinx.directives import ObjectDescription from sphinx.directives import ObjectDescription
from sphinx.domains import Domain from sphinx.domains import Domain, Index
from sphinx.domains import Index
from sphinx.roles import XRefRole from sphinx.roles import XRefRole
from sphinx.util.nodes import make_refnode from sphinx.util.nodes import make_refnode

View File

@ -61,6 +61,13 @@ def purge_todos(app, env, docname):
if todo['docname'] != docname] if todo['docname'] != docname]
def merge_todos(app, env, docnames, other):
if not hasattr(env, 'todo_all_todos'):
env.todo_all_todos = []
if hasattr(other, 'todo_all_todos'):
env.todo_all_todos.extend(other.todo_all_todos)
def process_todo_nodes(app, doctree, fromdocname): def process_todo_nodes(app, doctree, fromdocname):
if not app.config.todo_include_todos: if not app.config.todo_include_todos:
for node in doctree.traverse(todo): for node in doctree.traverse(todo):
@ -119,6 +126,7 @@ def setup(app):
app.add_directive('todolist', TodolistDirective) app.add_directive('todolist', TodolistDirective)
app.connect('doctree-resolved', process_todo_nodes) app.connect('doctree-resolved', process_todo_nodes)
app.connect('env-purge-doc', purge_todos) app.connect('env-purge-doc', purge_todos)
app.connect('env-merge-info', merge_todos)
return { return {
'version': '0.1', 'version': '0.1',

View File

@ -1,8 +1,11 @@
.. _extension-tutorials-index:
Extension tutorials Extension tutorials
=================== ===================
Refer to the following tutorials to get started with extension development. Refer to the following tutorials to get started with extension development.
.. toctree:: .. toctree::
:caption: Directive tutorials :caption: Directive tutorials
:maxdepth: 1 :maxdepth: 1

View File

@ -38,9 +38,10 @@ For that, we will need to add the following elements to Sphinx:
with the extension name, in order to stay unique) that controls whether todo with the extension name, in order to stay unique) that controls whether todo
entries make it into the output. entries make it into the output.
* New event handlers: one for the :event:`doctree-resolved` event, to replace * New event handlers: one for the :event:`doctree-resolved` event, to
the todo and todolist nodes, and one for :event:`env-purge-doc` (the reason replace the todo and todolist nodes, one for :event:`env-merge-info`
for that will be covered later). to merge intermediate results from parallel builds, and one for
:event:`env-purge-doc` (the reason for that will be covered later).
Prerequisites Prerequisites
@ -212,12 +213,23 @@ Here we clear out all todos whose docname matches the given one from the
``todo_all_todos`` list. If there are todos left in the document, they will be ``todo_all_todos`` list. If there are todos left in the document, they will be
added again during parsing. added again during parsing.
The next handler, for the :event:`env-merge-info` event, is used
during parallel builds. As during parallel builds all threads have
their own ``env``, there's multiple ``todo_all_todos`` lists that need
to be merged:
.. literalinclude:: examples/todo.py
:language: python
:linenos:
:lines: 64-68
The other handler belongs to the :event:`doctree-resolved` event: The other handler belongs to the :event:`doctree-resolved` event:
.. literalinclude:: examples/todo.py .. literalinclude:: examples/todo.py
:language: python :language: python
:linenos: :linenos:
:lines: 64-103 :lines: 71-113
The :event:`doctree-resolved` event is emitted at the end of :ref:`phase 3 The :event:`doctree-resolved` event is emitted at the end of :ref:`phase 3
(resolving) <build-phases>` and allows custom resolving to be done. The handler (resolving) <build-phases>` and allows custom resolving to be done. The handler
@ -230,7 +242,7 @@ where they come from. The list items are composed of the nodes from the
``todo`` entry and docutils nodes created on the fly: a paragraph for each ``todo`` entry and docutils nodes created on the fly: a paragraph for each
entry, containing text that gives the location, and a link (reference node entry, containing text that gives the location, and a link (reference node
containing an italic node) with the backreference. The reference URI is built containing an italic node) with the backreference. The reference URI is built
by :meth:`sphinx.builders.Builder.get_relative_uri`` which creates a suitable by :meth:`sphinx.builders.Builder.get_relative_uri` which creates a suitable
URI depending on the used builder, and appending the todo node's (the target's) URI depending on the used builder, and appending the todo node's (the target's)
ID as the anchor name. ID as the anchor name.
@ -245,7 +257,7 @@ the other parts of our extension. Let's look at our ``setup`` function:
.. literalinclude:: examples/todo.py .. literalinclude:: examples/todo.py
:language: python :language: python
:linenos: :linenos:
:lines: 106- :lines: 116-
The calls in this function refer to the classes and functions we added earlier. The calls in this function refer to the classes and functions we added earlier.
What the individual calls do is the following: What the individual calls do is the following:

View File

@ -25,75 +25,75 @@ package.
.. currentmodule:: sphinx.application .. currentmodule:: sphinx.application
.. automethod:: Sphinx.setup_extension(name) .. automethod:: Sphinx.setup_extension
.. automethod:: Sphinx.require_sphinx(version) .. automethod:: Sphinx.require_sphinx
.. automethod:: Sphinx.connect(event, callback) .. automethod:: Sphinx.connect
.. automethod:: Sphinx.disconnect(listener_id) .. automethod:: Sphinx.disconnect
.. automethod:: Sphinx.add_builder(builder) .. automethod:: Sphinx.add_builder
.. automethod:: Sphinx.add_config_value(name, default, rebuild) .. automethod:: Sphinx.add_config_value
.. automethod:: Sphinx.add_event(name) .. automethod:: Sphinx.add_event
.. automethod:: Sphinx.set_translator(name, translator_class) .. automethod:: Sphinx.set_translator
.. automethod:: Sphinx.add_node(node, \*\*kwds) .. automethod:: Sphinx.add_node
.. automethod:: Sphinx.add_enumerable_node(node, figtype, title_getter=None, \*\*kwds) .. automethod:: Sphinx.add_enumerable_node
.. automethod:: Sphinx.add_directive(name, directiveclass) .. automethod:: Sphinx.add_directive
.. automethod:: Sphinx.add_role(name, role) .. automethod:: Sphinx.add_role
.. automethod:: Sphinx.add_generic_role(name, nodeclass) .. automethod:: Sphinx.add_generic_role
.. automethod:: Sphinx.add_domain(domain) .. automethod:: Sphinx.add_domain
.. automethod:: Sphinx.add_directive_to_domain(domain, name, directiveclass) .. automethod:: Sphinx.add_directive_to_domain
.. automethod:: Sphinx.add_role_to_domain(domain, name, role) .. automethod:: Sphinx.add_role_to_domain
.. automethod:: Sphinx.add_index_to_domain(domain, index) .. automethod:: Sphinx.add_index_to_domain
.. automethod:: Sphinx.add_object_type(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None, objname='', doc_field_types=[]) .. automethod:: Sphinx.add_object_type
.. automethod:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None, objname='') .. automethod:: Sphinx.add_crossref_type
.. automethod:: Sphinx.add_transform(transform) .. automethod:: Sphinx.add_transform
.. automethod:: Sphinx.add_post_transform(transform) .. automethod:: Sphinx.add_post_transform
.. automethod:: Sphinx.add_js_file(filename, **kwargs) .. automethod:: Sphinx.add_js_file
.. automethod:: Sphinx.add_css_file(filename, **kwargs) .. automethod:: Sphinx.add_css_file
.. automethod:: Sphinx.add_latex_package(packagename, options=None) .. automethod:: Sphinx.add_latex_package
.. automethod:: Sphinx.add_lexer(alias, lexer) .. automethod:: Sphinx.add_lexer
.. automethod:: Sphinx.add_autodocumenter(cls) .. automethod:: Sphinx.add_autodocumenter
.. automethod:: Sphinx.add_autodoc_attrgetter(type, getter) .. automethod:: Sphinx.add_autodoc_attrgetter
.. automethod:: Sphinx.add_search_language(cls) .. automethod:: Sphinx.add_search_language
.. automethod:: Sphinx.add_source_suffix(suffix, filetype) .. automethod:: Sphinx.add_source_suffix
.. automethod:: Sphinx.add_source_parser(parser) .. automethod:: Sphinx.add_source_parser
.. automethod:: Sphinx.add_env_collector(collector) .. automethod:: Sphinx.add_env_collector
.. automethod:: Sphinx.add_html_theme(name, theme_path) .. automethod:: Sphinx.add_html_theme
.. automethod:: Sphinx.add_html_math_renderer(name, inline_renderers, block_renderers) .. automethod:: Sphinx.add_html_math_renderer
.. automethod:: Sphinx.add_message_catalog(catalog, locale_dir) .. automethod:: Sphinx.add_message_catalog
.. automethod:: Sphinx.is_parallel_allowed(typ) .. automethod:: Sphinx.is_parallel_allowed
.. exception:: ExtensionError .. exception:: ExtensionError
@ -107,9 +107,9 @@ Emitting events
.. class:: Sphinx .. class:: Sphinx
:noindex: :noindex:
.. automethod:: emit(event, \*arguments) .. automethod:: emit
.. automethod:: emit_firstresult(event, \*arguments) .. automethod:: emit_firstresult
Sphinx runtime information Sphinx runtime information
@ -157,6 +157,42 @@ connect handlers to the events. Example:
app.connect('source-read', source_read_handler) app.connect('source-read', source_read_handler)
Below is an overview of each event that happens during a build. In the list
below, we include the event name, its callback parameters, and the input and output
type for that event::
1. event.config-inited(app,config)
2. event.builder-inited(app)
3. event.env-get-outdated(app, env, added, changed, removed)
4. event.env-before-read-docs(app, env, docnames)
for docname in docnames:
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,
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)
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 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)
15. Generate output files
16. event.build-finished(app, exception)
Here is a more detailed list of these events.
.. event:: builder-inited (app) .. event:: builder-inited (app)
Emitted when the builder object has been created. It is available as Emitted when the builder object has been created. It is available as
@ -249,6 +285,14 @@ connect handlers to the events. Example:
.. versionadded:: 0.5 .. versionadded:: 0.5
.. event:: warn-missing-reference (app, domain, node)
Emitted when a cross-reference to an object cannot be resolved even after
:event:`missing-reference`. If the event handler can emit warnings for
the missing reference, it should return ``True``.
.. versionadded:: 3.4
.. event:: doctree-resolved (app, doctree, docname) .. event:: doctree-resolved (app, doctree, docname)
Emitted when a doctree has been "resolved" by the environment, that is, all Emitted when a doctree has been "resolved" by the environment, that is, all
@ -325,6 +369,9 @@ connect handlers to the events. Example:
You can return a string from the handler, it will then replace You can return a string from the handler, it will then replace
``'page.html'`` as the HTML template for this page. ``'page.html'`` as the HTML template for this page.
.. note:: You can install JS/CSS files for the specific page via
:meth:`Sphinx.add_js_file` and :meth:`Sphinx.add_css_file` since v3.5.0.
.. versionadded:: 0.4 .. versionadded:: 0.4
.. versionchanged:: 1.3 .. versionchanged:: 1.3

View File

@ -26,6 +26,167 @@ The following is a list of deprecated interfaces.
- (will be) Removed - (will be) Removed
- Alternatives - Alternatives
* - pending_xref node for viewcode extension
- 3.5
- 5.0
- ``sphinx.ext.viewcode.viewcode_anchor``
* - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.broken``
- 3.5
- 5.0
- N/A
* - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.good``
- 3.5
- 5.0
- N/A
* - ``sphinx.builders.linkcheck.CheckExternalLinksBuilder.redirected``
- 3.5
- 5.0
- N/A
* - ``sphinx.builders.linkcheck.node_line_or_0()``
- 3.5
- 5.0
- ``sphinx.util.nodes.get_node_line()``
* - ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()``
- 3.5
- 5.0
- N/A
* - ``sphinx.ext.autodoc.importer.get_module_members()``
- 3.5
- 5.0
- ``sphinx.ext.autodoc.ModuleDocumenter.get_module_members()``
* - ``sphinx.ext.autosummary.generate._simple_info()``
- 3.5
- 5.0
- :ref:`logging-api`
* - ``sphinx.ext.autosummary.generate._simple_warn()``
- 3.5
- 5.0
- :ref:`logging-api`
* - ``sphinx.writers.html.HTMLTranslator.permalink_text``
- 3.5
- 5.0
- :confval:`html_permalinks_icon`
* - ``sphinx.writers.html5.HTML5Translator.permalink_text``
- 3.5
- 5.0
- :confval:`html_permalinks_icon`
* - The ``follow_wrapped`` argument of ``sphinx.util.inspect.signature()``
- 3.4
- 5.0
- N/A
* - The ``no_docstring`` argument of
``sphinx.ext.autodoc.Documenter.add_content()``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.Documenter.get_doc()``
* - ``sphinx.ext.autodoc.Documenter.get_object_members()``
- 3.4
- 6.0
- ``sphinx.ext.autodoc.ClassDocumenter.get_object_members()``
* - ``sphinx.ext.autodoc.DataDeclarationDocumenter``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.DataDocumenter``
* - ``sphinx.ext.autodoc.GenericAliasDocumenter``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.DataDocumenter``
* - ``sphinx.ext.autodoc.InstanceAttributeDocumenter``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.AttributeDocumenter``
* - ``sphinx.ext.autodoc.SlotsAttributeDocumenter``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.AttributeDocumenter``
* - ``sphinx.ext.autodoc.TypeVarDocumenter``
- 3.4
- 5.0
- ``sphinx.ext.autodoc.DataDocumenter``
* - ``sphinx.ext.autodoc.directive.DocumenterBridge.reporter``
- 3.5
- 5.0
- ``sphinx.util.logging``
* - ``sphinx.ext.autodoc.importer._getannotations()``
- 3.4
- 4.0
- ``sphinx.util.inspect.getannotations()``
* - ``sphinx.ext.autodoc.importer._getmro()``
- 3.4
- 4.0
- ``sphinx.util.inspect.getmro()``
* - ``sphinx.pycode.ModuleAnalyzer.parse()``
- 3.4
- 5.0
- ``sphinx.pycode.ModuleAnalyzer.analyze()``
* - ``sphinx.util.osutil.movefile()``
- 3.4
- 5.0
- ``os.replace()``
* - ``sphinx.util.requests.is_ssl_error()``
- 3.4
- 5.0
- N/A
* - ``sphinx.builders.latex.LaTeXBuilder.usepackages``
- 3.3
- 5.0
- N/A
* - ``sphinx.builders.latex.LaTeXBuilder.usepackages_afger_hyperref``
- 3.3
- 5.0
- N/A
* - ``sphinx.ext.autodoc.SingledispatchFunctionDocumenter``
- 3.3
- 5.0
- ``sphinx.ext.autodoc.FunctionDocumenter``
* - ``sphinx.ext.autodoc.SingledispatchMethodDocumenter``
- 3.3
- 5.0
- ``sphinx.ext.autodoc.MethodDocumenter``
* - ``sphinx.ext.autodoc.members_set_option()``
- 3.2
- 5.0
- N/A
* - ``sphinx.ext.autodoc.merge_special_members_option()``
- 3.2
- 5.0
- ``sphinx.ext.autodoc.merge_members_option()``
* - ``sphinx.writers.texinfo.TexinfoWriter.desc``
- 3.2
- 5.0
- ``sphinx.writers.texinfo.TexinfoWriter.descs``
* - The first argument for * - The first argument for
``sphinx.ext.autosummary.generate.AutosummaryRenderer`` has been changed ``sphinx.ext.autosummary.generate.AutosummaryRenderer`` has been changed
to Sphinx object to Sphinx object

View File

@ -1,7 +1,7 @@
.. _domain-api: .. _domain-api:
Domain API Domain API
---------- ==========
.. module:: sphinx.domains .. module:: sphinx.domains
@ -12,3 +12,16 @@ Domain API
.. autoclass:: Index .. autoclass:: Index
:members: :members:
Python Domain
-------------
.. module:: sphinx.domains.python
.. autoclass:: PythonDomain
.. autoattribute:: objects
.. autoattribute:: modules
.. automethod:: note_object
.. automethod:: note_module

View File

@ -3,54 +3,41 @@
Developing extensions for Sphinx Developing extensions for Sphinx
================================ ================================
Since many projects will need special features in their documentation, Sphinx is Since many projects will need special features in their documentation, Sphinx
designed to be extensible on several levels. is designed to be extensible on several levels.
This is what you can do in an extension: First, you can add new Here are a few things you can do in an extension:
:term:`builder`\s to support new output formats or actions on the parsed
documents. Then, it is possible to register custom reStructuredText roles and
directives, extending the markup. And finally, there are so-called "hook
points" at strategic places throughout the build process, where an extension can
register a hook and run specialized code.
An extension is simply a Python module. When an extension is loaded, Sphinx * Add new :term:`builder`\s to support new output formats or actions on the
imports this module and executes its ``setup()`` function, which in turn parsed documents.
notifies Sphinx of everything the extension offers -- see the extension tutorial * Register custom reStructuredText roles and directives, extending the markup
for examples. using the :doc:`markupapi`.
* Add custom code to so-called "hook points" at strategic places throughout the
build process, allowing you to register a hook and run specialized code.
For example, see the :ref:`events`.
The configuration file itself can be treated as an extension if it contains a An extension is simply a Python module with a ``setup()`` function. A user
``setup()`` function. All other extensions to load must be listed in the activates the extension by placing the extension's module name
:confval:`extensions` configuration value. (or a sub-module) in their :confval:`extensions` configuration value.
Discovery of builders by entry point When :program:`sphinx-build` is executed, Sphinx will attempt to import each
------------------------------------ module that is listed, and execute ``yourmodule.setup(app)``. This
function is used to prepare the extension (e.g., by executing Python code),
linking resources that Sphinx uses in the build process (like CSS or HTML
files), and notifying Sphinx of everything the extension offers (such
as directive or role definitions). The ``app`` argument is an instance of
:class:`.Sphinx` and gives you control over most aspects of the Sphinx build.
.. versionadded:: 1.6 .. note::
:term:`builder` extensions can be discovered by means of `entry points`_ so The configuration file itself can be treated as an extension if it
that they do not have to be listed in the :confval:`extensions` configuration contains a ``setup()`` function. All other extensions to load must be
value. listed in the :confval:`extensions` configuration value.
Builder extensions should define an entry point in the ``sphinx.builders`` The rest of this page describes some high-level aspects of developing
group. The name of the entry point needs to match your builder's extensions and various parts of Sphinx's behavior that you can control.
:attr:`~.Builder.name` attribute, which is the name passed to the For some examples of how extensions can be built and used to control different
:option:`sphinx-build -b` option. The entry point value should equal the parts of Sphinx, see the :ref:`extension-tutorials-index`.
dotted name of the extension module. Here is an example of how an entry point
for 'mybuilder' can be defined in the extension's ``setup.py``::
setup(
# ...
entry_points={
'sphinx.builders': [
'mybuilder = my.extension.module',
],
}
)
Note that it is still necessary to register the builder using
:meth:`~.Sphinx.add_builder` in the extension's :func:`setup` function.
.. _entry points: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins
.. _important-objects: .. _important-objects:
@ -192,6 +179,11 @@ as metadata of the extension. Metadata keys currently recognized are:
APIs used for writing extensions APIs used for writing extensions
-------------------------------- --------------------------------
These sections provide a more complete description of the tools at your
disposal when developing Sphinx extensions. Some are core to Sphinx
(such as the :doc:`appapi`) while others trigger specific behavior
(such as the :doc:`i18n`)
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2

View File

@ -9,8 +9,8 @@ Glossary
A class (inheriting from :class:`~sphinx.builders.Builder`) that takes A class (inheriting from :class:`~sphinx.builders.Builder`) that takes
parsed documents and performs an action on them. Normally, builders parsed documents and performs an action on them. Normally, builders
translate the documents to an output format, but it is also possible to translate the documents to an output format, but it is also possible to
use the builder builders that e.g. check for broken links in the use builders that e.g. check for broken links in the documentation, or
documentation, or build coverage information. build coverage information.
See :doc:`/usage/builders/index` for an overview over Sphinx's built-in See :doc:`/usage/builders/index` for an overview over Sphinx's built-in
builders. builders.

View File

@ -12,6 +12,9 @@ Getting help
The Sphinx community maintains a number of mailing lists and IRC channels. The Sphinx community maintains a number of mailing lists and IRC channels.
Stack Overflow with tag `python-sphinx`_
Questions and answers about use and development.
sphinx-users <sphinx-users@googlegroups.com> sphinx-users <sphinx-users@googlegroups.com>
Mailing list for user support. Mailing list for user support.
@ -21,6 +24,7 @@ sphinx-dev <sphinx-dev@googlegroups.com>
#sphinx-doc on irc.freenode.net #sphinx-doc on irc.freenode.net
IRC channel for development questions and user support. IRC channel for development questions and user support.
.. _python-sphinx: https://stackoverflow.com/questions/tagged/python-sphinx
Bug Reports and Feature Requests Bug Reports and Feature Requests
-------------------------------- --------------------------------
@ -134,10 +138,7 @@ Coding style
Please follow these guidelines when writing code for Sphinx: Please follow these guidelines when writing code for Sphinx:
* Try to use the same code style as used in the rest of the project. See the * Try to use the same code style as used in the rest of the project.
`Pocoo Styleguide`__ for more information.
__ http://flask.pocoo.org/docs/styleguide/
* For non-trivial changes, please update the :file:`CHANGES` file. If your * For non-trivial changes, please update the :file:`CHANGES` file. If your
changes alter existing behavior, please document this. changes alter existing behavior, please document this.
@ -268,9 +269,9 @@ identifier and put ``sphinx.po`` in there. Don't forget to update the possible
values for :confval:`language` in ``doc/usage/configuration.rst``. values for :confval:`language` in ``doc/usage/configuration.rst``.
The Sphinx core messages can also be translated on `Transifex The Sphinx core messages can also be translated on `Transifex
<https://www.transifex.com/sphinx-doc/>`_. There ``tx`` client tool, which is <https://www.transifex.com/sphinx-doc/sphinx-1/>`_. There ``tx`` client tool,
provided by the ``transifex_client`` Python package, can be used to pull which is provided by the ``transifex_client`` Python package, can be used to
translations in ``.po`` format from Transifex. To do this, go to pull translations in ``.po`` format from Transifex. To do this, go to
``sphinx/locale`` and then run ``tx pull -f -l LANG`` where ``LANG`` is an ``sphinx/locale`` and then run ``tx pull -f -l LANG`` where ``LANG`` is an
existing language identifier. It is good practice to run ``python setup.py existing language identifier. It is good practice to run ``python setup.py
update_catalog`` afterwards to make sure the ``.po`` file has the canonical update_catalog`` afterwards to make sure the ``.po`` file has the canonical

View File

@ -95,6 +95,12 @@ Keys that you may want to override include:
A string which will be positioned early in the preamble, designed to A string which will be positioned early in the preamble, designed to
contain ``\\PassOptionsToPackage{options}{foo}`` commands. contain ``\\PassOptionsToPackage{options}{foo}`` commands.
.. hint::
It may be also used for loading LaTeX packages very early in the
preamble. For example package ``fancybox`` is incompatible with
being loaded via the ``'preamble'`` key, it must be loaded earlier.
Default: ``''`` Default: ``''``
.. versionadded:: 1.4 .. versionadded:: 1.4
@ -195,8 +201,8 @@ Keys that you may want to override include:
"Bjornstrup". You can also set this to ``''`` to disable fncychap. "Bjornstrup". You can also set this to ``''`` to disable fncychap.
Default: ``'\\usepackage[Bjarne]{fncychap}'`` for English documents, Default: ``'\\usepackage[Bjarne]{fncychap}'`` for English documents,
``'\\usepackage[Sonny]{fncychap}'`` for internationalized documents, and ``'\\usepackage[Sonny]{fncychap}'`` for internationalized documents, and
``''`` for Japanese documents. ``''`` for Japanese documents.
``'preamble'`` ``'preamble'``
Additional preamble content. One may move all needed macros into some file Additional preamble content. One may move all needed macros into some file
@ -300,7 +306,7 @@ Keys that don't need to be overridden unless in special cases are:
"inputenc" package inclusion. "inputenc" package inclusion.
Default: ``'\\usepackage[utf8]{inputenc}'`` when using pdflatex, else Default: ``'\\usepackage[utf8]{inputenc}'`` when using pdflatex, else
``''`` ``''``
.. versionchanged:: 1.4.3 .. versionchanged:: 1.4.3
Previously ``'\\usepackage[utf8]{inputenc}'`` was used for all Previously ``'\\usepackage[utf8]{inputenc}'`` was used for all
@ -389,7 +395,7 @@ Keys that don't need to be overridden unless in special cases are:
key is ignored. key is ignored.
Default: ``'\\usepackage{textalpha}'`` or ``''`` if ``fontenc`` does not Default: ``'\\usepackage{textalpha}'`` or ``''`` if ``fontenc`` does not
include the ``LGR`` option. include the ``LGR`` option.
.. versionadded:: 2.0 .. versionadded:: 2.0
@ -407,7 +413,7 @@ Keys that don't need to be overridden unless in special cases are:
<latexsphinxsetup>`. <latexsphinxsetup>`.
Default: ``'\\usepackage{geometry}'`` (or Default: ``'\\usepackage{geometry}'`` (or
``'\\usepackage[dvipdfm]{geometry}'`` for Japanese documents) ``'\\usepackage[dvipdfm]{geometry}'`` for Japanese documents)
.. versionadded:: 1.5 .. versionadded:: 1.5
@ -784,14 +790,14 @@ macros may be significant.
|warningbdcolors| |warningbdcolors|
The colour for the admonition frame. The colour for the admonition frame.
Default: ``{rgb}{0,0,0}`` (black) Default: ``{rgb}{0,0,0}`` (black)
.. only:: latex .. only:: latex
|wgbdcolorslatex| |wgbdcolorslatex|
The colour for the admonition frame. The colour for the admonition frame.
Default: ``{rgb}{0,0,0}`` (black) Default: ``{rgb}{0,0,0}`` (black)
|warningbgcolors| |warningbgcolors|
The background colours for the respective admonitions. The background colours for the respective admonitions.

View File

@ -20,7 +20,7 @@ Options
.. option:: -q, --quiet .. option:: -q, --quiet
Quiet mode that will skip interactive wizard to specify options. Quiet mode that skips the interactive wizard for specifying options.
This option requires `-p`, `-a` and `-v` options. This option requires `-p`, `-a` and `-v` options.
.. option:: -h, --help, --version .. option:: -h, --help, --version
@ -33,6 +33,10 @@ Options
If specified, separate source and build directories. If specified, separate source and build directories.
.. option:: --no-sep
If specified, create build directroy under source directroy.
.. option:: --dot=DOT .. option:: --dot=DOT
Inside the root directory, two more directories will be created; Inside the root directory, two more directories will be created;

View File

@ -7,7 +7,7 @@ Templating
========== ==========
Sphinx uses the `Jinja <http://jinja.pocoo.org>`_ templating engine for its HTML Sphinx uses the `Jinja <http://jinja.pocoo.org>`_ templating engine for its HTML
templates. Jinja is a text-based engine, and inspired by Django templates, so templates. Jinja is a text-based engine, inspired by Django templates, so
anyone having used Django will already be familiar with it. It also has anyone having used Django will already be familiar with it. It also has
excellent documentation for those who need to make themselves familiar with it. excellent documentation for those who need to make themselves familiar with it.

View File

@ -1,159 +0,0 @@
.. highlight:: python
HTML theming support
====================
.. versionadded:: 0.6
.. note::
This document provides information about creating your own theme. If you
simply wish to use a pre-existing HTML themes, refer to
:doc:`/usage/theming`.
Sphinx supports changing the appearance of its HTML output via *themes*. A
theme is a collection of HTML templates, stylesheet(s) and other static files.
Additionally, it has a configuration file which specifies from which theme to
inherit, which highlighting style to use, and what options exist for customizing
the theme's look and feel.
Themes are meant to be project-unaware, so they can be used for different
projects without change.
Creating themes
---------------
Themes take the form of either a directory or a zipfile (whose name is the
theme name), containing the following:
* A :file:`theme.conf` file.
* HTML templates, if needed.
* A ``static/`` directory containing any static files that will be copied to the
output static directory on build. These can be images, styles, script files.
The :file:`theme.conf` file is in INI format [1]_ (readable by the standard
Python :mod:`ConfigParser` module) and has the following structure:
.. sourcecode:: ini
[theme]
inherit = base theme
stylesheet = main CSS name
pygments_style = stylename
sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html
[options]
variable = default value
* The **inherit** setting gives the name of a "base theme", or ``none``. The
base theme will be used to locate missing templates (most themes will not have
to supply most templates if they use ``basic`` as the base theme), its options
will be inherited, and all of its static files will be used as well. If you
want to also inherit the stylesheet, include it via CSS' ``@import`` in your
own.
* The **stylesheet** setting gives the name of a CSS file which will be
referenced in the HTML header. If you need more than one CSS file, either
include one from the other via CSS' ``@import``, or use a custom HTML template
that adds ``<link rel="stylesheet">`` tags as necessary. Setting the
:confval:`html_style` config value will override this setting.
* The **pygments_style** setting gives the name of a Pygments style to use for
highlighting. This can be overridden by the user in the
:confval:`pygments_style` config value.
* The **pygments_dark_style** setting gives the name of a Pygments style to use
for highlighting when the CSS media query ``(prefers-color-scheme: dark)``
evaluates to true. It is injected into the page using
:meth:`~Sphinx.add_css_file()`.
* The **sidebars** setting gives the comma separated list of sidebar templates
for constructing sidebars. This can be overridden by the user in the
:confval:`html_sidebars` config value.
* The **options** section contains pairs of variable names and default values.
These options can be overridden by the user in :confval:`html_theme_options`
and are accessible from all templates as ``theme_<name>``.
.. versionadded:: 1.7
sidebar settings
.. _distribute-your-theme:
Distribute your theme as a Python package
-----------------------------------------
As a way to distribute your theme, you can use Python package. Python package
brings to users easy setting up ways.
To distribute your theme as a Python package, please define an entry point
called ``sphinx.html_themes`` in your ``setup.py`` file, and write a ``setup()``
function to register your themes using ``add_html_theme()`` API in it::
# 'setup.py'
setup(
...
entry_points = {
'sphinx.html_themes': [
'name_of_theme = your_package',
]
},
...
)
# 'your_package.py'
from os import path
def setup(app):
app.add_html_theme('name_of_theme', path.abspath(path.dirname(__file__)))
If your theme package contains two or more themes, please call
``add_html_theme()`` twice or more.
.. versionadded:: 1.2
'sphinx_themes' entry_points feature.
.. deprecated:: 1.6
``sphinx_themes`` entry_points has been deprecated.
.. versionadded:: 1.6
``sphinx.html_themes`` entry_points feature.
Templating
----------
The :doc:`guide to templating <templating>` is helpful if you want to write your
own templates. What is important to keep in mind is the order in which Sphinx
searches for templates:
* First, in the user's ``templates_path`` directories.
* Then, in the selected theme.
* Then, in its base theme, its base's base theme, etc.
When extending a template in the base theme with the same name, use the theme
name as an explicit directory: ``{% extends "basic/layout.html" %}``. From a
user ``templates_path`` template, you can still use the "exclamation mark"
syntax as described in the templating document.
Static templates
~~~~~~~~~~~~~~~~
Since theme options are meant for the user to configure a theme more easily,
without having to write a custom stylesheet, it is necessary to be able to
template static files as well as HTML files. Therefore, Sphinx supports
so-called "static templates", like this:
If the name of a file in the ``static/`` directory of a theme (or in the user's
static path, for that matter) ends with ``_t``, it will be processed by the
template engine. The ``_t`` will be left from the final file name. For
example, the *classic* theme has a file ``static/classic.css_t`` which uses
templating to put the color options into the stylesheet. When a documentation
is built with the classic theme, the output directory will contain a
``_static/classic.css`` file where all template tags have been processed.
.. [1] It is not an executable Python file, as opposed to :file:`conf.py`,
because that would pose an unnecessary security risk if themes are
shared.

View File

@ -6,10 +6,10 @@ Internationalization
.. versionadded:: 1.1 .. versionadded:: 1.1
Complementary to translations provided for Sphinx-generated messages such as Complementary to translations provided for Sphinx-generated messages such as
navigation bars, Sphinx provides mechanisms facilitating *document* translations navigation bars, Sphinx provides mechanisms facilitating the translation of
in itself. See the :ref:`intl-options` for details on configuration. *documents*. See the :ref:`intl-options` for details on configuration.
.. figure:: /_static/translation.svg .. figure:: /_static/translation.*
:width: 100% :width: 100%
Workflow visualization of translations in Sphinx. (The figure is created by Workflow visualization of translations in Sphinx. (The figure is created by

View File

@ -442,6 +442,10 @@ name is ``rinoh``. Refer to the `rinohtype manual`_ for details.
Since Sphinx-1.5, the linkcheck builder comes to use requests module. Since Sphinx-1.5, the linkcheck builder comes to use requests module.
.. versionchanged:: 3.4
The linkcheck builder retries links when servers apply rate limits.
.. module:: sphinx.builders.xml .. module:: sphinx.builders.xml
.. class:: XMLBuilder .. class:: XMLBuilder

View File

@ -70,9 +70,14 @@ Project information
The author name(s) of the document. The default value is ``'unknown'``. The author name(s) of the document. The default value is ``'unknown'``.
.. confval:: copyright .. confval:: copyright
.. confval:: project_copyright
A copyright statement in the style ``'2008, Author Name'``. A copyright statement in the style ``'2008, Author Name'``.
.. versionchanged:: 3.5
As an alias, ``project_copyright`` is also allowed.
.. confval:: version .. confval:: version
The major project version, used as the replacement for ``|version|``. For The major project version, used as the replacement for ``|version|``. For
@ -316,6 +321,7 @@ General configuration
* ``toc.circular`` * ``toc.circular``
* ``toc.secnum`` * ``toc.secnum``
* ``epub.unknown_project_files`` * ``epub.unknown_project_files``
* ``epub.duplicated_toc_entry``
* ``autosectionlabel.*`` * ``autosectionlabel.*``
You can choose from these types. You can choose from these types.
@ -340,6 +346,10 @@ General configuration
Added ``autosectionlabel.*`` Added ``autosectionlabel.*``
.. versionchanged:: 3.3.0
Added ``epub.duplicated_toc_entry``
.. confval:: needs_sphinx .. confval:: needs_sphinx
If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will If set to a ``major.minor`` version string like ``'1.1'``, Sphinx will
@ -551,7 +561,7 @@ General configuration
* Otherwise, the current time is formatted using :func:`time.strftime` and * Otherwise, the current time is formatted using :func:`time.strftime` and
the format given in :confval:`today_fmt`. the format given in :confval:`today_fmt`.
The default is now :confval:`today` and a :confval:`today_fmt` of ``'%B %d, The default is now :confval:`today` and a :confval:`today_fmt` of ``'%b %d,
%Y'`` (or, if translation is enabled with :confval:`language`, an equivalent %Y'`` (or, if translation is enabled with :confval:`language`, an equivalent
format for the selected locale). format for the selected locale).
@ -572,12 +582,27 @@ General configuration
.. confval:: highlight_options .. confval:: highlight_options
A dictionary of options that modify how the lexer specified by A dictionary that maps language names to options for the lexer modules of
:confval:`highlight_language` generates highlighted source code. These are Pygments. These are lexer-specific; for the options understood by each,
lexer-specific; for the options understood by each, see the see the `Pygments documentation <https://pygments.org/docs/lexers>`_.
`Pygments documentation <https://pygments.org/docs/lexers>`_.
Example::
highlight_options = {
'default': {'stripall': True},
'php': {'startinline': True},
}
A single dictionary of options are also allowed. Then it is recognized
as options to the lexer specified by :confval:`highlight_language`::
# configuration for the ``highlight_language``
highlight_options = {'stripall': True}
.. versionadded:: 1.3 .. versionadded:: 1.3
.. versionchanged:: 3.5
Allow to configure highlight options for multiple languages
.. confval:: pygments_style .. confval:: pygments_style
@ -660,10 +685,11 @@ documentation on :ref:`intl` for details.
generated by Sphinx will be in that language. Also, Sphinx will try to generated by Sphinx will be in that language. Also, Sphinx will try to
substitute individual paragraphs from your documents with the translation substitute individual paragraphs from your documents with the translation
sets obtained from :confval:`locale_dirs`. Sphinx will search sets obtained from :confval:`locale_dirs`. Sphinx will search
language-specific figures named by `figure_language_filename` and substitute language-specific figures named by :confval:`figure_language_filename`
them for original figures. In the LaTeX builder, a suitable language will (e.g. the German version of ``myfigure.png`` will be ``myfigure.de.png``
be selected as an option for the *Babel* package. Default is ``None``, by default setting) and substitute them for original figures. In the LaTeX
which means that no translation will be done. builder, a suitable language will be selected as an option for the *Babel*
package. Default is ``None``, which means that no translation will be done.
.. versionadded:: 0.5 .. versionadded:: 0.5
@ -755,9 +781,15 @@ documentation on :ref:`intl` for details.
If true, a document's text domain is its docname if it is a top-level If true, a document's text domain is its docname if it is a top-level
project file and its very base directory otherwise. project file and its very base directory otherwise.
If set to string, all document's text domain is this string, making all
documents use single text domain.
By default, the document ``markup/code.rst`` ends up in the ``markup`` text By default, the document ``markup/code.rst`` ends up in the ``markup`` text
domain. With this option set to ``False``, it is ``markup/code``. domain. With this option set to ``False``, it is ``markup/code``.
.. versionchanged:: 3.3
The string value is now accepted.
.. confval:: gettext_uuid .. confval:: gettext_uuid
If true, Sphinx generates uuid information for version tracking in message If true, Sphinx generates uuid information for version tracking in message
@ -820,6 +852,8 @@ documentation on :ref:`intl` for details.
extension, e.g. ``dirname/filename`` extension, e.g. ``dirname/filename``
* ``{path}`` - the directory path component of the filename, with a trailing * ``{path}`` - the directory path component of the filename, with a trailing
slash if non-empty, e.g. ``dirname/`` slash if non-empty, e.g. ``dirname/``
* ``{docpath}`` - the directory path component for the current document, with
a trailing slash if non-empty.
* ``{basename}`` - the filename without the directory path or file extension * ``{basename}`` - the filename without the directory path or file extension
components, e.g. ``filename`` components, e.g. ``filename``
* ``{ext}`` - the file extension, e.g. ``.png`` * ``{ext}`` - the file extension, e.g. ``.png``
@ -833,6 +867,9 @@ documentation on :ref:`intl` for details.
.. versionchanged:: 1.5 .. versionchanged:: 1.5
Added ``{path}`` and ``{basename}`` tokens. Added ``{path}`` and ``{basename}`` tokens.
.. versionchanged:: 3.2
Added ``{docpath}`` token.
.. _math-options: .. _math-options:
@ -912,7 +949,7 @@ that use Sphinx's HTMLWriter class.
.. confval:: html_short_title .. confval:: html_short_title
A shorter "title" for the HTML docs. This is used in for links in the A shorter "title" for the HTML docs. This is used for links in the
header and in the HTML Help docs. If not given, it defaults to the value of header and in the HTML Help docs. If not given, it defaults to the value of
:confval:`html_title`. :confval:`html_title`.
@ -920,11 +957,23 @@ that use Sphinx's HTMLWriter class.
.. confval:: html_baseurl .. confval:: html_baseurl
The URL which points to the root of the HTML documentation. It is used to The base URL which points to the root of the HTML documentation. It is used
indicate the location of document like ``canonical_url``. to indicate the location of document using `The Canonical Link Relation`_.
Default: ``''``.
.. _The Canonical Link Relation: https://tools.ietf.org/html/rfc6596
.. versionadded:: 1.8 .. versionadded:: 1.8
.. confval:: html_codeblock_linenos_style
The style of line numbers for code-blocks.
* ``'table'`` -- display line numbers using ``<table>`` tag (default)
* ``'inline'`` -- display line numbers using ``<span>`` tag
.. versionadded:: 3.2
.. confval:: html_context .. confval:: html_context
A dictionary of values to pass into the template engine's context for all A dictionary of values to pass into the template engine's context for all
@ -970,7 +1019,14 @@ that use Sphinx's HTMLWriter class.
'https://example.com/css/custom.css', 'https://example.com/css/custom.css',
('print.css', {'media': 'print'})] ('print.css', {'media': 'print'})]
As a special attribute, *priority* can be set as an integer to load the CSS
file earlier or lazier step. For more information, refer
:meth:`Sphinx.add_css_files()`.
.. versionadded:: 1.8 .. versionadded:: 1.8
.. versionchanged:: 3.5
Support priority attribute
.. confval:: html_js_files .. confval:: html_js_files
@ -986,7 +1042,14 @@ that use Sphinx's HTMLWriter class.
'https://example.com/scripts/custom.js', 'https://example.com/scripts/custom.js',
('custom.js', {'async': 'async'})] ('custom.js', {'async': 'async'})]
As a special attribute, *priority* can be set as an integer to load the CSS
file earlier or lazier step. For more information, refer
:meth:`Sphinx.add_css_files()`.
.. versionadded:: 1.8 .. versionadded:: 1.8
.. versionchanged:: 3.5
Support priority attribute
.. confval:: html_static_path .. confval:: html_static_path
@ -1070,6 +1133,23 @@ that use Sphinx's HTMLWriter class.
This can now be a string to select the actual text of the link. This can now be a string to select the actual text of the link.
Previously, only boolean values were accepted. Previously, only boolean values were accepted.
.. deprecated:: 3.5
This has been replaced by :confval:`html_permalinks`
.. confval:: html_permalinks
If true, Sphinx will add "permalinks" for each heading and description
environment. Default: ``True``.
.. versionadded:: 3.5
.. confval:: html_permalinks_icon
A text for permalinks for each heading and description environment. HTML
tags are allowed. Default: a paragraph sign; ````
.. versionadded:: 3.5
.. confval:: html_sidebars .. confval:: html_sidebars
Custom sidebar templates, must be a dictionary that maps document names to Custom sidebar templates, must be a dictionary that maps document names to
@ -2224,6 +2304,12 @@ These options influence manual page output.
.. versionadded:: 1.1 .. versionadded:: 1.1
.. confval:: man_make_section_directory
If true, make a section directory on build man page. Default is False.
.. versionadded:: 3.3
.. _texinfo-options: .. _texinfo-options:
@ -2390,6 +2476,32 @@ Options for the linkcheck builder
.. versionadded:: 1.1 .. versionadded:: 1.1
.. confval:: linkcheck_request_headers
A dictionary that maps baseurls to HTTP request headers.
The key is a URL base string like ``"https://sphinx-doc.org/"``. To specify
headers for other hosts, ``"*"`` can be used. It matches all hosts only when
the URL does not match other settings.
The value is a dictionary that maps header name to its value.
Example:
.. code-block:: python
linkcheck_request_headers = {
"https://sphinx-doc.org/": {
"Accept": "text/html",
"Accept-Encoding": "utf-8",
},
"*": {
"Accept": "text/html,application/xhtml+xml",
}
}
.. versionadded:: 3.1
.. confval:: linkcheck_retries .. confval:: linkcheck_retries
The number of times the linkcheck builder will attempt to check a URL before The number of times the linkcheck builder will attempt to check a URL before
@ -2467,6 +2579,23 @@ Options for the linkcheck builder
.. versionadded:: 2.3 .. versionadded:: 2.3
.. confval:: linkcheck_rate_limit_timeout
The ``linkcheck`` builder may issue a large number of requests to the same
site over a short period of time. This setting controls the builder behavior
when servers indicate that requests are rate-limited.
If a server indicates when to retry (using the `Retry-After`_ header),
``linkcheck`` always follows the server indication.
Otherwise, ``linkcheck`` waits for a minute before to retry and keeps
doubling the wait time between attempts until it succeeds or exceeds the
``linkcheck_rate_limit_timeout``. By default, the timeout is 5 minutes.
.. _Retry-After: https://tools.ietf.org/html/rfc7231#section-7.1.3
.. versionadded:: 3.4
Options for the XML builder Options for the XML builder
--------------------------- ---------------------------
@ -2509,6 +2638,23 @@ Options for the C domain
.. versionadded:: 3.0 .. versionadded:: 3.0
.. confval:: c_allow_pre_v3
A boolean (default ``False``) controlling whether to parse and try to
convert pre-v3 style type directives and type roles.
.. versionadded:: 3.2
.. deprecated:: 3.2
Use the directives and roles added in v3.
.. confval:: c_warn_on_allowed_pre_v3
A boolean (default ``True``) controlling whether to warn when a pre-v3
style type directive/role is parsed and converted.
.. versionadded:: 3.2
.. deprecated:: 3.2
Use the directives and roles added in v3.
.. _cpp-config: .. _cpp-config:

View File

@ -136,15 +136,28 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
:undoc-members: :undoc-members:
* "Private" members (that is, those named like ``_private`` or ``__private``) * "Private" members (that is, those named like ``_private`` or ``__private``)
will be included if the ``private-members`` flag option is given. 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 .. versionadded:: 1.1
.. versionchanged:: 3.2
The option can now take arguments.
* autodoc considers a member private if its docstring contains * autodoc considers a member private if its docstring contains
``:meta private:`` in its :ref:`info-field-lists`. ``:meta private:`` in its :ref:`info-field-lists`.
For example: For example:
.. code-block:: rst .. code-block:: python
def my_function(my_arg, my_other_arg): def my_function(my_arg, my_other_arg):
"""blah blah blah """blah blah blah
@ -159,7 +172,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
an underscore. an underscore.
For example: For example:
.. code-block:: rst .. code-block:: python
def _my_function(my_arg, my_other_arg): def _my_function(my_arg, my_other_arg):
"""blah blah blah """blah blah blah
@ -169,6 +182,16 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
.. versionadded:: 3.1 .. versionadded:: 3.1
* autodoc considers a variable member does not have any default value if its
docstring contains ``:meta hide-value:`` in its :ref:`info-field-lists`.
Example:
.. code-block:: python
var1 = None #: :meta hide-value:
.. versionadded:: 3.5
* Python "special" members (that is, those named like ``__special__``) will * Python "special" members (that is, those named like ``__special__``) will
be included if the ``special-members`` flag option is given:: be included if the ``special-members`` flag option is given::
@ -216,7 +239,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
.. versionchanged:: 3.0 .. versionchanged:: 3.0
It takes an anchestor class name as an argument. It takes an ancestor class name as an argument.
* It's possible to override the signature for explicitly documented callable * It's possible to override the signature for explicitly documented callable
objects (functions, methods, classes) with the regular syntax that will objects (functions, methods, classes) with the regular syntax that will
@ -280,6 +303,12 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
.. versionadded:: 1.3 .. versionadded:: 1.3
* As a hint to autodoc extension, you can put a ``::`` separator in between
module name and object name to let autodoc know the correct module name if
it is ambiguous. ::
.. autoclass:: module.name::Noodle
.. rst:directive:: autofunction .. rst:directive:: autofunction
autodecorator autodecorator
@ -307,6 +336,15 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
By default, without ``annotation`` option, Sphinx tries to obtain the value of By default, without ``annotation`` option, Sphinx tries to obtain the value of
the variable and print it after the name. the variable and print it after the name.
The ``no-value`` option can be used instead of a blank ``annotation`` to show the
type hint but not the value::
.. autodata:: CD_DRIVE
:no-value:
If both the ``annotation`` and ``no-value`` options are used, ``no-value`` has no
effect.
For module data members and class attributes, documentation can either be put For module data members and class attributes, documentation can either be put
into a comment with special formatting (using a ``#:`` to start the comment into a comment with special formatting (using a ``#:`` to start the comment
instead of just ``#``), or in a docstring *after* the definition. Comments instead of just ``#``), or in a docstring *after* the definition. Comments
@ -346,6 +384,9 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
option. option.
.. versionchanged:: 2.0 .. versionchanged:: 2.0
:rst:dir:`autodecorator` added. :rst:dir:`autodecorator` added.
.. versionchanged:: 3.4
:rst:dir:`autodata` and :rst:dir:`autoattribute` now have a ``no-value``
option.
.. note:: .. note::
@ -496,6 +537,44 @@ There are also config values that you can set:
New option ``'description'`` is added. New option ``'description'`` is added.
.. confval:: autodoc_type_aliases
A dictionary for users defined `type aliases`__ that maps a type name to the
full-qualified object name. It is used to keep type aliases not evaluated in
the document. Defaults to empty (``{}``).
The type aliases are only available if your program enables `Postponed
Evaluation of Annotations (PEP 563)`__ feature via ``from __future__ import
annotations``.
For example, there is code using a type alias::
from __future__ import annotations
AliasType = Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]
def f() -> AliasType:
...
If ``autodoc_type_aliases`` is not set, autodoc will generate internal mark-up
from this code as following::
.. py:function:: f() -> Union[List[Dict[Tuple[int, str], Set[int]]], Tuple[str, List[str]]]
...
If you set ``autodoc_type_aliases`` as
``{'AliasType': 'your.module.AliasType'}``, it generates the following document
internally::
.. py:function:: f() -> your.module.AliasType:
...
.. __: https://www.python.org/dev/peps/pep-0563/
.. __: https://mypy.readthedocs.io/en/latest/kinds_of_types.html#type-aliases
.. versionadded:: 3.3
.. confval:: autodoc_warningiserror .. confval:: autodoc_warningiserror
This value controls the behavior of :option:`sphinx-build -W` during This value controls the behavior of :option:`sphinx-build -W` during

View File

@ -175,7 +175,7 @@ also use these config values:
.. confval:: autosummary_generate_overwrite .. confval:: autosummary_generate_overwrite
If true, autosummary already overwrites stub files by generated contents. If true, autosummary overwrites existing files by generated stub pages.
Defaults to true (enabled). Defaults to true (enabled).
.. versionadded:: 3.0 .. versionadded:: 3.0
@ -195,6 +195,15 @@ also use these config values:
.. versionadded:: 2.1 .. versionadded:: 2.1
.. confval:: autosummary_filename_map
A dict mapping object names to filenames. This is necessary to avoid
filename conflicts where multiple objects have names that are
indistinguishable when case is ignored, on file systems where filenames
are case-insensitive.
.. versionadded:: 3.2
Customizing templates Customizing templates
--------------------- ---------------------
@ -295,7 +304,7 @@ The following variables available in the templates:
.. data:: modules .. data:: modules
List containing names of "public" modules in the package. Only available for List containing names of "public" modules in the package. Only available for
modules that are packages. modules that are packages and the ``recursive`` option is on.
.. versionadded:: 3.1 .. versionadded:: 3.1

View File

@ -51,4 +51,11 @@ should check:
.. versionadded:: 1.1 .. versionadded:: 1.1
.. _Python regular expressions: https://docs.python.org/library/re .. confval:: coverage_show_missing_items
Print objects that are missing to standard output also.
``False`` by default.
.. versionadded:: 3.1
.. _Python regular expressions: https://docs.python.org/library/re

View File

@ -67,7 +67,7 @@ a comma-separated list of group names.
default set of flags is specified by the :confval:`doctest_default_flags` default set of flags is specified by the :confval:`doctest_default_flags`
configuration variable. configuration variable.
This directive supports three options: This directive supports five options:
* ``hide``, a flag option, hides the doctest block in other builders. By * ``hide``, a flag option, hides the doctest block in other builders. By
default it is shown as a highlighted doctest block. default it is shown as a highlighted doctest block.
@ -102,6 +102,11 @@ a comma-separated list of group names.
Supported PEP-440 operands and notations Supported PEP-440 operands and notations
* ``trim-doctest-flags`` and ``no-trim-doctest-flags``, a flag option,
doctest flags (comments looking like ``# doctest: FLAG, ...``) at the
ends of lines and ``<BLANKLINE>`` markers are removed (or not removed)
individually. Default is ``trim-doctest-flags``.
Note that like with standard doctests, you have to use ``<BLANKLINE>`` to Note that like with standard doctests, you have to use ``<BLANKLINE>`` to
signal a blank line in the expected output. The ``<BLANKLINE>`` is removed signal a blank line in the expected output. The ``<BLANKLINE>`` is removed
when building presentation output (HTML, LaTeX etc.). when building presentation output (HTML, LaTeX etc.).
@ -119,11 +124,16 @@ a comma-separated list of group names.
A code block for a code-output-style test. A code block for a code-output-style test.
This directive supports one option: This directive supports three options:
* ``hide``, a flag option, hides the code block in other builders. By * ``hide``, a flag option, hides the code block in other builders. By
default it is shown as a highlighted code block. default it is shown as a highlighted code block.
* ``trim-doctest-flags`` and ``no-trim-doctest-flags``, a flag option,
doctest flags (comments looking like ``# doctest: FLAG, ...``) at the
ends of lines and ``<BLANKLINE>`` markers are removed (or not removed)
individually. Default is ``trim-doctest-flags``.
.. note:: .. note::
Code in a ``testcode`` block is always executed all at once, no matter how Code in a ``testcode`` block is always executed all at once, no matter how
@ -149,7 +159,7 @@ a comma-separated list of group names.
The corresponding output, or the exception message, for the last The corresponding output, or the exception message, for the last
:rst:dir:`testcode` block. :rst:dir:`testcode` block.
This directive supports two options: This directive supports four options:
* ``hide``, a flag option, hides the output block in other builders. By * ``hide``, a flag option, hides the output block in other builders. By
default it is shown as a literal block without highlighting. default it is shown as a literal block without highlighting.
@ -157,6 +167,11 @@ a comma-separated list of group names.
* ``options``, a string option, can be used to give doctest flags * ``options``, a string option, can be used to give doctest flags
(comma-separated) just like in normal doctest blocks. (comma-separated) just like in normal doctest blocks.
* ``trim-doctest-flags`` and ``no-trim-doctest-flags``, a flag option,
doctest flags (comments looking like ``# doctest: FLAG, ...``) at the
ends of lines and ``<BLANKLINE>`` markers are removed (or not removed)
individually. Default is ``trim-doctest-flags``.
Example:: Example::
.. testcode:: .. testcode::

View File

@ -294,3 +294,21 @@ class ExampleClass:
def _private_without_docstring(self): def _private_without_docstring(self):
pass pass
class ExamplePEP526Class:
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Args`` section. If ``napoleon_attr_annotations``
is True, types can be specified in the class body using ``PEP 526``
annotations.
Attributes:
attr1: Description of `attr1`.
attr2: Description of `attr2`.
"""
attr1: str
attr2: int

View File

@ -75,8 +75,9 @@ linking:
A dictionary mapping unique identifiers to a tuple ``(target, inventory)``. A dictionary mapping unique identifiers to a tuple ``(target, inventory)``.
Each ``target`` is the base URI of a foreign Sphinx documentation set and can Each ``target`` is the base URI of a foreign Sphinx documentation set and can
be a local path or an HTTP URI. The ``inventory`` indicates where the be a local path or an HTTP URI. The ``inventory`` indicates where the
inventory file can be found: it can be ``None`` (at the same location as inventory file can be found: it can be ``None`` (an :file:`objects.inv` file
the base URI) or another local or HTTP URI. at the same location as the base URI) or another local file path or a full
HTTP URI to an inventory file.
The unique identifier can be used to prefix cross-reference targets, so that The unique identifier can be used to prefix cross-reference targets, so that
it is clear which intersphinx set the target belongs to. A link like it is clear which intersphinx set the target belongs to. A link like
@ -106,7 +107,7 @@ linking:
``https://docs.python.org/3``. It is up to you to update the inventory file ``https://docs.python.org/3``. It is up to you to update the inventory file
as new objects are added to the Python documentation. as new objects are added to the Python documentation.
**Multiple target for the inventory** **Multiple targets for the inventory**
.. versionadded:: 1.3 .. versionadded:: 1.3
@ -120,6 +121,16 @@ linking:
intersphinx_mapping = {'python': ('https://docs.python.org/3', intersphinx_mapping = {'python': ('https://docs.python.org/3',
(None, 'python-inv.txt'))} (None, 'python-inv.txt'))}
For a set of books edited and tested locally and then published
together, it could be helpful to try a local inventory file first,
to check references before publication::
intersphinx_mapping = {
'otherbook':
('https://myproj.readthedocs.io/projects/otherbook/en/latest',
('../../otherbook/build/html/objects.inv', None)),
}
.. confval:: intersphinx_cache_limit .. confval:: intersphinx_cache_limit
The maximum number of days to cache remote inventories. The default is The maximum number of days to cache remote inventories. The default is

View File

@ -115,6 +115,7 @@ All of the following section headers are supported:
* ``Parameters`` * ``Parameters``
* ``Return`` *(alias of Returns)* * ``Return`` *(alias of Returns)*
* ``Returns`` * ``Returns``
* ``Raise`` *(alias of Raises)*
* ``Raises`` * ``Raises``
* ``References`` * ``References``
* ``See Also`` * ``See Also``
@ -122,6 +123,7 @@ All of the following section headers are supported:
* ``Todo`` * ``Todo``
* ``Warning`` * ``Warning``
* ``Warnings`` *(alias of Warning)* * ``Warnings`` *(alias of Warning)*
* ``Warn`` *(alias of Warns)*
* ``Warns`` * ``Warns``
* ``Yield`` *(alias of Yields)* * ``Yield`` *(alias of Yields)*
* ``Yields`` * ``Yields``
@ -201,7 +203,8 @@ Type Annotations
This is an alternative to expressing types directly in docstrings. This is an alternative to expressing types directly in docstrings.
One benefit of expressing types according to `PEP 484`_ is that One benefit of expressing types according to `PEP 484`_ is that
type checkers and IDEs can take advantage of them for static code type checkers and IDEs can take advantage of them for static code
analysis. analysis. `PEP 484`_ was then extended by `PEP 526`_ which introduced
a similar way to annotate variables (and attributes).
Google style with Python 3 type annotations:: Google style with Python 3 type annotations::
@ -219,6 +222,19 @@ Google style with Python 3 type annotations::
""" """
return True return True
class Class:
"""Summary line.
Extended description of class
Attributes:
attr1: Description of attr1
attr2: Description of attr2
"""
attr1: int
attr2: str
Google style with types in docstrings:: Google style with types in docstrings::
@ -236,6 +252,16 @@ Google style with types in docstrings::
""" """
return True return True
class Class:
"""Summary line.
Extended description of class
Attributes:
attr1 (int): Description of attr1
attr2 (str): Description of attr2
"""
.. Note:: .. Note::
`Python 2/3 compatible annotations`_ aren't currently `Python 2/3 compatible annotations`_ aren't currently
@ -244,6 +270,9 @@ Google style with types in docstrings::
.. _PEP 484: .. _PEP 484:
https://www.python.org/dev/peps/pep-0484/ https://www.python.org/dev/peps/pep-0484/
.. _PEP 526:
https://www.python.org/dev/peps/pep-0526/
.. _Python 2/3 compatible annotations: .. _Python 2/3 compatible annotations:
https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code
@ -272,11 +301,13 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
napoleon_use_ivar = False napoleon_use_ivar = False
napoleon_use_param = True napoleon_use_param = True
napoleon_use_rtype = True napoleon_use_rtype = True
napoleon_type_aliases = None
napoleon_attr_annotations = True
.. _Google style: .. _Google style:
https://google.github.io/styleguide/pyguide.html https://google.github.io/styleguide/pyguide.html
.. _NumPy style: .. _NumPy style:
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
.. confval:: napoleon_google_docstring .. confval:: napoleon_google_docstring
@ -433,7 +464,7 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
:param arg1: Description of `arg1` :param arg1: Description of `arg1`
:type arg1: str :type arg1: str
:param arg2: Description of `arg2`, defaults to 0 :param arg2: Description of `arg2`, defaults to 0
:type arg2: int, optional :type arg2: :class:`int`, *optional*
**If False**:: **If False**::
@ -478,3 +509,65 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
**If False**:: **If False**::
:returns: *bool* -- True if successful, False otherwise :returns: *bool* -- True if successful, False otherwise
.. confval:: napoleon_type_aliases
A mapping to translate type names to other names or references. Works
only when ``napoleon_use_param = True``. *Defaults to None.*
With::
napoleon_type_aliases = {
"CustomType": "mypackage.CustomType",
"dict-like": ":term:`dict-like <mapping>`",
}
This `NumPy style`_ snippet::
Parameters
----------
arg1 : CustomType
Description of `arg1`
arg2 : dict-like
Description of `arg2`
becomes::
:param arg1: Description of `arg1`
:type arg1: mypackage.CustomType
:param arg2: Description of `arg2`
:type arg2: :term:`dict-like <mapping>`
.. versionadded:: 3.2
.. confval:: napoleon_attr_annotations
True to allow using `PEP 526`_ attributes annotations in classes.
If an attribute is documented in the docstring without a type and
has an annotation in the class body, that type is used.
.. versionadded:: 3.4
.. confval:: napoleon_custom_sections
Add a list of custom sections to include, expanding the list of parsed sections.
*Defaults to None.*
The entries can either be strings or tuples, depending on the intention:
* To create a custom "generic" section, just pass a string.
* To create an alias for an existing section, pass a tuple containing the
alias name and the original, in that order.
* To create a custom section that displays like the parameters or returns
section, pass a tuple containing the custom section name and a string
value, "params_style" or "returns_style".
If an entry is just a string, it is interpreted as a header for a generic
section. If the entry is a tuple/list/indexed container, the first entry
is the name of the section, the second is the section key to emulate. If the
second entry value is "params_style" or "returns_style", the custom section
will be displayed like the parameters section or returns section.
.. versionadded:: 1.8
.. versionchanged:: 3.5
Support ``params_style`` and ``returns_style``

View File

@ -171,7 +171,7 @@ Docker images for Sphinx are published on the `Docker Hub <https://hub.docker.co
- `sphinxdoc/sphinx <https://hub.docker.com/repository/docker/sphinxdoc/sphinx>`_ - `sphinxdoc/sphinx <https://hub.docker.com/repository/docker/sphinxdoc/sphinx>`_
- `sphinxdoc/sphinx-latexpdf <https://hub.docker.com/repository/docker/sphinxdoc/sphinx-latexpdf>`_ - `sphinxdoc/sphinx-latexpdf <https://hub.docker.com/repository/docker/sphinxdoc/sphinx-latexpdf>`_
Former one is used for standard usage of Sphinx, and latter one is mainly used for PDF builds using LaTeX. Former one is used for standard usage of Sphinx, and latter one is mainly used for PDF builds using LaTeX.
Please choose one for your purpose. Please choose one for your purpose.
.. note:: .. note::

View File

@ -15,7 +15,7 @@ Much of Sphinx's power comes from the richness of its default plain-text markup
format, :doc:`reStructuredText </usage/restructuredtext/index>`, along with format, :doc:`reStructuredText </usage/restructuredtext/index>`, along with
it's :doc:`significant extensibility capabilities </development/index>`. it's :doc:`significant extensibility capabilities </development/index>`.
The goal of this document is to give you a quick taste of what Sphinx it is and 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 how you might use it. When you're done here, you can check out the
:doc:`installation guide </usage/installation>` followed by the intro to the :doc:`installation guide </usage/installation>` followed by the intro to the
default markup format used by Sphinx, :doc:`reStucturedText default markup format used by Sphinx, :doc:`reStucturedText

View File

@ -114,9 +114,9 @@ tables of contents. The ``toctree`` directive is the central element.
**Additional options** **Additional options**
You can use ``caption`` option to provide a toctree caption and you can use You can use the ``caption`` option to provide a toctree caption and you can
``name`` option to provide implicit target name that can be referenced by use the ``name`` option to provide an implicit target name that can be
using :rst:role:`ref`:: referenced by using :rst:role:`ref`::
.. toctree:: .. toctree::
:caption: Table of Contents :caption: Table of Contents
@ -246,7 +246,7 @@ The special document names (and pages generated for them) are:
* every name beginning with ``_`` * every name beginning with ``_``
Though only few such names are currently used by Sphinx, you should not Though few such names are currently used by Sphinx, you should not
create documents or document-containing directories with such names. (Using create documents or document-containing directories with such names. (Using
``_`` as a prefix for a custom template directory is fine.) ``_`` as a prefix for a custom template directory is fine.)
@ -569,12 +569,28 @@ __ http://pygments.org/docs/lexers
print 'Explicit is better than implicit.' print 'Explicit is better than implicit.'
In order to cross-reference a code-block using either the
:rst:role:`ref` or the :rst:role:`numref` role, it is necessary
that both :strong:`name` and :strong:`caption` be defined. The
argument of :strong:`name` can then be given to :rst:role:`numref`
to generate the cross-reference. Example::
See :numref:`this-py` for an example.
When using :rst:role:`ref`, it is possible to generate a cross-reference
with only :strong:`name` defined, provided an explicit title is
given. Example::
See :ref:`this code snippet <this-py>` for an example.
.. versionadded:: 1.3 .. versionadded:: 1.3
.. rst:directive:option:: dedent: number .. rst:directive:option:: dedent: number
:type: number :type: number or no value
Strip indentation characters from the code block. For example:: Strip indentation characters from the code block. When number given,
leading N characters are removed. When no argument given, leading spaces
are removed via :func:`textwrap.dedent()`. For example::
.. code-block:: ruby .. code-block:: ruby
:dedent: 4 :dedent: 4
@ -582,6 +598,8 @@ __ http://pygments.org/docs/lexers
some ruby code some ruby code
.. versionadded:: 1.3 .. versionadded:: 1.3
.. versionchanged:: 3.5
Support automatic dedent.
.. rst:directive:option:: force .. rst:directive:option:: force
:type: no value :type: no value
@ -656,9 +674,43 @@ __ http://pygments.org/docs/lexers
string are included. The ``start-at`` and ``end-at`` options behave in a string are included. The ``start-at`` and ``end-at`` options behave in a
similar way, but the lines containing the matched string are included. similar way, but the lines containing the matched string are included.
With lines selected using ``start-after`` it is still possible to use ``start-after``/``start-at`` and ``end-before``/``end-at`` can have same string.
``lines``, the first allowed line having by convention the line number ``start-after``/``start-at`` filter lines before the line that contains
``1``. option string (``start-at`` will keep the line). Then ``end-before``/``end-at``
filter lines after the line that contains option string (``end-at`` will keep
the line and ``end-before`` skip the first line).
.. note::
If you want to select only ``[second-section]`` of ini file like the
following, you can use ``:start-at: [second-section]`` and
``:end-before: [third-section]``:
.. code-block:: ini
[first-section]
var_in_first=true
[second-section]
var_in_second=true
[third-section]
var_in_third=true
Useful cases of these option is working with tag comments.
``:start-after: [initialized]`` and ``:end-before: [initialized]`` options
keep lines between comments:
.. code-block:: py
if __name__ == "__main__":
# [initialize]
app.start(":8000")
# [initialize]
When lines have been selected in any of the ways described above, the line When lines have been selected in any of the ways described above, the line
numbers in ``emphasize-lines`` refer to those selected lines, counted numbers in ``emphasize-lines`` refer to those selected lines, counted
@ -708,6 +760,9 @@ __ http://pygments.org/docs/lexers
.. versionchanged:: 2.1 .. versionchanged:: 2.1
Added the ``force`` option. Added the ``force`` option.
.. versionchanged:: 3.5
Support automatic dedent.
.. _glossary-directive: .. _glossary-directive:
Glossary Glossary
@ -1165,20 +1220,29 @@ the definition of the symbol. There is this directive:
the following definition. If the definition spans multiple lines, each the following definition. If the definition spans multiple lines, each
continuation line must begin with a colon placed at the same column as in continuation line must begin with a colon placed at the same column as in
the first line. the first line.
Blank lines are not allowed within ``productionlist`` directive arguments.
The definition can contain token names which are marked as interpreted text
(e.g., "``sum ::= `integer` "+" `integer```") -- this generates
cross-references to the productions of these tokens. Outside of the
production list, you can reference to token productions using
:rst:role:`token`.
The *productionGroup* argument to :rst:dir:`productionlist` serves to The *productionGroup* argument to :rst:dir:`productionlist` serves to
distinguish different sets of production lists that belong to different distinguish different sets of production lists that belong to different
grammars. Multiple production lists with the same *productionGroup* thus grammars. Multiple production lists with the same *productionGroup* thus
define rules in the same scope. define rules in the same scope.
Blank lines are not allowed within ``productionlist`` directive arguments. Inside of the production list, tokens implicitly refer to productions
from the current group. You can refer to the production of another
grammar by prefixing the token with its group name and a colon, e.g,
"``otherGroup:sum``". If the group of the token should not be shown in
the production, it can be prefixed by a tilde, e.g.,
"``~otherGroup:sum``". To refer to a production from an unnamed
grammar, the token should be prefixed by a colon, e.g., "``:sum``".
The definition can contain token names which are marked as interpreted text Outside of the production list,
(e.g. "``sum ::= `integer` "+" `integer```") -- this generates if you have given a *productionGroup* argument you must prefix the
cross-references to the productions of these tokens. Outside of the
production list, you can reference to token productions using
:rst:role:`token`.
However, if you have given a *productionGroup* argument you must prefix the
token name in the cross-reference with the group name and a colon, token name in the cross-reference with the group name and a colon,
e.g., "``myGroup:sum``" instead of just "``sum``". e.g., "``myGroup:sum``" instead of just "``sum``".
If the group should not be shown in the title of the link either If the group should not be shown in the title of the link either

View File

@ -42,9 +42,22 @@ Basic Markup
Most domains provide a number of :dfn:`object description directives`, used to Most domains provide a number of :dfn:`object description directives`, used to
describe specific objects provided by modules. Each directive requires one or describe specific objects provided by modules. Each directive requires one or
more signatures to provide basic information about what is being described, and more signatures to provide basic information about what is being described, and
the content should be the description. The basic version makes entries in the the content should be the description. A domain will typically keep an
general index; if no index entry is desired, you can give the directive option internal index of all entites to aid cross-referencing. Typically it will
flag ``:noindex:``. An example using a Python domain directive:: also add entries in the shown general index.
If you want to suppress the addition of an entry in the shown index, you can
give the directive option flag ``:noindexentry:``.
If you want to typeset an object description, without even making it available
for cross-referencing, you can give the directive option flag ``:noindex:``
(which implies ``:noindexentry:``).
Though, note that not every directive en every domain may support these
options.
.. versionadded:: 3.2
The directive option ``noindexentry`` in the Python, C, C++, and Javascript
domains.
An example using a Python domain directive::
.. py:function:: spam(eggs) .. py:function:: spam(eggs)
ham(eggs) ham(eggs)
@ -699,6 +712,53 @@ Explicit ref: :c:var:`Data.@data.a`. Short-hand ref: :c:var:`Data.a`.
.. versionadded:: 3.0 .. versionadded:: 3.0
Aliasing Declarations
~~~~~~~~~~~~~~~~~~~~~
.. c:namespace-push:: @alias
Sometimes it may be helpful list declarations elsewhere than their main
documentation, e.g., when creating a synopsis of an interface.
The following directive can be used for this purpose.
.. rst:directive:: .. c:alias:: name
Insert one or more alias declarations. Each entity can be specified
as they can in the :rst:role:`c:any` role.
For example::
.. c:var:: int data
.. c:function:: int f(double k)
.. c:alias:: data
f
becomes
.. c:var:: int data
.. c:function:: int f(double k)
.. c:alias:: data
f
.. versionadded:: 3.2
.. rubric:: Options
.. rst:directive:option:: maxdepth: int
Insert nested declarations as well, up to the total depth given.
Use 0 for infinite depth and 1 for just the mentioned declaration.
Defaults to 1.
.. versionadded:: 3.3
.. c:namespace-pop::
Inline Expressions and Types Inline Expressions and Types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -1038,7 +1098,7 @@ Options
Some directives support options: Some directives support options:
- ``:noindex:``, see :ref:`basic-domain-markup`. - ``:noindexentry:``, see :ref:`basic-domain-markup`.
- ``:tparam-line-spec:``, for templated declarations. - ``:tparam-line-spec:``, for templated declarations.
If specified, each template parameter will be rendered on a separate line. If specified, each template parameter will be rendered on a separate line.

View File

@ -9,7 +9,14 @@ fields marked up like this::
:fieldname: Field content :fieldname: Field content
Sphinx provides custom behavior for bibliographic fields compared to docutils. Sphinx extends standard docutils behavior for field lists and adds some extra
functionality that is covered in this section.
.. note::
The values of field lists will be parsed as
strings. You cannot use Python collections such as lists or dictionaries.
.. _metadata: .. _metadata:
@ -17,11 +24,20 @@ File-wide metadata
------------------ ------------------
A field list near the top of a file is normally parsed by docutils as the A field list near the top of a file is normally parsed by docutils as the
*docinfo* which is generally used to record the author, date of publication and *docinfo* and shown on the page. However, in Sphinx, a field list preceding
other metadata. However, in Sphinx, a field list preceding any other markup is any other markup is moved from the *docinfo* to the Sphinx environment as
moved from the *docinfo* to the Sphinx environment as document metadata and is document metadata, and is not displayed in the output.
not displayed in the output; a field list appearing after the document title
will be part of the *docinfo* as normal and will be displayed in the output. .. note::
A field list appearing after the document title *will* be part of the
*docinfo* as normal and will be displayed in the output.
Special metadata fields
-----------------------
Sphinx provides custom behavior for bibliographic fields compared to docutils.
At the moment, these metadata fields are recognized: At the moment, these metadata fields are recognized:

View File

@ -2,8 +2,8 @@
.. _html-themes: .. _html-themes:
HTML HTML Theming
==== ============
Sphinx provides a number of builders for HTML and HTML-based formats. Sphinx provides a number of builders for HTML and HTML-based formats.
@ -21,7 +21,8 @@ Themes
.. note:: .. note::
This section provides information about using pre-existing HTML themes. If This section provides information about using pre-existing HTML themes. If
you wish to create your own theme, refer to :doc:`/theming`. you wish to create your own theme, refer to
:doc:`/development/theming`.
Sphinx supports changing the appearance of its HTML output via *themes*. A Sphinx supports changing the appearance of its HTML output via *themes*. A
theme is a collection of HTML templates, stylesheet(s) and other static files. theme is a collection of HTML templates, stylesheet(s) and other static files.
@ -80,7 +81,7 @@ zipfile-based theme::
html_theme = "dotted" html_theme = "dotted"
For more information on the design of themes, including information about For more information on the design of themes, including information about
writing your own themes, refer to :doc:`/theming`. writing your own themes, refer to :doc:`/development/theming`.
.. _builtin-themes: .. _builtin-themes:
@ -172,6 +173,12 @@ These themes are:
.. versionadded:: 3.1 .. versionadded:: 3.1
- **globaltoc_maxdepth** (int): The maximum depth of the toctree in
``globaltoc.html`` (see :confval:`html_sidebars`). Set it to -1 to allow
unlimited depth. Defaults to the max depth selected in the toctree directive.
.. versionadded:: 3.2
**alabaster** **alabaster**
`Alabaster theme`_ is a modified "Kr" Sphinx theme from @kennethreitz `Alabaster theme`_ is a modified "Kr" Sphinx theme from @kennethreitz
(especially as used in his Requests project), which was itself originally (especially as used in his Requests project), which was itself originally
@ -341,7 +348,7 @@ Third Party Themes
There are many third-party themes available. Some of these are general use, 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 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__ and themes is listed below. Many more can be found on PyPI__, GitHub__, GitLab__ and
sphinx-themes.org__. sphinx-themes.org__.
.. cssclass:: clear .. cssclass:: clear
@ -357,6 +364,8 @@ sphinx-themes.org__.
.. versionchanged:: 1.4 .. versionchanged:: 1.4
**sphinx_rtd_theme** has become optional. **sphinx_rtd_theme** has become optional.
.. __: https://pypi.org/search/?q=&o=&c=Framework+%3A%3A+Sphinx+%3A%3A+Theme .. __: 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://github.com/search?utf8=%E2%9C%93&q=sphinx+theme&type=
.. __: https://gitlab.com/explore?name=sphinx+theme
.. __: https://sphinx-themes.org/ .. __: https://sphinx-themes.org/

28
package-lock.json generated
View File

@ -385,12 +385,6 @@
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
"dev": true "dev": true
}, },
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"dev": true
},
"extend": { "extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@ -535,14 +529,22 @@
} }
}, },
"http-proxy": { "http-proxy": {
"version": "1.17.0", "version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"eventemitter3": "^3.0.0", "eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0", "follow-redirects": "^1.0.0",
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
},
"dependencies": {
"eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"dev": true
}
} }
}, },
"iconv-lite": { "iconv-lite": {
@ -702,9 +704,9 @@
} }
}, },
"lodash": { "lodash": {
"version": "4.17.14", "version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
"dev": true "dev": true
}, },
"log4js": { "log4js": {

View File

@ -29,9 +29,11 @@ directory = sphinx/locale/
[flake8] [flake8]
max-line-length = 95 max-line-length = 95
ignore = E116,E241,E251,E741,W504,I101 ignore = E116,E241,E251,E741,W504,I101
exclude = .git,.tox,.venv,tests/*,build/*,doc/_build/*,sphinx/search/*,doc/usage/extensions/example*.py exclude = .git,.tox,.venv,tests/roots/*,build/*,doc/_build/*,sphinx/search/*,doc/usage/extensions/example*.py
application-import-names = sphinx application-import-names = sphinx
import-order-style = smarkets import-order-style = smarkets
per-file-ignores =
tests/*: E501
[flake8:local-plugins] [flake8:local-plugins]
extension = extension =
@ -39,6 +41,9 @@ extension =
paths = paths =
. .
[isort]
line_length = 95
[mypy] [mypy]
python_version = 3.5 python_version = 3.5
disallow_incomplete_defs = True disallow_incomplete_defs = True
@ -55,12 +60,11 @@ filterwarnings =
all all
ignore::DeprecationWarning:docutils.io ignore::DeprecationWarning:docutils.io
ignore::DeprecationWarning:pyximport.pyximport ignore::DeprecationWarning:pyximport.pyximport
ignore::ImportWarning:importlib._bootstrap
ignore::PendingDeprecationWarning:sphinx.util.pycompat ignore::PendingDeprecationWarning:sphinx.util.pycompat
markers = markers =
sphinx
apidoc apidoc
setup_command setup_command
test_params
testpaths = tests testpaths = tests
[coverage:run] [coverage:run]

View File

@ -43,15 +43,15 @@ extras_require = {
], ],
'lint': [ 'lint': [
'flake8>=3.5.0', 'flake8>=3.5.0',
'flake8-import-order', 'isort',
'mypy>=0.770', 'mypy>=0.800',
'docutils-stubs', 'docutils-stubs',
], ],
'test': [ 'test': [
'pytest', 'pytest',
'pytest-cov', 'pytest-cov',
'html5lib', 'html5lib',
'typed_ast', # for py35-37 "typed_ast; python_version < '3.8'",
'cython', 'cython',
], ],
} }
@ -76,9 +76,10 @@ class Tee:
try: try:
from babel.messages.pofile import read_po
from babel.messages.frontend import compile_catalog
from json import dump from json import dump
from babel.messages.frontend import compile_catalog
from babel.messages.pofile import read_po
except ImportError: except ImportError:
pass pass
else: else:
@ -139,7 +140,7 @@ else:
domain + '.js')) domain + '.js'))
for js_file, (locale, po_file) in zip(js_files, po_files): for js_file, (locale, po_file) in zip(js_files, po_files):
with open(po_file) as infile: with open(po_file, encoding='utf8') as infile:
catalog = read_po(infile, locale) catalog = read_po(infile, locale)
if catalog.fuzzy and not self.use_fuzzy: if catalog.fuzzy and not self.use_fuzzy:
@ -157,13 +158,13 @@ else:
msgid = msgid[0] msgid = msgid[0]
jscatalog[msgid] = message.string jscatalog[msgid] = message.string
with open(js_file, 'wt') as outfile: with open(js_file, 'wt', encoding='utf8') as outfile:
outfile.write('Documentation.addTranslations(') outfile.write('Documentation.addTranslations(')
dump({ dump({
'messages': jscatalog, 'messages': jscatalog,
'plural_expr': catalog.plural_expr, 'plural_expr': catalog.plural_expr,
'locale': str(catalog.locale) 'locale': str(catalog.locale)
}, outfile, sort_keys=True) }, outfile, sort_keys=True, indent=4)
outfile.write(');') outfile.write(');')
cmdclass['compile_catalog'] = compile_catalog_plusjs cmdclass['compile_catalog'] = compile_catalog_plusjs
@ -203,6 +204,7 @@ setup(
'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy', 'Programming Language :: Python :: Implementation :: PyPy',
'Framework :: Setuptools Plugin', 'Framework :: Setuptools Plugin',

View File

@ -4,7 +4,7 @@
The Sphinx documentation toolchain. The Sphinx documentation toolchain.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -32,8 +32,8 @@ if 'PYTHONWARNINGS' not in os.environ:
warnings.filterwarnings('ignore', "'U' mode is deprecated", warnings.filterwarnings('ignore', "'U' mode is deprecated",
DeprecationWarning, module='docutils.io') DeprecationWarning, module='docutils.io')
__version__ = '3.1.0+' __version__ = '3.5.0+'
__released__ = '3.1.0' # used when Sphinx builds its own docs __released__ = '3.5.0' # used when Sphinx builds its own docs
#: Version info for better programmatic use. #: Version info for better programmatic use.
#: #:
@ -43,7 +43,7 @@ __released__ = '3.1.0' # used when Sphinx builds its own docs
#: #:
#: .. versionadded:: 1.2 #: .. versionadded:: 1.2
#: Before version 1.2, check the string ``sphinx.__version__``. #: Before version 1.2, check the string ``sphinx.__version__``.
version_info = (3, 1, 0, 'beta', 0) version_info = (3, 5, 0, 'beta', 0)
package_dir = path.abspath(path.dirname(__file__)) package_dir = path.abspath(path.dirname(__file__))

View File

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

View File

@ -4,7 +4,7 @@
Additional docutils nodes. Additional docutils nodes.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -21,6 +21,33 @@ if False:
from sphinx.application import Sphinx from sphinx.application import Sphinx
class document(nodes.document):
"""The document root element patched by Sphinx.
This fixes that document.set_id() does not support a node having multiple node Ids.
see https://sourceforge.net/p/docutils/patches/167/
.. important:: This is only for Sphinx internal use. Please don't use this
in your extensions. It will be removed without deprecation period.
"""
def set_id(self, node: Element, msgnode: Element = None,
suggested_prefix: str = '') -> str:
from sphinx.util import docutils
if docutils.__version_info__ >= (0, 16):
ret = super().set_id(node, msgnode, suggested_prefix) # type: ignore
else:
ret = super().set_id(node, msgnode)
if docutils.__version_info__ < (0, 17):
# register other node IDs forcedly
for node_id in node['ids']:
if node_id not in self.ids:
self.ids[node_id] = node
return ret
class translatable(nodes.Node): class translatable(nodes.Node):
"""Node which supports translation. """Node which supports translation.

View File

@ -6,7 +6,7 @@
Gracefully adapted from the TextPress system by Armin. Gracefully adapted from the TextPress system by Armin.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -18,16 +18,17 @@ import warnings
from collections import deque from collections import deque
from io import StringIO from io import StringIO
from os import path from os import path
from typing import Any, Callable, Dict, IO, List, Tuple, Union from typing import IO, Any, Callable, Dict, List, Optional, Tuple, Union
from docutils import nodes from docutils import nodes
from docutils.nodes import Element, TextElement from docutils.nodes import Element, TextElement
from docutils.parsers import Parser
from docutils.parsers.rst import Directive, roles from docutils.parsers.rst import Directive, roles
from docutils.transforms import Transform from docutils.transforms import Transform
from pygments.lexer import Lexer from pygments.lexer import Lexer
import sphinx import sphinx
from sphinx import package_dir, locale from sphinx import locale, package_dir
from sphinx.config import Config from sphinx.config import Config
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.domains import Domain, Index from sphinx.domains import Domain, Index
@ -42,9 +43,7 @@ from sphinx.project import Project
from sphinx.registry import SphinxComponentRegistry from sphinx.registry import SphinxComponentRegistry
from sphinx.roles import XRefRole from sphinx.roles import XRefRole
from sphinx.theming import Theme from sphinx.theming import Theme
from sphinx.util import docutils from sphinx.util import docutils, logging, progress_message
from sphinx.util import logging
from sphinx.util import progress_message
from sphinx.util.build_phase import BuildPhase from sphinx.util.build_phase import BuildPhase
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.i18n import CatalogRepository from sphinx.util.i18n import CatalogRepository
@ -55,8 +54,10 @@ from sphinx.util.typing import RoleFunction, TitleGetter
if False: if False:
# For type annotation # For type annotation
from docutils.nodes import Node # NOQA
from typing import Type # for python3.5.1 from typing import Type # for python3.5.1
from docutils.nodes import Node # NOQA
from sphinx.builders import Builder from sphinx.builders import Builder
@ -134,7 +135,7 @@ class Sphinx:
:ivar outdir: Directory for storing build documents. :ivar outdir: Directory for storing build documents.
""" """
def __init__(self, srcdir: str, confdir: str, outdir: str, doctreedir: str, def __init__(self, srcdir: str, confdir: Optional[str], outdir: str, doctreedir: str,
buildername: str, confoverrides: Dict = None, buildername: str, confoverrides: Dict = None,
status: IO = sys.stdout, warning: IO = sys.stderr, status: IO = sys.stdout, warning: IO = sys.stderr,
freshenv: bool = False, warningiserror: bool = False, tags: List[str] = None, freshenv: bool = False, warningiserror: bool = False, tags: List[str] = None,
@ -165,7 +166,7 @@ class Sphinx:
if path.exists(self.outdir) and not path.isdir(self.outdir): if path.exists(self.outdir) and not path.isdir(self.outdir):
raise ApplicationError(__('Output directory (%s) is not a directory') % raise ApplicationError(__('Output directory (%s) is not a directory') %
self.srcdir) self.outdir)
if self.srcdir == self.outdir: if self.srcdir == self.outdir:
raise ApplicationError(__('Source directory and destination ' raise ApplicationError(__('Source directory and destination '
@ -293,7 +294,10 @@ class Sphinx:
if catalog.domain == 'sphinx' and catalog.is_outdated(): if catalog.domain == 'sphinx' and catalog.is_outdated():
catalog.write_mo(self.config.language) catalog.write_mo(self.config.language)
locale_dirs = [None, path.join(package_dir, 'locale')] + list(repo.locale_dirs) locale_dirs = list(repo.locale_dirs) # type: List[Optional[str]]
locale_dirs += [None]
locale_dirs += [path.join(package_dir, 'locale')]
self.translator, has_translation = locale.init(locale_dirs, self.config.language) self.translator, has_translation = locale.init(locale_dirs, self.config.language)
if has_translation or self.config.language == 'en': if has_translation or self.config.language == 'en':
# "en" never needs to be translated # "en" never needs to be translated
@ -400,9 +404,10 @@ class Sphinx:
def require_sphinx(self, version: str) -> None: def require_sphinx(self, version: str) -> None:
"""Check the Sphinx version if requested. """Check the Sphinx version if requested.
Compare *version* (which must be a ``major.minor`` version string, e.g. Compare *version* with the version of the running Sphinx, and abort the
``'1.1'``) with the version of the running Sphinx, and abort the build build when it is too old.
when it is too old.
:param version: The required version in the form of ``major.minor``.
.. versionadded:: 1.0 .. versionadded:: 1.0
""" """
@ -416,11 +421,11 @@ class Sphinx:
For details on available core events and the arguments of callback For details on available core events and the arguments of callback
functions, please see :ref:`events`. functions, please see :ref:`events`.
Registered callbacks will be invoked on event in the order of *priority* and :param event: The name of target event
registration. The priority is ascending order. :param callback: Callback function for the event
:param priority: The priority of the callback. The callbacks will be invoked
The method returns a "listener ID" that can be used as an argument to in the order of *priority* in asending.
:meth:`disconnect`. :return: A listener ID. It can be used for :meth:`disconnect`.
.. versionchanged:: 3.0 .. versionchanged:: 3.0
@ -432,7 +437,10 @@ class Sphinx:
return listener_id return listener_id
def disconnect(self, listener_id: int) -> None: def disconnect(self, listener_id: int) -> None:
"""Unregister callback by *listener_id*.""" """Unregister callback by *listener_id*.
:param listener_id: A listener_id that :meth:`connect` returns
"""
logger.debug('[app] disconnecting event: [id=%s]', listener_id) logger.debug('[app] disconnecting event: [id=%s]', listener_id)
self.events.disconnect(listener_id) self.events.disconnect(listener_id)
@ -443,6 +451,10 @@ class Sphinx:
Return the return values of all callbacks as a list. Do not emit core Return the return values of all callbacks as a list. Do not emit core
Sphinx events in extensions! Sphinx events in extensions!
:param event: The name of event that will be emitted
:param args: The arguments for the event
:param allowed_exceptions: The list of exceptions that are allowed in the callbacks
.. versionchanged:: 3.1 .. versionchanged:: 3.1
Added *allowed_exceptions* to specify path-through exceptions Added *allowed_exceptions* to specify path-through exceptions
@ -455,6 +467,10 @@ class Sphinx:
Return the result of the first callback that doesn't return ``None``. Return the result of the first callback that doesn't return ``None``.
:param event: The name of event that will be emitted
:param args: The arguments for the event
:param allowed_exceptions: The list of exceptions that are allowed in the callbacks
.. versionadded:: 0.5 .. versionadded:: 0.5
.. versionchanged:: 3.1 .. versionchanged:: 3.1
@ -468,8 +484,9 @@ class Sphinx:
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. """Register a new builder.
*builder* must be a class that inherits from :param builder: A builder class
:class:`~sphinx.builders.Builder`. :param override: If true, install the builder forcedly even if another builder
is already installed as the same name
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -493,6 +510,10 @@ class Sphinx:
documents. documents.
* ``''`` if a change in the setting will not need any special rebuild. * ``''`` if a change in the setting will not need any special rebuild.
The *types* value takes a list of types that describes the type of
configuration value. For example, ``[str]`` is used to describe a
configuration that takes string value.
.. versionchanged:: 0.6 .. versionchanged:: 0.6
Changed *rebuild* from a simple boolean (equivalent to ``''`` or Changed *rebuild* from a simple boolean (equivalent to ``''`` or
``'env'``) to a string. However, booleans are still accepted and ``'env'``) to a string. However, booleans are still accepted and
@ -526,6 +547,11 @@ class Sphinx:
builtin translator. This allows extensions to use custom translator builtin translator. This allows extensions to use custom translator
and define custom nodes for the translator (see :meth:`add_node`). and define custom nodes for the translator (see :meth:`add_node`).
:param name: The name of builder for the translator
:param translator_class: A translator class
:param override: If true, install the translator forcedly even if another translator
is already installed as the same name
.. versionadded:: 1.3 .. versionadded:: 1.3
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -560,6 +586,9 @@ class Sphinx:
Obviously, translators for which you don't specify visitor methods will Obviously, translators for which you don't specify visitor methods will
choke on the node when encountered in a document to translate. choke on the node when encountered in a document to translate.
If *override* is True, the given *node* is forcedly installed even if
a node having the same name is already installed.
.. versionchanged:: 0.5 .. versionchanged:: 0.5
Added the support for keyword arguments giving visit functions. Added the support for keyword arguments giving visit functions.
""" """
@ -595,6 +624,9 @@ class Sphinx:
Other keyword arguments are used for node visitor functions. See the Other keyword arguments are used for node visitor functions. See the
:meth:`.Sphinx.add_node` for details. :meth:`.Sphinx.add_node` for details.
If *override* is True, the given *node* is forcedly installed even if
a node having the same name is already installed.
.. versionadded:: 1.4 .. versionadded:: 1.4
""" """
self.registry.add_enumerable_node(node, figtype, title_getter, override=override) self.registry.add_enumerable_node(node, figtype, title_getter, override=override)
@ -603,19 +635,19 @@ class Sphinx:
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. """Register a Docutils directive.
*name* must be the prospective directive name. *cls* is a directive :param name: The name of directive
class which inherits ``docutils.parsers.rst.Directive``. For more :param cls: A directive class
details, see `the Docutils docs :param override: If true, install the directive forcedly even if another directive
<http://docutils.sourceforge.net/docs/howto/rst-directives.html>`_ . is already installed as the same name
For example, the (already existing) :rst:dir:`literalinclude` directive For example, a custom directive named ``my-directive`` would be added
would be added like this: like this:
.. code-block:: python .. code-block:: python
from docutils.parsers.rst import Directive, directives from docutils.parsers.rst import Directive, directives
class LiteralIncludeDirective(Directive): class MyDirective(Directive):
has_content = True has_content = True
required_arguments = 1 required_arguments = 1
optional_arguments = 0 optional_arguments = 0
@ -628,7 +660,11 @@ class Sphinx:
def run(self): def run(self):
... ...
add_directive('literalinclude', LiteralIncludeDirective) def setup(app):
add_directive('my-directive', MyDirective)
For more details, see `the Docutils docs
<http://docutils.sourceforge.net/docs/howto/rst-directives.html>`__ .
.. versionchanged:: 0.6 .. versionchanged:: 0.6
Docutils 0.5-style directive classes are now supported. Docutils 0.5-style directive classes are now supported.
@ -647,10 +683,13 @@ class Sphinx:
def add_role(self, name: str, role: Any, override: bool = False) -> None: def add_role(self, name: str, role: Any, override: bool = False) -> None:
"""Register a Docutils role. """Register a Docutils role.
*name* must be the role name that occurs in the source, *role* the role :param name: The name of role
function. Refer to the `Docutils documentation :param cls: A role function
<http://docutils.sourceforge.net/docs/howto/rst-roles.html>`_ for :param override: If true, install the role forcedly even if another role is already
more information. installed as the same name
For more details about role functions, see `the Docutils docs
<http://docutils.sourceforge.net/docs/howto/rst-roles.html>`__ .
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -667,6 +706,9 @@ class Sphinx:
Register a Docutils role that does nothing but wrap its contents in the Register a Docutils role that does nothing but wrap its contents in the
node given by *nodeclass*. node given by *nodeclass*.
If *override* is True, the given *nodeclass* is forcedly installed even if
a role named as *name* is already installed.
.. versionadded:: 0.6 .. versionadded:: 0.6
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -686,6 +728,9 @@ class Sphinx:
Make the given *domain* (which must be a class; more precisely, a Make the given *domain* (which must be a class; more precisely, a
subclass of :class:`~sphinx.domains.Domain`) known to Sphinx. subclass of :class:`~sphinx.domains.Domain`) known to Sphinx.
If *override* is True, the given *domain* is forcedly installed even if
a domain having the same name is already installed.
.. versionadded:: 1.0 .. versionadded:: 1.0
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -699,6 +744,9 @@ class Sphinx:
Like :meth:`add_directive`, but the directive is added to the domain Like :meth:`add_directive`, but the directive is added to the domain
named *domain*. named *domain*.
If *override* is True, the given *directive* is forcedly installed even if
a directive named as *name* is already installed.
.. versionadded:: 1.0 .. versionadded:: 1.0
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -712,6 +760,9 @@ class Sphinx:
Like :meth:`add_role`, but the role is added to the domain named Like :meth:`add_role`, but the role is added to the domain named
*domain*. *domain*.
If *override* is True, the given *role* is forcedly installed even if
a role named as *name* is already installed.
.. versionadded:: 1.0 .. versionadded:: 1.0
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -725,6 +776,9 @@ class Sphinx:
Add a custom *index* class to the domain named *domain*. *index* must Add a custom *index* class to the domain named *domain*. *index* must
be a subclass of :class:`~sphinx.domains.Index`. be a subclass of :class:`~sphinx.domains.Index`.
If *override* is True, the given *index* is forcedly installed even if
an index having the same name is already installed.
.. versionadded:: 1.0 .. versionadded:: 1.0
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
@ -788,6 +842,9 @@ class Sphinx:
For the role content, you have the same syntactical possibilities as For the role content, you have the same syntactical possibilities as
for standard Sphinx roles (see :ref:`xref-syntax`). for standard Sphinx roles (see :ref:`xref-syntax`).
If *override* is True, the given object_type is forcedly installed even if
an object_type having the same name is already installed.
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
""" """
@ -824,6 +881,9 @@ class Sphinx:
(Of course, the element following the ``topic`` directive needn't be a (Of course, the element following the ``topic`` directive needn't be a
section.) section.)
If *override* is True, the given crossref_type is forcedly installed even if
a crossref_type having the same name is already installed.
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
""" """
@ -873,22 +933,24 @@ class Sphinx:
""" """
self.registry.add_post_transform(transform) self.registry.add_post_transform(transform)
def add_javascript(self, filename: str, **kwargs: str) -> None: def add_javascript(self, filename: str, **kwargs: Any) -> None:
"""An alias of :meth:`add_js_file`.""" """An alias of :meth:`add_js_file`."""
warnings.warn('The app.add_javascript() is deprecated. ' warnings.warn('The app.add_javascript() is deprecated. '
'Please use app.add_js_file() instead.', 'Please use app.add_js_file() instead.',
RemovedInSphinx40Warning, stacklevel=2) RemovedInSphinx40Warning, stacklevel=2)
self.add_js_file(filename, **kwargs) self.add_js_file(filename, **kwargs)
def add_js_file(self, filename: str, **kwargs: str) -> None: def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None:
"""Register a JavaScript file to include in the HTML output. """Register a JavaScript file to include in the HTML output.
Add *filename* to the list of JavaScript files that the default HTML Add *filename* to the list of JavaScript files that the default HTML
template will include. The filename must be relative to the HTML template will include in order of *priority* (ascending). The filename
static path , or a full URI with scheme. If the keyword argument must be relative to the HTML static path , or a full URI with scheme.
``body`` is given, its value will be added between the If the priority of JavaScript file is the same as others, the JavaScript
``<script>`` tags. Extra keyword arguments are included as files will be included in order of the registration. If the keyword
attributes of the ``<script>`` tag. argument ``body`` is given, its value will be added between the
``<script>`` tags. Extra keyword arguments are included as attributes of
the ``<script>`` tag.
Example:: Example::
@ -901,23 +963,43 @@ class Sphinx:
app.add_js_file(None, body="var myVariable = 'foo';") app.add_js_file(None, body="var myVariable = 'foo';")
# => <script>var myVariable = 'foo';</script> # => <script>var myVariable = 'foo';</script>
.. list-table:: priority range for JavaScript files
:widths: 20,80
* - Priority
- Main purpose in Sphinx
* - 200
- default priority for built-in JavaScript files
* - 500
- default priority for extensions
* - 800
- default priority for :confval:`html_js_files`
A JavaScript file can be added to the specific HTML page when on extension
calls this method on :event:`html-page-context` event.
.. versionadded:: 0.5 .. versionadded:: 0.5
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Renamed from ``app.add_javascript()``. Renamed from ``app.add_javascript()``.
And it allows keyword arguments as attributes of script tag. And it allows keyword arguments as attributes of script tag.
"""
self.registry.add_js_file(filename, **kwargs)
if hasattr(self.builder, 'add_js_file'):
self.builder.add_js_file(filename, **kwargs) # type: ignore
def add_css_file(self, filename: str, **kwargs: str) -> None: .. versionchanged:: 3.5
Take priority argument. Allow to add a JavaScript file to the specific page.
"""
self.registry.add_js_file(filename, priority=priority, **kwargs)
if hasattr(self.builder, 'add_js_file'):
self.builder.add_js_file(filename, priority=priority, **kwargs) # type: ignore
def add_css_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None:
"""Register a stylesheet to include in the HTML output. """Register a stylesheet to include in the HTML output.
Add *filename* to the list of CSS files that the default HTML template Add *filename* to the list of CSS files that the default HTML template
will include. The filename must be relative to the HTML static path, will include in order of *priority* (ascending). The filename must be
or a full URI with scheme. The keyword arguments are also accepted for relative to the HTML static path, or a full URI with scheme. If the
attributes of ``<link>`` tag. priority of CSS file is the same as others, the CSS files will be
included in order of the registration. The keyword arguments are also
accepted for attributes of ``<link>`` tag.
Example:: Example::
@ -932,6 +1014,19 @@ class Sphinx:
# => <link rel="alternate stylesheet" href="_static/fancy.css" # => <link rel="alternate stylesheet" href="_static/fancy.css"
# type="text/css" title="fancy" /> # type="text/css" title="fancy" />
.. list-table:: priority range for CSS files
:widths: 20,80
* - Priority
- Main purpose in Sphinx
* - 500
- default priority for extensions
* - 800
- default priority for :confval:`html_css_files`
A CSS file can be added to the specific HTML page when on extension calls
this method on :event:`html-page-context` event.
.. versionadded:: 1.0 .. versionadded:: 1.0
.. versionchanged:: 1.6 .. versionchanged:: 1.6
@ -944,11 +1039,14 @@ class Sphinx:
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Renamed from ``app.add_stylesheet()``. Renamed from ``app.add_stylesheet()``.
And it allows keyword arguments as attributes of link tag. And it allows keyword arguments as attributes of link tag.
.. versionchanged:: 3.5
Take priority argument. Allow to add a CSS file to the specific page.
""" """
logger.debug('[app] adding stylesheet: %r', filename) logger.debug('[app] adding stylesheet: %r', filename)
self.registry.add_css_files(filename, **kwargs) self.registry.add_css_files(filename, priority=priority, **kwargs)
if hasattr(self.builder, 'add_css_file'): if hasattr(self.builder, 'add_css_file'):
self.builder.add_css_file(filename, **kwargs) # type: ignore self.builder.add_css_file(filename, priority=priority, **kwargs) # type: ignore
def add_stylesheet(self, filename: str, alternate: bool = False, title: str = None def add_stylesheet(self, filename: str, alternate: bool = False, title: str = None
) -> None: ) -> None:
@ -957,7 +1055,7 @@ class Sphinx:
'Please use app.add_css_file() instead.', 'Please use app.add_css_file() instead.',
RemovedInSphinx40Warning, stacklevel=2) RemovedInSphinx40Warning, stacklevel=2)
attributes = {} # type: Dict[str, str] attributes = {} # type: Dict[str, Any]
if alternate: if alternate:
attributes['rel'] = 'alternate stylesheet' attributes['rel'] = 'alternate stylesheet'
else: else:
@ -1004,7 +1102,7 @@ class Sphinx:
logger.debug('[app] adding lexer: %r', (alias, lexer)) logger.debug('[app] adding lexer: %r', (alias, lexer))
if isinstance(lexer, Lexer): if isinstance(lexer, Lexer):
warnings.warn('app.add_lexer() API changed; ' warnings.warn('app.add_lexer() API changed; '
'Please give lexer class instead instance', 'Please give lexer class instead of instance',
RemovedInSphinx40Warning, stacklevel=2) RemovedInSphinx40Warning, stacklevel=2)
lexers[alias] = lexer lexers[alias] = lexer
else: else:
@ -1019,6 +1117,9 @@ class Sphinx:
new types of objects. See the source of the autodoc module for new types of objects. See the source of the autodoc module for
examples on how to subclass :class:`Documenter`. examples on how to subclass :class:`Documenter`.
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 .. todo:: Add real docs for Documenter and subclassing
.. versionadded:: 0.6 .. versionadded:: 0.6
@ -1057,7 +1158,7 @@ class Sphinx:
.. versionadded:: 1.1 .. versionadded:: 1.1
""" """
logger.debug('[app] adding search language: %r', cls) logger.debug('[app] adding search language: %r', cls)
from sphinx.search import languages, SearchLanguage from sphinx.search import SearchLanguage, languages
assert issubclass(cls, SearchLanguage) assert issubclass(cls, SearchLanguage)
languages[cls.lang] = cls languages[cls.lang] = cls
@ -1067,13 +1168,19 @@ class Sphinx:
Same as :confval:`source_suffix`. The users can override this Same as :confval:`source_suffix`. The users can override this
using the setting. using the setting.
If *override* is True, the given *suffix* is forcedly installed even if
a same suffix is already installed.
.. versionadded:: 1.8 .. versionadded:: 1.8
""" """
self.registry.add_source_suffix(suffix, filetype, override=override) self.registry.add_source_suffix(suffix, filetype, override=override)
def add_source_parser(self, *args: Any, **kwargs: Any) -> None: def add_source_parser(self, parser: "Type[Parser]", override: bool = False) -> None:
"""Register a parser class. """Register a parser class.
If *override* is True, the given *parser* is forcedly installed even if
a parser for the same suffix is already installed.
.. versionadded:: 1.4 .. versionadded:: 1.4
.. versionchanged:: 1.8 .. versionchanged:: 1.8
*suffix* argument is deprecated. It only accepts *parser* argument. *suffix* argument is deprecated. It only accepts *parser* argument.
@ -1081,7 +1188,7 @@ class Sphinx:
.. versionchanged:: 1.8 .. versionchanged:: 1.8
Add *override* keyword. Add *override* keyword.
""" """
self.registry.add_source_parser(*args, **kwargs) 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. """Register an environment collector class.

View File

@ -4,7 +4,7 @@
Builder superclass for all builders. Builder superclass for all builders.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -17,26 +17,24 @@ from docutils import nodes
from docutils.nodes import Node from docutils.nodes import Node
from sphinx.config import Config from sphinx.config import Config
from sphinx.environment import BuildEnvironment, CONFIG_OK, CONFIG_CHANGED_REASON from sphinx.environment import CONFIG_CHANGED_REASON, CONFIG_OK, BuildEnvironment
from sphinx.environment.adapters.asset import ImageAdapter from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.events import EventManager from sphinx.events import EventManager
from sphinx.io import read_doc from sphinx.io import read_doc
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import import_object, logging, rst, progress_message, status_iterator from sphinx.util import import_object, logging, progress_message, rst, status_iterator
from sphinx.util.build_phase import BuildPhase from sphinx.util.build_phase import BuildPhase
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.docutils import sphinx_domains from sphinx.util.docutils import sphinx_domains
from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain
from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \ from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available
parallel_available
from sphinx.util.tags import Tags from sphinx.util.tags import Tags
# side effect: registers roles and directives # side effect: registers roles and directives
from sphinx import roles # noqa from sphinx import directives # NOQA isort:skip
from sphinx import directives # noqa from sphinx import roles # NOQA isort:skip
try: try:
import multiprocessing import multiprocessing
except ImportError: except ImportError:
@ -45,6 +43,7 @@ except ImportError:
if False: if False:
# For type annotation # For type annotation
from typing import Type # for python3.5.1 from typing import Type # for python3.5.1
from sphinx.application import Sphinx from sphinx.application import Sphinx

View File

@ -4,7 +4,7 @@
Base class of epub2/epub3 builders. Base class of epub2/epub3 builders.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -25,11 +25,10 @@ from sphinx import addnodes
from sphinx.builders.html import BuildInfo, StandaloneHTMLBuilder from sphinx.builders.html import BuildInfo, StandaloneHTMLBuilder
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging, status_iterator
from sphinx.util import status_iterator
from sphinx.util.fileutil import copy_asset_file from sphinx.util.fileutil import copy_asset_file
from sphinx.util.i18n import format_date from sphinx.util.i18n import format_date
from sphinx.util.osutil import ensuredir, copyfile from sphinx.util.osutil import copyfile, ensuredir
try: try:
from PIL import Image from PIL import Image
@ -208,7 +207,12 @@ class EpubBuilder(StandaloneHTMLBuilder):
appeared = set() # type: Set[str] appeared = set() # type: Set[str]
for node in nodes: for node in nodes:
if node['refuri'] in appeared: if node['refuri'] in appeared:
logger.warning(__('duplicated ToC entry found: %s'), node['refuri']) logger.warning(
__('duplicated ToC entry found: %s'),
node['refuri'],
type="epub",
subtype="duplicated_toc_entry",
)
else: else:
appeared.add(node['refuri']) appeared.add(node['refuri'])
@ -388,7 +392,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
return ext in VECTOR_GRAPHICS_EXTENSIONS return ext in VECTOR_GRAPHICS_EXTENSIONS
def copy_image_files_pil(self) -> None: def copy_image_files_pil(self) -> None:
"""Copy images using Pillow, the Python Imaging Libary. """Copy images using Pillow, the Python Imaging Library.
The method tries to read and write the files with Pillow, converting The method tries to read and write the files with Pillow, converting
the format and resizing the image if necessary/possible. the format and resizing the image if necessary/possible.
""" """

View File

@ -4,30 +4,33 @@
Build Apple help books. Build Apple help books.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import warnings import warnings
from typing import Any, Dict from typing import Any, Dict
from sphinxcontrib.applehelp import ( from sphinxcontrib.applehelp import (AppleHelpBuilder, AppleHelpCodeSigningFailed,
AppleHelpCodeSigningFailed, AppleHelpIndexerFailed)
AppleHelpIndexerFailed,
AppleHelpBuilder,
)
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
deprecated_alias('sphinx.builders.applehelp', deprecated_alias('sphinx.builders.applehelp',
{ {
'AppleHelpCodeSigningFailed': AppleHelpCodeSigningFailed, 'AppleHelpCodeSigningFailed': AppleHelpCodeSigningFailed,
'AppleHelpIndexerFailed': AppleHelpIndexerFailed, 'AppleHelpIndexerFailed': AppleHelpIndexerFailed,
'AppleHelpBuilder': AppleHelpBuilder, 'AppleHelpBuilder': AppleHelpBuilder,
}, },
RemovedInSphinx40Warning) RemovedInSphinx40Warning,
{
'AppleHelpCodeSigningFailed':
'sphinxcontrib.applehelp.AppleHelpCodeSigningFailed',
'AppleHelpIndexerFailed':
'sphinxcontrib.applehelp.AppleHelpIndexerFailed',
'AppleHelpBuilder': 'sphinxcontrib.applehelp.AppleHelpBuilder',
})
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:

View File

@ -4,14 +4,13 @@
Changelog builder. Changelog builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import html import html
from os import path from os import path
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple, cast
from typing import cast
from sphinx import package_dir from sphinx import package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
@ -24,7 +23,6 @@ from sphinx.util.console import bold # type: ignore
from sphinx.util.fileutil import copy_asset_file from sphinx.util.fileutil import copy_asset_file
from sphinx.util.osutil import ensuredir, os_path from sphinx.util.osutil import ensuredir, os_path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -6,7 +6,7 @@
.. _Devhelp: https://wiki.gnome.org/Apps/Devhelp .. _Devhelp: https://wiki.gnome.org/Apps/Devhelp
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -18,12 +18,14 @@ from sphinxcontrib.devhelp import DevhelpBuilder
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
deprecated_alias('sphinx.builders.devhelp', deprecated_alias('sphinx.builders.devhelp',
{ {
'DevhelpBuilder': DevhelpBuilder, 'DevhelpBuilder': DevhelpBuilder,
}, },
RemovedInSphinx40Warning) RemovedInSphinx40Warning,
{
'DevhelpBuilder': 'sphinxcontrib.devhelp.DevhelpBuilder'
})
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:

View File

@ -4,7 +4,7 @@
Directory HTML builders. Directory HTML builders.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -49,9 +49,12 @@ class DirectoryHTMLBuilder(StandaloneHTMLBuilder):
# for compatibility # for compatibility
deprecated_alias('sphinx.builders.html', deprecated_alias('sphinx.builders.html',
{ {
'DirectoryHTMLBuilder': DirectoryHTMLBuilder, 'DirectoryHTMLBuilder': DirectoryHTMLBuilder,
}, },
RemovedInSphinx40Warning) RemovedInSphinx40Warning,
{
'DirectoryHTMLBuilder': 'sphinx.builders.dirhtml.DirectoryHTMLBuilder',
})
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:

View File

@ -4,7 +4,7 @@
Do syntax checks, but no writing. Do syntax checks, but no writing.
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """

View File

@ -5,7 +5,7 @@
Build epub3 files. Build epub3 files.
Originally derived from epub.py. Originally derived from epub.py.
:copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -18,7 +18,7 @@ from typing import Any, Dict, List, Set, Tuple
from sphinx import package_dir from sphinx import package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import _epub_base from sphinx.builders import _epub_base
from sphinx.config import Config, ENUM from sphinx.config import ENUM, Config
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging, xmlname_checker from sphinx.util import logging, xmlname_checker

View File

@ -4,33 +4,32 @@
The MessageCatalogBuilder class. The MessageCatalogBuilder class.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from codecs import open from codecs import open
from collections import defaultdict, OrderedDict from collections import OrderedDict, defaultdict
from datetime import datetime, tzinfo, timedelta from datetime import datetime, timedelta, tzinfo
from os import path, walk, getenv from os import getenv, path, walk
from time import time from time import time
from typing import Any, Dict, Iterable, Generator, List, Set, Tuple, Union from typing import Any, Dict, Generator, Iterable, List, Set, Tuple, Union
from uuid import uuid4 from uuid import uuid4
from docutils import nodes from docutils import nodes
from docutils.nodes import Element from docutils.nodes import Element
from sphinx import addnodes from sphinx import addnodes, package_dir
from sphinx import package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.domains.python import pairindextypes from sphinx.domains.python import pairindextypes
from sphinx.errors import ThemeError from sphinx.errors import ThemeError
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import split_index_msg, logging, status_iterator from sphinx.util import logging, split_index_msg, status_iterator
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
from sphinx.util.i18n import CatalogInfo, docname_to_domain from sphinx.util.i18n import CatalogInfo, docname_to_domain
from sphinx.util.nodes import extract_messages, traverse_translatable_index from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.osutil import ensuredir, canon_path, relpath from sphinx.util.osutil import canon_path, ensuredir, relpath
from sphinx.util.tags import Tags from sphinx.util.tags import Tags
from sphinx.util.template import SphinxRenderer from sphinx.util.template import SphinxRenderer
@ -278,7 +277,7 @@ class MessageCatalogBuilder(I18nBuilder):
origin = MsgOrigin(template, line) origin = MsgOrigin(template, line)
self.catalogs['sphinx'].add(msg, origin) self.catalogs['sphinx'].add(msg, origin)
except Exception as exc: except Exception as exc:
raise ThemeError('%s: %r' % (template, exc)) raise ThemeError('%s: %r' % (template, exc)) from exc
def build(self, docnames: Iterable[str], summary: str = None, method: str = 'update') -> None: # NOQA def build(self, docnames: Iterable[str], summary: str = None, method: str = 'update') -> None: # NOQA
self._extract_from_template() self._extract_from_template()
@ -316,7 +315,7 @@ class MessageCatalogBuilder(I18nBuilder):
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:
app.add_builder(MessageCatalogBuilder) app.add_builder(MessageCatalogBuilder)
app.add_config_value('gettext_compact', True, 'gettext') app.add_config_value('gettext_compact', True, 'gettext', {bool, str})
app.add_config_value('gettext_location', True, 'gettext') app.add_config_value('gettext_location', True, 'gettext')
app.add_config_value('gettext_uuid', False, 'gettext') app.add_config_value('gettext_uuid', False, 'gettext')
app.add_config_value('gettext_auto_build', True, 'env') app.add_config_value('gettext_auto_build', True, 'env')

View File

@ -4,17 +4,19 @@
Several HTML builders. Several HTML builders.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import html import html
import os
import posixpath import posixpath
import re import re
import sys import sys
import warnings import warnings
from os import path from os import path
from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Tuple from typing import IO, Any, Dict, Iterable, Iterator, List, Set, Tuple
from urllib.parse import quote
from docutils import nodes from docutils import nodes
from docutils.core import publish_parts from docutils.core import publish_parts
@ -23,10 +25,10 @@ from docutils.io import DocTreeInput, StringOutput
from docutils.nodes import Node from docutils.nodes import Node
from docutils.utils import relative_path from docutils.utils import relative_path
from sphinx import package_dir, __display_version__ from sphinx import __display_version__, package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.config import Config from sphinx.config import ENUM, Config
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.domains import Domain, Index, IndexEntry from sphinx.domains import Domain, Index, IndexEntry
from sphinx.environment.adapters.asset import ImageAdapter from sphinx.environment.adapters.asset import ImageAdapter
@ -37,15 +39,15 @@ from sphinx.highlighting import PygmentsBridge
from sphinx.locale import _, __ from sphinx.locale import _, __
from sphinx.search import js_index from sphinx.search import js_index
from sphinx.theming import HTMLThemeFactory from sphinx.theming import HTMLThemeFactory
from sphinx.util import logging, progress_message, status_iterator, md5 from sphinx.util import logging, md5, progress_message, status_iterator
from sphinx.util.docutils import is_html5_writer_available, new_document from sphinx.util.docutils import is_html5_writer_available, new_document
from sphinx.util.fileutil import copy_asset from sphinx.util.fileutil import copy_asset
from sphinx.util.i18n import format_date from sphinx.util.i18n import format_date
from sphinx.util.inventory import InventoryFile from sphinx.util.inventory import InventoryFile
from sphinx.util.matching import patmatch, Matcher, DOTFILES from sphinx.util.matching import DOTFILES, Matcher, patmatch
from sphinx.util.osutil import os_path, relative_uri, ensuredir, movefile, copyfile from sphinx.util.osutil import copyfile, ensuredir, os_path, relative_uri
from sphinx.util.tags import Tags from sphinx.util.tags import Tags
from sphinx.writers.html import HTMLWriter, HTMLTranslator from sphinx.writers.html import HTMLTranslator, HTMLWriter
if False: if False:
# For type annotation # For type annotation
@ -88,10 +90,13 @@ class Stylesheet(str):
attributes = None # type: Dict[str, str] attributes = None # type: Dict[str, str]
filename = None # type: str filename = None # type: str
priority = None # type: int
def __new__(cls, filename: str, *args: str, **attributes: str) -> "Stylesheet": def __new__(cls, filename: str, *args: str, priority: int = 500, **attributes: Any
self = str.__new__(cls, filename) # type: ignore ) -> "Stylesheet":
self = str.__new__(cls, filename)
self.filename = filename self.filename = filename
self.priority = priority
self.attributes = attributes self.attributes = attributes
self.attributes.setdefault('rel', 'stylesheet') self.attributes.setdefault('rel', 'stylesheet')
self.attributes.setdefault('type', 'text/css') self.attributes.setdefault('type', 'text/css')
@ -111,10 +116,12 @@ class JavaScript(str):
attributes = None # type: Dict[str, str] attributes = None # type: Dict[str, str]
filename = None # type: str filename = None # type: str
priority = None # type: int
def __new__(cls, filename: str, **attributes: str) -> "JavaScript": def __new__(cls, filename: str, priority: int = 500, **attributes: str) -> "JavaScript":
self = str.__new__(cls, filename) # type: ignore self = str.__new__(cls, filename)
self.filename = filename self.filename = filename
self.priority = priority
self.attributes = attributes self.attributes = attributes
return self return self
@ -140,7 +147,7 @@ class BuildInfo:
build_info.tags_hash = lines[3].split()[1].strip() build_info.tags_hash = lines[3].split()[1].strip()
return build_info return build_info
except Exception as exc: except Exception as exc:
raise ValueError(__('build info file is broken: %r') % exc) raise ValueError(__('build info file is broken: %r') % exc) from exc
def __init__(self, config: Config = None, tags: Tags = None, config_categories: List[str] = []) -> None: # NOQA def __init__(self, config: Config = None, tags: Tags = None, config_categories: List[str] = []) -> None: # NOQA
self.config_hash = '' self.config_hash = ''
@ -288,30 +295,31 @@ class StandaloneHTMLBuilder(Builder):
self.add_css_file(filename, **attrs) self.add_css_file(filename, **attrs)
for filename, attrs in self.get_builder_config('css_files', 'html'): for filename, attrs in self.get_builder_config('css_files', 'html'):
attrs.setdefault('priority', 800) # User's CSSs are loaded after extensions'
self.add_css_file(filename, **attrs) self.add_css_file(filename, **attrs)
def add_css_file(self, filename: str, **kwargs: str) -> None: def add_css_file(self, filename: str, **kwargs: Any) -> None:
if '://' not in filename: if '://' not in filename:
filename = posixpath.join('_static', filename) filename = posixpath.join('_static', filename)
self.css_files.append(Stylesheet(filename, **kwargs)) # type: ignore self.css_files.append(Stylesheet(filename, **kwargs)) # type: ignore
def init_js_files(self) -> None: def init_js_files(self) -> None:
self.add_js_file('jquery.js') self.add_js_file('jquery.js', priority=200)
self.add_js_file('underscore.js') self.add_js_file('underscore.js', priority=200)
self.add_js_file('doctools.js') self.add_js_file('doctools.js', priority=200)
self.add_js_file('language_data.js')
for filename, attrs in self.app.registry.js_files: for filename, attrs in self.app.registry.js_files:
self.add_js_file(filename, **attrs) self.add_js_file(filename, **attrs)
for filename, attrs in self.get_builder_config('js_files', 'html'): for filename, attrs in self.get_builder_config('js_files', 'html'):
attrs.setdefault('priority', 800) # User's JSs are loaded after extensions'
self.add_js_file(filename, **attrs) self.add_js_file(filename, **attrs)
if self.config.language and self._get_translations_js(): if self.config.language and self._get_translations_js():
self.add_js_file('translations.js') self.add_js_file('translations.js')
def add_js_file(self, filename: str, **kwargs: str) -> None: def add_js_file(self, filename: str, **kwargs: Any) -> None:
if filename and '://' not in filename: if filename and '://' not in filename:
filename = posixpath.join('_static', filename) filename = posixpath.join('_static', filename)
@ -447,9 +455,6 @@ class StandaloneHTMLBuilder(Builder):
logo = path.basename(self.config.html_logo) if self.config.html_logo else '' logo = path.basename(self.config.html_logo) if self.config.html_logo else ''
favicon = path.basename(self.config.html_favicon) if self.config.html_favicon else '' favicon = path.basename(self.config.html_favicon) if self.config.html_favicon else ''
if not isinstance(self.config.html_use_opensearch, str):
logger.warning(__('html_use_opensearch config value must now be a string'))
self.relations = self.env.collect_relations() self.relations = self.env.collect_relations()
rellinks = [] # type: List[Tuple[str, str, str, str]] rellinks = [] # type: List[Tuple[str, str, str, str]]
@ -461,6 +466,10 @@ class StandaloneHTMLBuilder(Builder):
rellinks.append((indexname, indexcls.localname, rellinks.append((indexname, indexcls.localname,
'', indexcls.shortname)) '', indexcls.shortname))
# back up script_files and css_files to allow adding JS/CSS files to a specific page.
self._script_files = list(self.script_files)
self._css_files = list(self.css_files)
if self.config.html_style is not None: if self.config.html_style is not None:
stylename = self.config.html_style stylename = self.config.html_style
elif self.theme: elif self.theme:
@ -640,17 +649,17 @@ class StandaloneHTMLBuilder(Builder):
def gen_additional_pages(self) -> None: def gen_additional_pages(self) -> None:
# additional pages from conf.py # additional pages from conf.py
for pagename, template in self.config.html_additional_pages.items(): for pagename, template in self.config.html_additional_pages.items():
logger.info(' ' + pagename, nonl=True) logger.info(pagename + ' ', nonl=True)
self.handle_page(pagename, {}, template) self.handle_page(pagename, {}, template)
# the search page # the search page
if self.search: if self.search:
logger.info(' search', nonl=True) logger.info('search ', nonl=True)
self.handle_page('search', {}, 'search.html') self.handle_page('search', {}, 'search.html')
# the opensearch xml file # the opensearch xml file
if self.config.html_use_opensearch and self.search: if self.config.html_use_opensearch and self.search:
logger.info(' opensearch', nonl=True) logger.info('opensearch ', nonl=True)
fn = path.join(self.outdir, '_static', 'opensearch.xml') fn = path.join(self.outdir, '_static', 'opensearch.xml')
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn) self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
@ -668,7 +677,7 @@ class StandaloneHTMLBuilder(Builder):
'genindexcounts': indexcounts, 'genindexcounts': indexcounts,
'split_index': self.config.html_split_index, 'split_index': self.config.html_split_index,
} }
logger.info(' genindex', nonl=True) logger.info('genindex ', nonl=True)
if self.config.html_split_index: if self.config.html_split_index:
self.handle_page('genindex', genindexcontext, self.handle_page('genindex', genindexcontext,
@ -690,7 +699,7 @@ class StandaloneHTMLBuilder(Builder):
'content': content, 'content': content,
'collapse_index': collapse, 'collapse_index': collapse,
} }
logger.info(' ' + indexname, nonl=True) logger.info(indexname + ' ', nonl=True)
self.handle_page(indexname, indexcontext, 'domainindex.html') self.handle_page(indexname, indexcontext, 'domainindex.html')
def copy_image_files(self) -> None: def copy_image_files(self) -> None:
@ -750,18 +759,27 @@ class StandaloneHTMLBuilder(Builder):
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js')) copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
def copy_theme_static_files(self, context: Dict) -> None: def copy_theme_static_files(self, context: Dict) -> None:
def onerror(filename: str, error: Exception) -> None:
logger.warning(__('Failed to copy a file in html_static_file: %s: %r'),
filename, error)
if self.theme: if self.theme:
for entry in self.theme.get_theme_dirs()[::-1]: for entry in self.theme.get_theme_dirs()[::-1]:
copy_asset(path.join(entry, 'static'), copy_asset(path.join(entry, 'static'),
path.join(self.outdir, '_static'), path.join(self.outdir, '_static'),
excluded=DOTFILES, context=context, renderer=self.templates) excluded=DOTFILES, context=context,
renderer=self.templates, onerror=onerror)
def copy_html_static_files(self, context: Dict) -> None: def copy_html_static_files(self, context: Dict) -> None:
def onerror(filename: str, error: Exception) -> None:
logger.warning(__('Failed to copy a file in html_static_file: %s: %r'),
filename, error)
excluded = Matcher(self.config.exclude_patterns + ["**/.*"]) excluded = Matcher(self.config.exclude_patterns + ["**/.*"])
for entry in self.config.html_static_path: for entry in self.config.html_static_path:
copy_asset(path.join(self.confdir, entry), copy_asset(path.join(self.confdir, entry),
path.join(self.outdir, '_static'), path.join(self.outdir, '_static'),
excluded, context=context, renderer=self.templates) excluded, context=context, renderer=self.templates, onerror=onerror)
def copy_html_logo(self) -> None: def copy_html_logo(self) -> None:
if self.config.html_logo: if self.config.html_logo:
@ -775,7 +793,7 @@ class StandaloneHTMLBuilder(Builder):
def copy_static_files(self) -> None: def copy_static_files(self) -> None:
try: try:
with progress_message(__('copying static files... ')): with progress_message(__('copying static files')):
ensuredir(path.join(self.outdir, '_static')) ensuredir(path.join(self.outdir, '_static'))
# prepare context for templates # prepare context for templates
@ -886,6 +904,8 @@ class StandaloneHTMLBuilder(Builder):
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str: def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str:
if 'includehidden' not in kwargs: if 'includehidden' not in kwargs:
kwargs['includehidden'] = False kwargs['includehidden'] = False
if kwargs.get('maxdepth') == '':
kwargs.pop('maxdepth')
return self.render_partial(TocTree(self.env).get_toctree_for( return self.render_partial(TocTree(self.env).get_toctree_for(
docname, self, collapse, **kwargs))['fragment'] docname, self, collapse, **kwargs))['fragment']
@ -945,7 +965,7 @@ class StandaloneHTMLBuilder(Builder):
# --------- these are overwritten by the serialization builder # --------- these are overwritten by the serialization builder
def get_target_uri(self, docname: str, typ: str = None) -> str: def get_target_uri(self, docname: str, typ: str = None) -> str:
return docname + self.link_suffix return quote(docname) + self.link_suffix
def handle_page(self, pagename: str, addctx: Dict, templatename: str = 'page.html', def handle_page(self, pagename: str, addctx: Dict, templatename: str = 'page.html',
outfilename: str = None, event_arg: Any = None) -> None: outfilename: str = None, event_arg: Any = None) -> None:
@ -1000,12 +1020,20 @@ class StandaloneHTMLBuilder(Builder):
self.add_sidebars(pagename, ctx) self.add_sidebars(pagename, ctx)
ctx.update(addctx) ctx.update(addctx)
# revert script_files and css_files
self.script_files[:] = self._script_files
self.css_files[:] = self.css_files
self.update_page_context(pagename, templatename, ctx, event_arg) self.update_page_context(pagename, templatename, ctx, event_arg)
newtmpl = self.app.emit_firstresult('html-page-context', pagename, newtmpl = self.app.emit_firstresult('html-page-context', pagename,
templatename, ctx, event_arg) templatename, ctx, event_arg)
if newtmpl: if newtmpl:
templatename = newtmpl templatename = newtmpl
# sort JS/CSS before rendering HTML
ctx['script_files'].sort(key=lambda js: js.priority)
ctx['css_files'].sort(key=lambda js: js.priority)
try: try:
output = self.templates.render(templatename, ctx) output = self.templates.render(templatename, ctx)
except UnicodeError: except UnicodeError:
@ -1015,7 +1043,7 @@ class StandaloneHTMLBuilder(Builder):
return return
except Exception as exc: except Exception as exc:
raise ThemeError(__("An error happened in rendering the page %s.\nReason: %r") % raise ThemeError(__("An error happened in rendering the page %s.\nReason: %r") %
(pagename, exc)) (pagename, exc)) from exc
if not outfilename: if not outfilename:
outfilename = self.get_outfilename(pagename) outfilename = self.get_outfilename(pagename)
@ -1059,7 +1087,7 @@ class StandaloneHTMLBuilder(Builder):
else: else:
with open(searchindexfn + '.tmp', 'wb') as fb: with open(searchindexfn + '.tmp', 'wb') as fb:
self.indexer.dump(fb, self.indexer_format) self.indexer.dump(fb, self.indexer_format)
movefile(searchindexfn + '.tmp', searchindexfn) os.replace(searchindexfn + '.tmp', searchindexfn)
def convert_html_css_files(app: Sphinx, config: Config) -> None: def convert_html_css_files(app: Sphinx, config: Config) -> None:
@ -1177,10 +1205,21 @@ def validate_html_favicon(app: Sphinx, config: Config) -> None:
config.html_favicon = None # type: ignore config.html_favicon = None # type: ignore
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
# for compatibility # for compatibility
import sphinxcontrib.serializinghtml # NOQA
import sphinx.builders.dirhtml # NOQA import sphinx.builders.dirhtml # NOQA
import sphinx.builders.singlehtml # NOQA import sphinx.builders.singlehtml # NOQA
import sphinxcontrib.serializinghtml # NOQA
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:
@ -1206,7 +1245,9 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('html_sidebars', {}, 'html') app.add_config_value('html_sidebars', {}, 'html')
app.add_config_value('html_additional_pages', {}, 'html') app.add_config_value('html_additional_pages', {}, 'html')
app.add_config_value('html_domain_indices', True, 'html', [list]) app.add_config_value('html_domain_indices', True, 'html', [list])
app.add_config_value('html_add_permalinks', '', 'html') app.add_config_value('html_add_permalinks', None, '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') app.add_config_value('html_use_index', True, 'html')
app.add_config_value('html_split_index', False, 'html') app.add_config_value('html_split_index', False, 'html')
app.add_config_value('html_copy_source', True, 'html') app.add_config_value('html_copy_source', True, 'html')
@ -1226,12 +1267,19 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('html_search_scorer', '', None) app.add_config_value('html_search_scorer', '', None)
app.add_config_value('html_scaled_image_link', True, 'html') app.add_config_value('html_scaled_image_link', True, 'html')
app.add_config_value('html_baseurl', '', 'html') app.add_config_value('html_baseurl', '', 'html')
app.add_config_value('html_codeblock_linenos_style', 'table', 'html',
ENUM('table', 'inline'))
app.add_config_value('html_math_renderer', None, 'env') app.add_config_value('html_math_renderer', None, 'env')
app.add_config_value('html4_writer', False, 'html') app.add_config_value('html4_writer', False, 'html')
# events
app.add_event('html-collect-pages')
app.add_event('html-page-context')
# event handlers # event handlers
app.connect('config-inited', convert_html_css_files, priority=800) app.connect('config-inited', convert_html_css_files, priority=800)
app.connect('config-inited', convert_html_js_files, priority=800) app.connect('config-inited', convert_html_js_files, priority=800)
app.connect('config-inited', migrate_html_add_permalinks, priority=800)
app.connect('config-inited', validate_html_extra_path, priority=800) app.connect('config-inited', validate_html_extra_path, priority=800)
app.connect('config-inited', validate_html_static_path, priority=800) app.connect('config-inited', validate_html_static_path, priority=800)
app.connect('config-inited', validate_html_logo, priority=800) app.connect('config-inited', validate_html_logo, priority=800)

View File

@ -4,12 +4,12 @@
Transforms for HTML builder. Transforms for HTML builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import re import re
from typing import Any, Dict from typing import Any, Dict, List
from docutils import nodes from docutils import nodes
@ -28,7 +28,7 @@ class KeyboardTransform(SphinxPostTransform):
After:: After::
<literal class="kbd"> <literal class="kbd compound">
<literal class="kbd"> <literal class="kbd">
Control Control
- -
@ -37,18 +37,30 @@ class KeyboardTransform(SphinxPostTransform):
""" """
default_priority = 400 default_priority = 400
builders = ('html',) builders = ('html',)
pattern = re.compile(r'(-|\+|\^|\s+)') pattern = re.compile(r'(?<=.)(-|\+|\^|\s+)(?=.)')
multiwords_keys = (('caps', 'lock'),
('page' 'down'),
('page', 'up'),
('scroll' 'lock'),
('num', 'lock'),
('sys' 'rq'),
('back' 'space'))
def run(self, **kwargs: Any) -> None: def run(self, **kwargs: Any) -> None:
matcher = NodeMatcher(nodes.literal, classes=["kbd"]) matcher = NodeMatcher(nodes.literal, classes=["kbd"])
for node in self.document.traverse(matcher): # type: nodes.literal for node in self.document.traverse(matcher): # type: nodes.literal
parts = self.pattern.split(node[-1].astext()) parts = self.pattern.split(node[-1].astext())
if len(parts) == 1: if len(parts) == 1 or self.is_multiwords_key(parts):
continue continue
node['classes'].append('compound')
node.pop() node.pop()
while parts: while parts:
key = parts.pop(0) if self.is_multiwords_key(parts):
key = ''.join(parts[:3])
parts[:3] = []
else:
key = parts.pop(0)
node += nodes.literal('', key, classes=["kbd"]) node += nodes.literal('', key, classes=["kbd"])
try: try:
@ -58,6 +70,16 @@ class KeyboardTransform(SphinxPostTransform):
except IndexError: except IndexError:
pass pass
def is_multiwords_key(self, parts: List[str]) -> bool:
if len(parts) >= 3 and parts[1].strip() == '':
name = parts[0].lower(), parts[2].lower()
if name in self.multiwords_keys:
return True
else:
return False
else:
return False
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:
app.add_post_transform(KeyboardTransform) app.add_post_transform(KeyboardTransform)

View File

@ -5,29 +5,34 @@
Build HTML help support files. Build HTML help support files.
Parts adapted from Python's Doc/tools/prechm.py. Parts adapted from Python's Doc/tools/prechm.py.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import warnings import warnings
from typing import Any, Dict from typing import Any, Dict
from sphinxcontrib.htmlhelp import ( from sphinxcontrib.htmlhelp import (HTMLHelpBuilder, chm_htmlescape, chm_locales,
chm_locales, chm_htmlescape, HTMLHelpBuilder, default_htmlhelp_basename default_htmlhelp_basename)
)
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
deprecated_alias('sphinx.builders.htmlhelp', deprecated_alias('sphinx.builders.htmlhelp',
{ {
'chm_locales': chm_locales, 'chm_locales': chm_locales,
'chm_htmlescape': chm_htmlescape, 'chm_htmlescape': chm_htmlescape,
'HTMLHelpBuilder': HTMLHelpBuilder, 'HTMLHelpBuilder': HTMLHelpBuilder,
'default_htmlhelp_basename': default_htmlhelp_basename, 'default_htmlhelp_basename': default_htmlhelp_basename,
}, },
RemovedInSphinx40Warning) 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]: def setup(app: Sphinx) -> Dict[str, Any]:

View File

@ -4,7 +4,7 @@
LaTeX builder. LaTeX builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -17,18 +17,18 @@ from docutils.frontend import OptionParser
from docutils.nodes import Node from docutils.nodes import Node
import sphinx.builders.latex.nodes # NOQA # Workaround: import this before writer to avoid ImportError import sphinx.builders.latex.nodes # NOQA # Workaround: import this before writer to avoid ImportError
from sphinx import package_dir, addnodes, highlighting from sphinx import addnodes, highlighting, package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, SHORTHANDOFF from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, SHORTHANDOFF
from sphinx.builders.latex.theming import Theme, ThemeFactory from sphinx.builders.latex.theming import Theme, ThemeFactory
from sphinx.builders.latex.util import ExtBabel from sphinx.builders.latex.util import ExtBabel
from sphinx.config import Config, ENUM from sphinx.config import ENUM, Config
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
from sphinx.environment.adapters.asset import ImageAdapter from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.errors import NoUri, SphinxError from sphinx.errors import NoUri, SphinxError
from sphinx.locale import _, __ from sphinx.locale import _, __
from sphinx.util import texescape, logging, progress_message, status_iterator from sphinx.util import logging, progress_message, status_iterator, texescape
from sphinx.util.console import bold, darkgreen # type: ignore from sphinx.util.console import bold, darkgreen # type: ignore
from sphinx.util.docutils import SphinxFileOutput, new_document from sphinx.util.docutils import SphinxFileOutput, new_document
from sphinx.util.fileutil import copy_asset_file from sphinx.util.fileutil import copy_asset_file
@ -36,11 +36,10 @@ from sphinx.util.i18n import format_date
from sphinx.util.nodes import inline_all_toctrees from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, make_filename_from_project from sphinx.util.osutil import SEP, make_filename_from_project
from sphinx.util.template import LaTeXRenderer from sphinx.util.template import LaTeXRenderer
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator from sphinx.writers.latex import LaTeXTranslator, LaTeXWriter
# load docutils.nodes after loading sphinx.builders.latex.nodes # load docutils.nodes after loading sphinx.builders.latex.nodes
from docutils import nodes # NOQA from docutils import nodes # isort:skip
XINDY_LANG_OPTIONS = { XINDY_LANG_OPTIONS = {
# language codes from docutils.writers.latex2e.Babel # language codes from docutils.writers.latex2e.Babel
@ -128,8 +127,6 @@ class LaTeXBuilder(Builder):
self.docnames = [] # type: Iterable[str] self.docnames = [] # type: Iterable[str]
self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]] self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]]
self.themes = ThemeFactory(self.app) self.themes = ThemeFactory(self.app)
self.usepackages = self.app.registry.latex_packages
self.usepackages_after_hyperref = self.app.registry.latex_packages_after_hyperref
texescape.init() texescape.init()
self.init_context() self.init_context()
@ -179,10 +176,6 @@ class LaTeXBuilder(Builder):
key = (self.config.latex_engine, self.config.language[:2]) key = (self.config.latex_engine, self.config.language[:2])
self.context.update(ADDITIONAL_SETTINGS.get(key, {})) self.context.update(ADDITIONAL_SETTINGS.get(key, {}))
# Apply extension settings to context
self.context['packages'] = self.usepackages
self.context['packages_after_hyperref'] = self.usepackages_after_hyperref
# Apply user settings to context # Apply user settings to context
self.context.update(self.config.latex_elements) self.context.update(self.config.latex_elements)
self.context['release'] = self.config.release self.context['release'] = self.config.release
@ -203,6 +196,13 @@ class LaTeXBuilder(Builder):
# Show the release label only if release value exists # Show the release label only if release value exists
self.context.setdefault('releasename', _('Release')) self.context.setdefault('releasename', _('Release'))
def update_context(self) -> None:
"""Update template variables for .tex file just before writing."""
# Apply extension settings to context
registry = self.app.registry
self.context['packages'] = registry.latex_packages
self.context['packages_after_hyperref'] = registry.latex_packages_after_hyperref
def init_babel(self) -> None: def init_babel(self) -> None:
self.babel = ExtBabel(self.config.language, not self.context['babel']) self.babel = ExtBabel(self.config.language, not self.context['babel'])
if self.config.language and not self.babel.is_supported_language(): if self.config.language and not self.babel.is_supported_language():
@ -290,6 +290,7 @@ class LaTeXBuilder(Builder):
doctree['tocdepth'] = tocdepth doctree['tocdepth'] = tocdepth
self.post_process_images(doctree) self.post_process_images(doctree)
self.update_doc_context(title, author, theme) self.update_doc_context(title, author, theme)
self.update_context()
with progress_message(__("writing")): with progress_message(__("writing")):
docsettings._author = author docsettings._author = author
@ -448,6 +449,18 @@ class LaTeXBuilder(Builder):
filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t') filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t')
copy_asset_file(filename, self.outdir, context=context, renderer=LaTeXRenderer()) copy_asset_file(filename, self.outdir, context=context, renderer=LaTeXRenderer())
@property
def usepackages(self) -> List[Tuple[str, str]]:
warnings.warn('LaTeXBuilder.usepackages is deprecated.',
RemovedInSphinx50Warning, stacklevel=2)
return self.app.registry.latex_packages
@property
def usepackages_after_hyperref(self) -> List[Tuple[str, str]]:
warnings.warn('LaTeXBuilder.usepackages_after_hyperref is deprecated.',
RemovedInSphinx50Warning, stacklevel=2)
return self.app.registry.latex_packages_after_hyperref
def patch_settings(settings: Any) -> Any: def patch_settings(settings: Any) -> Any:
"""Make settings object to show deprecation messages.""" """Make settings object to show deprecation messages."""
@ -503,9 +516,9 @@ def validate_latex_theme_options(app: Sphinx, config: Config) -> None:
config.latex_theme_options.pop(key) config.latex_theme_options.pop(key)
def install_pakcages_for_ja(app: Sphinx) -> None: def install_packages_for_ja(app: Sphinx) -> None:
"""Install packages for Japanese.""" """Install packages for Japanese."""
if app.config.language == 'ja': if app.config.language == 'ja' and app.config.latex_engine in ('platex', 'uplatex'):
app.add_latex_package('pxjahyper', after_hyperref=True) app.add_latex_package('pxjahyper', after_hyperref=True)
@ -556,7 +569,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_builder(LaTeXBuilder) app.add_builder(LaTeXBuilder)
app.connect('config-inited', validate_config_values, priority=800) app.connect('config-inited', validate_config_values, priority=800)
app.connect('config-inited', validate_latex_theme_options, priority=800) app.connect('config-inited', validate_latex_theme_options, priority=800)
app.connect('builder-inited', install_pakcages_for_ja) app.connect('builder-inited', install_packages_for_ja)
app.add_config_value('latex_engine', default_latex_engine, None, app.add_config_value('latex_engine', default_latex_engine, None,
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex')) ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex'))

View File

@ -4,13 +4,12 @@
consntants for LaTeX builder. consntants for LaTeX builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from typing import Any, Dict from typing import Any, Dict
PDFLATEX_DEFAULT_FONTPKG = r''' PDFLATEX_DEFAULT_FONTPKG = r'''
\usepackage{times} \usepackage{times}
\expandafter\ifx\csname T@LGR\endcsname\relax \expandafter\ifx\csname T@LGR\endcsname\relax

View File

@ -4,7 +4,7 @@
Additional nodes for LaTeX writer. Additional nodes for LaTeX writer.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """

View File

@ -4,7 +4,7 @@
Theming support for LaTeX builder. Theming support for LaTeX builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -87,10 +87,12 @@ class UserTheme(Theme):
try: try:
value = self.config.get('theme', key) value = self.config.get('theme', key)
setattr(self, key, value) setattr(self, key, value)
except configparser.NoSectionError: except configparser.NoSectionError as exc:
raise ThemeError(__('%r doesn\'t have "theme" setting') % filename) raise ThemeError(__('%r doesn\'t have "theme" setting') %
filename) from exc
except configparser.NoOptionError as exc: except configparser.NoOptionError as exc:
raise ThemeError(__('%r doesn\'t have "%s" setting') % (filename, exc.args[0])) raise ThemeError(__('%r doesn\'t have "%s" setting') %
(filename, exc.args[0])) from exc
for key in self.OPTIONAL_CONFIG_KEYS: for key in self.OPTIONAL_CONFIG_KEYS:
try: try:

View File

@ -4,21 +4,20 @@
Transforms for LaTeX builder. Transforms for LaTeX builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from typing import Any, Dict, List, Set, Tuple from typing import Any, Dict, List, Set, Tuple, cast
from typing import cast
from docutils import nodes from docutils import nodes
from docutils.nodes import Element, Node from docutils.nodes import Element, Node
from docutils.transforms.references import Substitutions
from sphinx import addnodes from sphinx import addnodes
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders.latex.nodes import ( from sphinx.builders.latex.nodes import (captioned_literal_block, footnotemark, footnotetext,
captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography math_reference, thebibliography)
)
from sphinx.domains.citation import CitationDomain from sphinx.domains.citation import CitationDomain
from sphinx.transforms import SphinxTransform from sphinx.transforms import SphinxTransform
from sphinx.transforms.post_transforms import SphinxPostTransform from sphinx.transforms.post_transforms import SphinxPostTransform
@ -38,6 +37,18 @@ class FootnoteDocnameUpdater(SphinxTransform):
node['docname'] = self.env.docname node['docname'] = self.env.docname
class SubstitutionDefinitionsRemover(SphinxPostTransform):
"""Remove ``substitution_definition node from doctrees."""
# should be invoked after Substitutions process
default_priority = Substitutions.default_priority + 1
builders = ('latex',)
def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(nodes.substitution_definition):
node.parent.remove(node)
class ShowUrlsTransform(SphinxPostTransform): class ShowUrlsTransform(SphinxPostTransform):
"""Expand references to inline text or footnotes. """Expand references to inline text or footnotes.
@ -602,6 +613,7 @@ class IndexInSectionTitleTransform(SphinxTransform):
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:
app.add_transform(FootnoteDocnameUpdater) app.add_transform(FootnoteDocnameUpdater)
app.add_post_transform(SubstitutionDefinitionsRemover)
app.add_post_transform(BibliographyTransform) app.add_post_transform(BibliographyTransform)
app.add_post_transform(CitationReferenceTransform) app.add_post_transform(CitationReferenceTransform)
app.add_post_transform(DocumentTargetTransform) app.add_post_transform(DocumentTargetTransform)

View File

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

View File

@ -4,7 +4,7 @@
The CheckExternalLinksBuilder class. The CheckExternalLinksBuilder class.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -13,28 +13,56 @@ import queue
import re import re
import socket import socket
import threading import threading
import time
import warnings
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
from html.parser import HTMLParser from html.parser import HTMLParser
from os import path from os import path
from typing import Any, Dict, List, Set, Tuple from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple, cast
from urllib.parse import unquote from urllib.parse import unquote, urlparse
from docutils import nodes from docutils import nodes
from docutils.nodes import Node from docutils.nodes import Element
from requests.exceptions import HTTPError from requests import Response
from requests.exceptions import HTTPError, TooManyRedirects
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders.dummy import DummyBuilder
from sphinx.deprecation import RemovedInSphinx50Warning
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import encode_uri, requests, logging from sphinx.transforms.post_transforms import SphinxPostTransform
from sphinx.util.console import ( # type: ignore from sphinx.util import encode_uri, logging, requests
purple, red, darkgreen, darkgray, turquoise from sphinx.util.console import darkgray, darkgreen, purple, red, turquoise # type: ignore
)
from sphinx.util.nodes import get_node_line from sphinx.util.nodes import get_node_line
from sphinx.util.requests import is_ssl_error
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
uri_re = re.compile('([a-z]+:)?//') # matches to foo:// and // (a protocol relative URL)
Hyperlink = NamedTuple('Hyperlink', (('next_check', float),
('uri', Optional[str]),
('docname', Optional[str]),
('lineno', Optional[int])))
RateLimit = NamedTuple('RateLimit', (('delay', float), ('next_check', float)))
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',
}
CHECK_IMMEDIATELY = 0
QUEUE_POLL_SECS = 1
DEFAULT_DELAY = 60.0
def node_line_or_0(node: Element) -> int:
"""
PriorityQueue items must be comparable. The line number is part of the
tuple used by the PriorityQueue, keep an homogeneous type for comparison.
"""
warnings.warn('node_line_or_0() is deprecated.',
RemovedInSphinx50Warning, stacklevel=2)
return get_node_line(node) or 0
class AnchorCheckParser(HTMLParser): class AnchorCheckParser(HTMLParser):
"""Specialized HTML parser that looks for a specific anchor.""" """Specialized HTML parser that looks for a specific anchor."""
@ -70,7 +98,7 @@ def check_anchor(response: requests.requests.Response, anchor: str) -> bool:
return parser.found return parser.found
class CheckExternalLinksBuilder(Builder): class CheckExternalLinksBuilder(DummyBuilder):
""" """
Checks for broken external links. Checks for broken external links.
""" """
@ -79,14 +107,15 @@ class CheckExternalLinksBuilder(Builder):
'%(outdir)s/output.txt') '%(outdir)s/output.txt')
def init(self) -> None: def init(self) -> None:
self.hyperlinks = {} # type: Dict[str, Hyperlink]
self.to_ignore = [re.compile(x) for x in self.app.config.linkcheck_ignore] self.to_ignore = [re.compile(x) for x in self.app.config.linkcheck_ignore]
self.anchors_ignore = [re.compile(x) self.anchors_ignore = [re.compile(x)
for x in self.app.config.linkcheck_anchors_ignore] for x in self.app.config.linkcheck_anchors_ignore]
self.auth = [(re.compile(pattern), auth_info) for pattern, auth_info self.auth = [(re.compile(pattern), auth_info) for pattern, auth_info
in self.app.config.linkcheck_auth] in self.app.config.linkcheck_auth]
self.good = set() # type: Set[str] self._good = set() # type: Set[str]
self.broken = {} # type: Dict[str, str] self._broken = {} # type: Dict[str, str]
self.redirected = {} # type: Dict[str, Tuple[str, int]] self._redirected = {} # type: Dict[str, Tuple[str, int]]
# set a timeout for non-responding servers # set a timeout for non-responding servers
socket.setdefaulttimeout(5.0) socket.setdefaulttimeout(5.0)
# create output file # create output file
@ -95,25 +124,62 @@ class CheckExternalLinksBuilder(Builder):
open(path.join(self.outdir, 'output.json'), 'w').close() open(path.join(self.outdir, 'output.json'), 'w').close()
# create queues and worker threads # create queues and worker threads
self.wqueue = queue.Queue() # type: queue.Queue self.rate_limits = {} # type: Dict[str, RateLimit]
self.wqueue = queue.PriorityQueue() # type: queue.PriorityQueue
self.rqueue = queue.Queue() # type: queue.Queue self.rqueue = queue.Queue() # type: queue.Queue
self.workers = [] # type: List[threading.Thread] self.workers = [] # type: List[threading.Thread]
for i in range(self.app.config.linkcheck_workers): for i in range(self.app.config.linkcheck_workers):
thread = threading.Thread(target=self.check_thread) thread = threading.Thread(target=self.check_thread, daemon=True)
thread.setDaemon(True)
thread.start() thread.start()
self.workers.append(thread) self.workers.append(thread)
@property
def good(self):
warnings.warn(
"%s.%s is deprecated." % (self.__class__.__name__, "good"),
RemovedInSphinx50Warning,
stacklevel=2,
)
return self._good
@property
def broken(self):
warnings.warn(
"%s.%s is deprecated." % (self.__class__.__name__, "broken"),
RemovedInSphinx50Warning,
stacklevel=2,
)
return self._broken
@property
def redirected(self):
warnings.warn(
"%s.%s is deprecated." % (self.__class__.__name__, "redirected"),
RemovedInSphinx50Warning,
stacklevel=2,
)
return self._redirected
def check_thread(self) -> None: def check_thread(self) -> None:
kwargs = { kwargs = {}
'allow_redirects': True,
'headers': {
'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',
},
}
if self.app.config.linkcheck_timeout: if self.app.config.linkcheck_timeout:
kwargs['timeout'] = self.app.config.linkcheck_timeout kwargs['timeout'] = self.app.config.linkcheck_timeout
def get_request_headers() -> Dict:
url = urlparse(uri)
candidates = ["%s://%s" % (url.scheme, url.netloc),
"%s://%s/" % (url.scheme, url.netloc),
uri,
"*"]
for u in candidates:
if u in self.config.linkcheck_request_headers:
headers = dict(DEFAULT_REQUEST_HEADERS)
headers.update(self.config.linkcheck_request_headers[u])
return headers
return {}
def check_uri() -> Tuple[str, str, int]: def check_uri() -> Tuple[str, str, int]:
# split off anchor # split off anchor
if '#' in uri: if '#' in uri:
@ -139,11 +205,15 @@ class CheckExternalLinksBuilder(Builder):
else: else:
auth_info = None auth_info = None
# update request headers for the URL
kwargs['headers'] = get_request_headers()
try: try:
if anchor and self.app.config.linkcheck_anchors: if anchor and self.app.config.linkcheck_anchors:
# Read the whole document and see if #anchor exists # Read the whole document and see if #anchor exists
response = requests.get(req_url, stream=True, config=self.app.config, response = requests.get(req_url, stream=True, config=self.app.config,
auth=auth_info, **kwargs) auth=auth_info, **kwargs)
response.raise_for_status()
found = check_anchor(response, unquote(anchor)) found = check_anchor(response, unquote(anchor))
if not found: if not found:
@ -152,29 +222,42 @@ class CheckExternalLinksBuilder(Builder):
try: try:
# try a HEAD request first, which should be easier on # try a HEAD request first, which should be easier on
# the server and the network # the server and the network
response = requests.head(req_url, config=self.app.config, response = requests.head(req_url, allow_redirects=True,
auth=auth_info, **kwargs) config=self.app.config, auth=auth_info,
**kwargs)
response.raise_for_status() response.raise_for_status()
except HTTPError: except (HTTPError, TooManyRedirects) as err:
if isinstance(err, HTTPError) and err.response.status_code == 429:
raise
# retry with GET request if that fails, some servers # retry with GET request if that fails, some servers
# don't like HEAD requests. # don't like HEAD requests.
response = requests.get(req_url, stream=True, config=self.app.config, response = requests.get(req_url, stream=True,
config=self.app.config,
auth=auth_info, **kwargs) auth=auth_info, **kwargs)
response.raise_for_status() response.raise_for_status()
except HTTPError as err: except HTTPError as err:
if err.response.status_code == 401: if err.response.status_code == 401:
# We'll take "Unauthorized" as working. # We'll take "Unauthorized" as working.
return 'working', ' - unauthorized', 0 return 'working', ' - unauthorized', 0
elif err.response.status_code == 429:
next_check = self.limit_rate(err.response)
if next_check is not None:
self.wqueue.put((next_check, uri, docname, lineno), False)
return 'rate-limited', '', 0
return 'broken', str(err), 0
elif err.response.status_code == 503: elif err.response.status_code == 503:
# We'll take "Service Unavailable" as ignored. # We'll take "Service Unavailable" as ignored.
return 'ignored', str(err), 0 return 'ignored', str(err), 0
else: else:
return 'broken', str(err), 0 return 'broken', str(err), 0
except Exception as err: except Exception as err:
if is_ssl_error(err): return 'broken', str(err), 0
return 'ignored', str(err), 0 else:
else: netloc = urlparse(req_url).netloc
return 'broken', str(err), 0 try:
del self.rate_limits[netloc]
except KeyError:
pass
if response.url.rstrip('/') == req_url.rstrip('/'): if response.url.rstrip('/') == req_url.rstrip('/'):
return 'working', '', 0 return 'working', '', 0
else: else:
@ -188,18 +271,31 @@ class CheckExternalLinksBuilder(Builder):
else: else:
return 'redirected', new_url, 0 return 'redirected', new_url, 0
def check() -> Tuple[str, str, int]: def check(docname: str) -> Tuple[str, str, int]:
# check for various conditions without bothering the network # check for various conditions without bothering the network
if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'ftp:')): if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'tel:')):
return 'unchecked', '', 0 return 'unchecked', '', 0
elif not uri.startswith(('http:', 'https:')): elif not uri.startswith(('http:', 'https:')):
return 'local', '', 0 if uri_re.match(uri):
elif uri in self.good: # non supported URI schemes (ex. ftp)
return 'unchecked', '', 0
else:
srcdir = path.dirname(self.env.doc2path(docname))
if path.exists(path.join(srcdir, uri)):
return 'working', '', 0
else:
for rex in self.to_ignore:
if rex.match(uri):
return 'ignored', '', 0
else:
self._broken[uri] = ''
return 'broken', '', 0
elif uri in self._good:
return 'working', 'old', 0 return 'working', 'old', 0
elif uri in self.broken: elif uri in self._broken:
return 'broken', self.broken[uri], 0 return 'broken', self._broken[uri], 0
elif uri in self.redirected: elif uri in self._redirected:
return 'redirected', self.redirected[uri][0], self.redirected[uri][1] return 'redirected', self._redirected[uri][0], self._redirected[uri][1]
for rex in self.to_ignore: for rex in self.to_ignore:
if rex.match(uri): if rex.match(uri):
return 'ignored', '', 0 return 'ignored', '', 0
@ -211,20 +307,78 @@ class CheckExternalLinksBuilder(Builder):
break break
if status == "working": if status == "working":
self.good.add(uri) self._good.add(uri)
elif status == "broken": elif status == "broken":
self.broken[uri] = info self._broken[uri] = info
elif status == "redirected": elif status == "redirected":
self.redirected[uri] = (info, code) self._redirected[uri] = (info, code)
return (status, info, code) return (status, info, code)
while True: while True:
uri, docname, lineno = self.wqueue.get() next_check, uri, docname, lineno = self.wqueue.get()
if uri is None: if uri is None:
break break
status, info, code = check() netloc = urlparse(uri).netloc
self.rqueue.put((uri, docname, lineno, status, info, code)) try:
# Refresh rate limit.
# When there are many links in the queue, workers are all stuck waiting
# for responses, but the builder keeps queuing. Links in the queue may
# have been queued before rate limits were discovered.
next_check = self.rate_limits[netloc].next_check
except KeyError:
pass
if next_check > time.time():
# Sleep before putting message back in the queue to avoid
# waking up other threads.
time.sleep(QUEUE_POLL_SECS)
self.wqueue.put((next_check, uri, docname, lineno), False)
self.wqueue.task_done()
continue
status, info, code = check(docname)
if status == 'rate-limited':
logger.info(darkgray('-rate limited- ') + uri + darkgray(' | sleeping...'))
else:
self.rqueue.put((uri, docname, lineno, status, info, code))
self.wqueue.task_done()
def limit_rate(self, response: Response) -> Optional[float]:
next_check = None
retry_after = response.headers.get("Retry-After")
if retry_after:
try:
# Integer: time to wait before next attempt.
delay = float(retry_after)
except ValueError:
try:
# An HTTP-date: time of next attempt.
until = parsedate_to_datetime(retry_after)
except (TypeError, ValueError):
# TypeError: Invalid date format.
# ValueError: Invalid date, e.g. Oct 52th.
pass
else:
next_check = datetime.timestamp(until)
delay = (until - datetime.now(timezone.utc)).total_seconds()
else:
next_check = time.time() + delay
netloc = urlparse(response.url).netloc
if next_check is None:
max_delay = self.app.config.linkcheck_rate_limit_timeout
try:
rate_limit = self.rate_limits[netloc]
except KeyError:
delay = DEFAULT_DELAY
else:
last_wait_time = rate_limit.delay
delay = 2.0 * last_wait_time
if delay > max_delay and last_wait_time < max_delay:
delay = max_delay
if delay > max_delay:
return None
next_check = time.time() + delay
self.rate_limits[netloc] = RateLimit(delay, next_check)
return next_check
def process_result(self, result: Tuple[str, str, int, str, str, int]) -> None: def process_result(self, result: Tuple[str, str, int, str, str, int]) -> None:
uri, docname, lineno, status, info, code = result uri, docname, lineno, status, info, code = result
@ -279,44 +433,6 @@ class CheckExternalLinksBuilder(Builder):
lineno, uri + ' to ' + info) lineno, uri + ' to ' + info)
self.write_linkstat(linkstat) self.write_linkstat(linkstat)
def get_target_uri(self, docname: str, typ: str = None) -> str:
return ''
def get_outdated_docs(self) -> Set[str]:
return self.env.found_docs
def prepare_writing(self, docnames: Set[str]) -> None:
return
def write_doc(self, docname: str, doctree: Node) -> None:
logger.info('')
n = 0
# reference nodes
for refnode in doctree.traverse(nodes.reference):
if 'refuri' not in refnode:
continue
uri = refnode['refuri']
lineno = get_node_line(refnode)
self.wqueue.put((uri, docname, lineno), False)
n += 1
# image nodes
for imgnode in doctree.traverse(nodes.image):
uri = imgnode['candidates'].get('?')
if uri and '://' in uri:
lineno = get_node_line(imgnode)
self.wqueue.put((uri, docname, lineno), False)
n += 1
done = 0
while done < n:
self.process_result(self.rqueue.get())
done += 1
if self.broken:
self.app.statuscode = 1
def write_entry(self, what: str, docname: str, filename: str, line: int, def write_entry(self, what: str, docname: str, filename: str, line: int,
uri: str) -> None: uri: str) -> None:
with open(path.join(self.outdir, 'output.txt'), 'a') as output: with open(path.join(self.outdir, 'output.txt'), 'a') as output:
@ -328,15 +444,62 @@ class CheckExternalLinksBuilder(Builder):
output.write('\n') output.write('\n')
def finish(self) -> None: def finish(self) -> None:
logger.info('')
n = 0
for hyperlink in self.hyperlinks.values():
self.wqueue.put(hyperlink, False)
n += 1
done = 0
while done < n:
self.process_result(self.rqueue.get())
done += 1
if self._broken:
self.app.statuscode = 1
self.wqueue.join()
# Shutdown threads.
for worker in self.workers: for worker in self.workers:
self.wqueue.put((None, None, None), False) self.wqueue.put((CHECK_IMMEDIATELY, None, None, None), False)
class HyperlinkCollector(SphinxPostTransform):
builders = ('linkcheck',)
default_priority = 800
def run(self, **kwargs: Any) -> None:
builder = cast(CheckExternalLinksBuilder, self.app.builder)
hyperlinks = builder.hyperlinks
# reference nodes
for refnode in self.document.traverse(nodes.reference):
if 'refuri' not in refnode:
continue
uri = refnode['refuri']
lineno = get_node_line(refnode)
uri_info = Hyperlink(CHECK_IMMEDIATELY, uri, self.env.docname, lineno)
if uri not in hyperlinks:
hyperlinks[uri] = uri_info
# image nodes
for imgnode in self.document.traverse(nodes.image):
uri = imgnode['candidates'].get('?')
if uri and '://' in uri:
lineno = get_node_line(imgnode)
uri_info = Hyperlink(CHECK_IMMEDIATELY, uri, self.env.docname, lineno)
if uri not in hyperlinks:
hyperlinks[uri] = uri_info
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:
app.add_builder(CheckExternalLinksBuilder) app.add_builder(CheckExternalLinksBuilder)
app.add_post_transform(HyperlinkCollector)
app.add_config_value('linkcheck_ignore', [], None) app.add_config_value('linkcheck_ignore', [], None)
app.add_config_value('linkcheck_auth', [], None) app.add_config_value('linkcheck_auth', [], None)
app.add_config_value('linkcheck_request_headers', {}, None)
app.add_config_value('linkcheck_retries', 1, None) app.add_config_value('linkcheck_retries', 1, None)
app.add_config_value('linkcheck_timeout', None, None, [int]) app.add_config_value('linkcheck_timeout', None, None, [int])
app.add_config_value('linkcheck_workers', 5, None) app.add_config_value('linkcheck_workers', 5, None)
@ -344,6 +507,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
# Anchors starting with ! are ignored since they are # Anchors starting with ! are ignored since they are
# commonly used for dynamic pages # commonly used for dynamic pages
app.add_config_value('linkcheck_anchors_ignore', ["^!"], None) app.add_config_value('linkcheck_anchors_ignore', ["^!"], None)
app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None)
return { return {
'version': 'builtin', 'version': 'builtin',

View File

@ -4,7 +4,7 @@
Manual pages builder. Manual pages builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -20,13 +20,11 @@ from sphinx.builders import Builder
from sphinx.config import Config from sphinx.config import Config
from sphinx.errors import NoUri from sphinx.errors import NoUri
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging, progress_message
from sphinx.util import progress_message
from sphinx.util.console import darkgreen # type: ignore from sphinx.util.console import darkgreen # type: ignore
from sphinx.util.nodes import inline_all_toctrees from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import make_filename_from_project from sphinx.util.osutil import ensuredir, make_filename_from_project
from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator from sphinx.writers.manpage import ManualPageTranslator, ManualPageWriter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -80,7 +78,12 @@ class ManualPageBuilder(Builder):
docsettings.authors = authors docsettings.authors = authors
docsettings.section = section docsettings.section = section
targetname = '%s.%s' % (name, section) if self.config.man_make_section_directory:
ensuredir(path.join(self.outdir, str(section)))
targetname = '%s/%s.%s' % (section, name, section)
else:
targetname = '%s.%s' % (name, section)
logger.info(darkgreen(targetname) + ' { ', nonl=True) logger.info(darkgreen(targetname) + ' { ', nonl=True)
destination = FileOutput( destination = FileOutput(
destination_path=path.join(self.outdir, targetname), destination_path=path.join(self.outdir, targetname),
@ -115,6 +118,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('man_pages', default_man_pages, None) app.add_config_value('man_pages', default_man_pages, None)
app.add_config_value('man_show_urls', False, None) app.add_config_value('man_show_urls', False, None)
app.add_config_value('man_make_section_directory', False, None)
return { return {
'version': 'builtin', 'version': 'builtin',

View File

@ -4,7 +4,7 @@
Build input files for the Qt collection generator. Build input files for the Qt collection generator.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -17,13 +17,16 @@ import sphinx
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
deprecated_alias('sphinx.builders.qthelp', deprecated_alias('sphinx.builders.qthelp',
{ {
'render_file': render_file, 'render_file': render_file,
'QtHelpBuilder': QtHelpBuilder, 'QtHelpBuilder': QtHelpBuilder,
}, },
RemovedInSphinx40Warning) RemovedInSphinx40Warning,
{
'render_file': 'sphinxcontrib.qthelp.render_file',
'QtHelpBuilder': 'sphinxcontrib.qthelp.QtHelpBuilder',
})
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:

View File

@ -4,7 +4,7 @@
Single HTML builders. Single HTML builders.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -19,8 +19,7 @@ from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.adapters.toctree import TocTree
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging, progress_message
from sphinx.util import progress_message
from sphinx.util.console import darkgreen # type: ignore from sphinx.util.console import darkgreen # type: ignore
from sphinx.util.nodes import inline_all_toctrees from sphinx.util.nodes import inline_all_toctrees
@ -193,7 +192,11 @@ deprecated_alias('sphinx.builders.html',
{ {
'SingleFileHTMLBuilder': SingleFileHTMLBuilder, 'SingleFileHTMLBuilder': SingleFileHTMLBuilder,
}, },
RemovedInSphinx40Warning) RemovedInSphinx40Warning,
{
'SingleFileHTMLBuilder':
'sphinx.builders.singlehtml.SingleFileHTMLBuilder',
})
def setup(app: Sphinx) -> Dict[str, Any]: def setup(app: Sphinx) -> Dict[str, Any]:

View File

@ -4,7 +4,7 @@
Texinfo builder. Texinfo builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -16,23 +16,20 @@ from docutils import nodes
from docutils.frontend import OptionParser from docutils.frontend import OptionParser
from docutils.io import FileOutput from docutils.io import FileOutput
from sphinx import addnodes from sphinx import addnodes, package_dir
from sphinx import package_dir
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.config import Config from sphinx.config import Config
from sphinx.environment.adapters.asset import ImageAdapter from sphinx.environment.adapters.asset import ImageAdapter
from sphinx.errors import NoUri from sphinx.errors import NoUri
from sphinx.locale import _, __ from sphinx.locale import _, __
from sphinx.util import logging from sphinx.util import logging, progress_message, status_iterator
from sphinx.util import progress_message, status_iterator
from sphinx.util.console import darkgreen # type: ignore from sphinx.util.console import darkgreen # type: ignore
from sphinx.util.docutils import new_document from sphinx.util.docutils import new_document
from sphinx.util.fileutil import copy_asset_file from sphinx.util.fileutil import copy_asset_file
from sphinx.util.nodes import inline_all_toctrees from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, ensuredir, make_filename_from_project from sphinx.util.osutil import SEP, ensuredir, make_filename_from_project
from sphinx.writers.texinfo import TexinfoWriter, TexinfoTranslator from sphinx.writers.texinfo import TexinfoTranslator, TexinfoWriter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
template_dir = os.path.join(package_dir, 'templates', 'texinfo') template_dir = os.path.join(package_dir, 'templates', 'texinfo')
@ -182,7 +179,8 @@ class TexinfoBuilder(Builder):
try: try:
imagedir = path.join(self.outdir, targetname + '-figures') imagedir = path.join(self.outdir, targetname + '-figures')
ensuredir(imagedir) ensuredir(imagedir)
copy_asset_file(path.join(self.srcdir, dest), imagedir) copy_asset_file(path.join(self.srcdir, src),
path.join(imagedir, dest))
except Exception as err: except Exception as err:
logger.warning(__('cannot copy image file %r: %s'), logger.warning(__('cannot copy image file %r: %s'),
path.join(self.srcdir, src), err) path.join(self.srcdir, src), err)

View File

@ -4,7 +4,7 @@
Plain-text Sphinx builder. Plain-text Sphinx builder.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -19,7 +19,7 @@ from sphinx.builders import Builder
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path from sphinx.util.osutil import ensuredir, os_path
from sphinx.writers.text import TextWriter, TextTranslator from sphinx.writers.text import TextTranslator, TextWriter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -4,7 +4,7 @@
Docutils-native XML and pseudo-XML builders. Docutils-native XML and pseudo-XML builders.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -21,7 +21,7 @@ from sphinx.builders import Builder
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path from sphinx.util.osutil import ensuredir, os_path
from sphinx.writers.xml import XMLWriter, PseudoXMLWriter from sphinx.writers.xml import PseudoXMLWriter, XMLWriter
if False: if False:
# For type annotation # For type annotation

View File

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

View File

@ -4,7 +4,7 @@
Build documentation from a provided source. Build documentation from a provided source.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -16,7 +16,7 @@ import os
import pdb import pdb
import sys import sys
import traceback import traceback
from typing import Any, IO, List from typing import IO, Any, List
from docutils.utils import SystemMessage from docutils.utils import SystemMessage
@ -26,7 +26,7 @@ from sphinx.application import Sphinx
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import Tee, format_exception_cut_frames, save_traceback from sphinx.util import Tee, format_exception_cut_frames, save_traceback
from sphinx.util.console import red, nocolor, color_terminal, terminal_safe # type: ignore from sphinx.util.console import color_terminal, nocolor, red, terminal_safe # type: ignore
from sphinx.util.docutils import docutils_namespace, patch_docutils from sphinx.util.docutils import docutils_namespace, patch_docutils

View File

@ -10,7 +10,7 @@
This is in its own module so that importing it is fast. It should not This is in its own module so that importing it is fast. It should not
import the main Sphinx modules (like sphinx.applications, sphinx.builders). import the main Sphinx modules (like sphinx.applications, sphinx.builders).
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -22,10 +22,9 @@ from typing import List
import sphinx import sphinx
from sphinx.cmd.build import build_main from sphinx.cmd.build import build_main
from sphinx.util.console import color_terminal, nocolor, bold, blue # type: ignore from sphinx.util.console import blue, bold, color_terminal, nocolor # type: ignore
from sphinx.util.osutil import cd, rmtree from sphinx.util.osutil import cd, rmtree
BUILDERS = [ BUILDERS = [
("", "html", "to make standalone HTML files"), ("", "html", "to make standalone HTML files"),
("", "dirhtml", "to make HTML files named index.html in directories"), ("", "dirhtml", "to make HTML files named index.html in directories"),

View File

@ -4,7 +4,7 @@
Quickly setup documentation source to work with Sphinx. Quickly setup documentation source to work with Sphinx.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -37,9 +37,8 @@ import sphinx.locale
from sphinx import __display_version__, package_dir from sphinx import __display_version__, package_dir
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util.console import ( # type: ignore from sphinx.util.console import (bold, color_terminal, colorize, nocolor, red, # type: ignore
colorize, bold, red, turquoise, nocolor, color_terminal turquoise)
)
from sphinx.util.osutil import ensuredir from sphinx.util.osutil import ensuredir
from sphinx.util.template import SphinxRenderer from sphinx.util.template import SphinxRenderer
@ -489,8 +488,10 @@ def get_parser() -> argparse.ArgumentParser:
help=__('project root')) help=__('project root'))
group = parser.add_argument_group(__('Structure options')) group = parser.add_argument_group(__('Structure options'))
group.add_argument('--sep', action='store_true', default=None, group.add_argument('--sep', action='store_true', dest='sep', default=None,
help=__('if specified, separate source and build dirs')) help=__('if specified, separate source and build dirs'))
group.add_argument('--no-sep', action='store_false', dest='sep',
help=__('if specified, create build dir under source dir'))
group.add_argument('--dot', metavar='DOT', default='_', group.add_argument('--dot', metavar='DOT', default='_',
help=__('replacement for dot in _templates etc.')) help=__('replacement for dot in _templates etc.'))

View File

@ -4,7 +4,7 @@
Build configuration file handling. Build configuration file handling.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -13,10 +13,9 @@ import traceback
import types import types
import warnings import warnings
from collections import OrderedDict from collections import OrderedDict
from os import path, getenv from os import getenv, path
from typing import ( from typing import (Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple,
Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple, Union Union)
)
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.errors import ConfigError, ExtensionError from sphinx.errors import ConfigError, ExtensionError
@ -99,7 +98,8 @@ class Config:
# general options # general options
'project': ('Python', 'env', []), 'project': ('Python', 'env', []),
'author': ('unknown', 'env', []), 'author': ('unknown', 'env', []),
'copyright': ('', 'html', []), 'project_copyright': ('', 'html', [str]),
'copyright': (lambda c: c.project_copyright, 'html', [str]),
'version': ('', 'env', []), 'version': ('', 'env', []),
'release': ('', 'env', []), 'release': ('', 'env', []),
'today': ('', 'env', []), 'today': ('', 'env', []),
@ -131,7 +131,7 @@ class Config:
'rst_epilog': (None, 'env', [str]), 'rst_epilog': (None, 'env', [str]),
'rst_prolog': (None, 'env', [str]), 'rst_prolog': (None, 'env', [str]),
'trim_doctest_flags': (True, 'env', []), 'trim_doctest_flags': (True, 'env', []),
'primary_domain': ('py', 'env', [NoneType]), # type: ignore 'primary_domain': ('py', 'env', [NoneType]),
'needs_sphinx': (None, None, [str]), 'needs_sphinx': (None, None, [str]),
'needs_extensions': ({}, None, []), 'needs_extensions': ({}, None, []),
'manpages_url': (None, 'env', []), 'manpages_url': (None, 'env', []),
@ -181,6 +181,14 @@ class Config:
defvalue = self.values[name][0] defvalue = self.values[name][0]
if self.values[name][2] == Any: if self.values[name][2] == Any:
return value return value
elif self.values[name][2] == {bool, str}:
if value == '0':
# given falsy string from command line option
return False
elif value == '1':
return True
else:
return value
elif type(defvalue) is bool or self.values[name][2] == [bool]: elif type(defvalue) is bool or self.values[name][2] == [bool]:
if value == '0': if value == '0':
# given falsy string from command line option # given falsy string from command line option
@ -196,9 +204,9 @@ class Config:
elif isinstance(defvalue, int): elif isinstance(defvalue, int):
try: try:
return int(value) return int(value)
except ValueError: except ValueError as exc:
raise ValueError(__('invalid number %r for config value %r, ignoring') % raise ValueError(__('invalid number %r for config value %r, ignoring') %
(value, name)) (value, name)) from exc
elif hasattr(defvalue, '__call__'): elif hasattr(defvalue, '__call__'):
return value return value
elif defvalue is not None and not isinstance(defvalue, str): elif defvalue is not None and not isinstance(defvalue, str):
@ -319,17 +327,17 @@ def eval_config_file(filename: str, tags: Tags) -> Dict[str, Any]:
execfile_(filename, namespace) execfile_(filename, namespace)
except SyntaxError as err: except SyntaxError as err:
msg = __("There is a syntax error in your configuration file: %s\n") msg = __("There is a syntax error in your configuration file: %s\n")
raise ConfigError(msg % err) raise ConfigError(msg % err) from err
except SystemExit: except SystemExit as exc:
msg = __("The configuration file (or one of the modules it imports) " msg = __("The configuration file (or one of the modules it imports) "
"called sys.exit()") "called sys.exit()")
raise ConfigError(msg) raise ConfigError(msg) from exc
except ConfigError: except ConfigError:
# pass through ConfigError from conf.py as is. It will be shown in console. # pass through ConfigError from conf.py as is. It will be shown in console.
raise raise
except Exception: except Exception as exc:
msg = __("There is a programmable error in your configuration file:\n\n%s") msg = __("There is a programmable error in your configuration file:\n\n%s")
raise ConfigError(msg % traceback.format_exc()) raise ConfigError(msg % traceback.format_exc()) from exc
return namespace return namespace
@ -359,6 +367,18 @@ def convert_source_suffix(app: "Sphinx", config: Config) -> None:
"But `%r' is given." % source_suffix)) "But `%r' is given." % source_suffix))
def convert_highlight_options(app: "Sphinx", config: Config) -> None:
"""Convert old styled highlight_options to new styled one.
* old style: options
* new style: dict that maps language names to options
"""
options = config.highlight_options
if options and not all(isinstance(v, dict) for v in options.values()):
# old styled option detected because all values are not dictionary.
config.highlight_options = {config.highlight_language: options} # type: ignore
def init_numfig_format(app: "Sphinx", config: Config) -> None: def init_numfig_format(app: "Sphinx", config: Config) -> None:
"""Initialize :confval:`numfig_format`.""" """Initialize :confval:`numfig_format`."""
numfig_format = {'section': _('Section %s'), numfig_format = {'section': _('Section %s'),
@ -479,6 +499,7 @@ def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],
def setup(app: "Sphinx") -> Dict[str, Any]: def setup(app: "Sphinx") -> Dict[str, Any]:
app.connect('config-inited', convert_source_suffix, priority=800) app.connect('config-inited', convert_source_suffix, priority=800)
app.connect('config-inited', convert_highlight_options, priority=800)
app.connect('config-inited', init_numfig_format, priority=800) app.connect('config-inited', init_numfig_format, priority=800)
app.connect('config-inited', correct_copyright_year, priority=800) app.connect('config-inited', correct_copyright_year, priority=800)
app.connect('config-inited', check_confval_types, priority=800) app.connect('config-inited', check_confval_types, priority=800)

View File

@ -4,7 +4,7 @@
Sphinx deprecation classes and utilities. Sphinx deprecation classes and utilities.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
@ -26,30 +26,46 @@ class RemovedInSphinx50Warning(PendingDeprecationWarning):
pass pass
class RemovedInSphinx60Warning(PendingDeprecationWarning):
pass
RemovedInNextVersionWarning = RemovedInSphinx40Warning RemovedInNextVersionWarning = RemovedInSphinx40Warning
def deprecated_alias(modname: str, objects: Dict, warning: "Type[Warning]") -> None: def deprecated_alias(modname: str, objects: Dict[str, object],
warning: "Type[Warning]", names: Dict[str, str] = None) -> None:
module = import_module(modname) module = import_module(modname)
sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore sys.modules[modname] = _ModuleWrapper( # type: ignore
module, modname, objects, warning, names)
class _ModuleWrapper: class _ModuleWrapper:
def __init__(self, module: Any, modname: str, objects: Dict, warning: "Type[Warning]" def __init__(self, module: Any, modname: str,
) -> None: objects: Dict[str, object],
warning: "Type[Warning]",
names: Dict[str, str]) -> None:
self._module = module self._module = module
self._modname = modname self._modname = modname
self._objects = objects self._objects = objects
self._warning = warning self._warning = warning
self._names = names
def __getattr__(self, name: str) -> Any: def __getattr__(self, name: str) -> Any:
if name in self._objects: if name not in self._objects:
warnings.warn("%s.%s is deprecated. Check CHANGES for Sphinx " return getattr(self._module, name)
"API modifications." % (self._modname, name),
self._warning, stacklevel=3)
return self._objects[name]
return getattr(self._module, name) canonical_name = self._names.get(name, None)
if canonical_name is not None:
warnings.warn(
"The alias '{}.{}' is deprecated, use '{}' instead. Check CHANGES for "
"Sphinx API modifications.".format(self._modname, name, canonical_name),
self._warning, stacklevel=3)
else:
warnings.warn("{}.{} is deprecated. Check CHANGES for Sphinx "
"API modifications.".format(self._modname, name),
self._warning, stacklevel=3)
return self._objects[name]
class DeprecatedDict(dict): class DeprecatedDict(dict):

View File

@ -4,13 +4,12 @@
Handlers for additional ReST directives. Handlers for additional ReST directives.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import re import re
from typing import Any, Dict, List, Tuple from typing import Any, Dict, Generic, List, Tuple, TypeVar, cast
from typing import cast
from docutils import nodes from docutils import nodes
from docutils.nodes import Node from docutils.nodes import Node
@ -18,9 +17,8 @@ from docutils.parsers.rst import directives, roles
from sphinx import addnodes from sphinx import addnodes
from sphinx.addnodes import desc_signature from sphinx.addnodes import desc_signature
from sphinx.deprecation import ( from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,
RemovedInSphinx40Warning, RemovedInSphinx50Warning, deprecated_alias deprecated_alias)
)
from sphinx.util import docutils from sphinx.util import docutils
from sphinx.util.docfields import DocFieldTransformer, Field, TypedField from sphinx.util.docfields import DocFieldTransformer, Field, TypedField
from sphinx.util.docutils import SphinxDirective from sphinx.util.docutils import SphinxDirective
@ -35,6 +33,8 @@ if False:
nl_escape_re = re.compile(r'\\\n') nl_escape_re = re.compile(r'\\\n')
strip_backslash_re = re.compile(r'\\(.)') strip_backslash_re = re.compile(r'\\(.)')
T = TypeVar('T')
def optional_int(argument: str) -> int: def optional_int(argument: str) -> int:
""" """
@ -49,7 +49,7 @@ def optional_int(argument: str) -> int:
return value return value
class ObjectDescription(SphinxDirective): class ObjectDescription(SphinxDirective, Generic[T]):
""" """
Directive to describe a class, function or similar object. Not used Directive to describe a class, function or similar object. Not used
directly, but subclassed (in domain-specific directives) to add custom directly, but subclassed (in domain-specific directives) to add custom
@ -99,7 +99,7 @@ class ObjectDescription(SphinxDirective):
else: else:
return [line.strip() for line in lines] return [line.strip() for line in lines]
def handle_signature(self, sig: str, signode: desc_signature) -> Any: def handle_signature(self, sig: str, signode: desc_signature) -> T:
""" """
Parse the signature *sig* into individual nodes and append them to Parse the signature *sig* into individual nodes and append them to
*signode*. If ValueError is raised, parsing is aborted and the whole *signode*. If ValueError is raised, parsing is aborted and the whole
@ -111,7 +111,7 @@ class ObjectDescription(SphinxDirective):
""" """
raise ValueError raise ValueError
def add_target_and_index(self, name: Any, sig: str, signode: desc_signature) -> None: def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None:
""" """
Add cross-reference IDs and entries to self.indexnode, if applicable. Add cross-reference IDs and entries to self.indexnode, if applicable.
@ -175,7 +175,7 @@ class ObjectDescription(SphinxDirective):
if self.domain: if self.domain:
node['classes'].append(self.domain) node['classes'].append(self.domain)
self.names = [] # type: List[Any] self.names = [] # type: List[T]
signatures = self.get_signatures() signatures = self.get_signatures()
for i, sig in enumerate(signatures): for i, sig in enumerate(signatures):
# add a signature node for each signature in the current unit # add a signature node for each signature in the current unit
@ -266,16 +266,10 @@ class DefaultDomain(SphinxDirective):
self.env.temp_data['default_domain'] = self.env.domains.get(domain_name) self.env.temp_data['default_domain'] = self.env.domains.get(domain_name)
return [] return []
from sphinx.directives.code import ( # noqa from sphinx.directives.code import CodeBlock, Highlight, LiteralInclude # noqa
Highlight, CodeBlock, LiteralInclude from sphinx.directives.other import (Acks, Author, Centered, Class, HList, Include, # noqa
) Only, SeeAlso, TabularColumns, TocTree, VersionChange)
from sphinx.directives.other import ( # noqa from sphinx.directives.patches import Figure, Meta # noqa
TocTree, Author, VersionChange, SeeAlso,
TabularColumns, Centered, Acks, HList, Only, Include, Class
)
from sphinx.directives.patches import ( # noqa
Figure, Meta
)
from sphinx.domains.index import IndexDirective # noqa from sphinx.domains.index import IndexDirective # noqa
deprecated_alias('sphinx.directives', deprecated_alias('sphinx.directives',
@ -298,13 +292,35 @@ deprecated_alias('sphinx.directives',
'Figure': Figure, 'Figure': Figure,
'Meta': Meta, 'Meta': Meta,
}, },
RemovedInSphinx40Warning) 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', deprecated_alias('sphinx.directives',
{ {
'DescDirective': ObjectDescription, 'DescDirective': ObjectDescription,
}, },
RemovedInSphinx50Warning) RemovedInSphinx50Warning,
{
'DescDirective': 'sphinx.directives.ObjectDescription',
})
def setup(app: "Sphinx") -> Dict[str, Any]: def setup(app: "Sphinx") -> Dict[str, Any]:

View File

@ -2,11 +2,12 @@
sphinx.directives.code sphinx.directives.code
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import sys import sys
import textwrap
import warnings import warnings
from difflib import unified_diff from difflib import unified_diff
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple
@ -19,9 +20,9 @@ from docutils.statemachine import StringList
from sphinx import addnodes from sphinx import addnodes
from sphinx.config import Config from sphinx.config import Config
from sphinx.deprecation import RemovedInSphinx40Warning from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.directives import optional_int
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging, parselinenos
from sphinx.util import parselinenos
from sphinx.util.docutils import SphinxDirective from sphinx.util.docutils import SphinxDirective
if False: if False:
@ -69,10 +70,10 @@ class HighlightLang(Highlight):
def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]: def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:
if not dedent: if not dedent:
return lines return textwrap.dedent(''.join(lines)).splitlines(True)
if any(s[:dedent].strip() for s in lines): if any(s[:dedent].strip() for s in lines):
logger.warning(__('Over dedent has detected'), location=location) logger.warning(__('non-whitespace stripped by dedent'), location=location)
new_lines = [] new_lines = []
for line in lines: for line in lines:
@ -118,7 +119,7 @@ class CodeBlock(SphinxDirective):
option_spec = { option_spec = {
'force': directives.flag, 'force': directives.flag,
'linenos': directives.flag, 'linenos': directives.flag,
'dedent': int, 'dedent': optional_int,
'lineno-start': int, 'lineno-start': int,
'emphasize-lines': directives.unchanged_required, 'emphasize-lines': directives.unchanged_required,
'caption': directives.unchanged_required, 'caption': directives.unchanged_required,
@ -227,12 +228,13 @@ class LiteralIncludeReader:
text = text.expandtabs(self.options['tab-width']) text = text.expandtabs(self.options['tab-width'])
return text.splitlines(True) return text.splitlines(True)
except OSError: except OSError as exc:
raise OSError(__('Include file %r not found or reading it failed') % filename) raise OSError(__('Include file %r not found or reading it failed') %
except UnicodeError: filename) from exc
except UnicodeError as exc:
raise UnicodeError(__('Encoding %r used for reading included file %r seems to ' raise UnicodeError(__('Encoding %r used for reading included file %r seems to '
'be wrong, try giving an :encoding: option') % 'be wrong, try giving an :encoding: option') %
(self.encoding, filename)) (self.encoding, filename)) from exc
def read(self, location: Tuple[str, int] = None) -> Tuple[str, int]: def read(self, location: Tuple[str, int] = None) -> Tuple[str, int]:
if 'diff' in self.options: if 'diff' in self.options:
@ -391,7 +393,7 @@ class LiteralInclude(SphinxDirective):
optional_arguments = 0 optional_arguments = 0
final_argument_whitespace = True final_argument_whitespace = True
option_spec = { option_spec = {
'dedent': int, 'dedent': optional_int,
'linenos': directives.flag, 'linenos': directives.flag,
'lineno-start': int, 'lineno-start': int,
'lineno-match': directives.flag, 'lineno-match': directives.flag,

View File

@ -2,13 +2,12 @@
sphinx.directives.other sphinx.directives.other
~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
import re import re
from typing import Any, Dict, List from typing import Any, Dict, List, cast
from typing import cast
from docutils import nodes from docutils import nodes
from docutils.nodes import Element, Node from docutils.nodes import Element, Node
@ -21,7 +20,7 @@ from sphinx import addnodes
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
from sphinx.domains.changeset import VersionChange # NOQA # for compatibility from sphinx.domains.changeset import VersionChange # NOQA # for compatibility
from sphinx.locale import _ from sphinx.locale import _
from sphinx.util import url_re, docname_join from sphinx.util import docname_join, url_re
from sphinx.util.docutils import SphinxDirective from sphinx.util.docutils import SphinxDirective
from sphinx.util.matching import Matcher, patfilter from sphinx.util.matching import Matcher, patfilter
from sphinx.util.nodes import explicit_title_re from sphinx.util.nodes import explicit_title_re
@ -368,7 +367,10 @@ deprecated_alias('sphinx.directives.other',
{ {
'Index': IndexDirective, 'Index': IndexDirective,
}, },
RemovedInSphinx40Warning) RemovedInSphinx40Warning,
{
'Index': 'sphinx.domains.index.IndexDirective',
})
def setup(app: "Sphinx") -> Dict[str, Any]: def setup(app: "Sphinx") -> Dict[str, Any]:

View File

@ -2,17 +2,16 @@
sphinx.directives.patches sphinx.directives.patches
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from typing import Any, Dict, List, Tuple from typing import Any, Dict, List, Tuple, cast
from typing import cast
from docutils import nodes from docutils import nodes
from docutils.nodes import Node, make_id, system_message from docutils.nodes import Node, make_id, system_message
from docutils.parsers.rst import directives from docutils.parsers.rst import directives
from docutils.parsers.rst.directives import images, html, tables from docutils.parsers.rst.directives import html, images, tables
from sphinx import addnodes from sphinx import addnodes
from sphinx.directives import optional_int from sphinx.directives import optional_int

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