mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x' into 7774_remove_develop.rst
This commit is contained in:
commit
51d500833e
@ -3,12 +3,14 @@ jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: sphinxdoc/docker-ci
|
||||
environment:
|
||||
DO_EPUBCHECK: 1
|
||||
working_directory: /sphinx
|
||||
steps:
|
||||
- checkout
|
||||
- run: /python3.6/bin/pip install -U pip setuptools
|
||||
- run: /python3.6/bin/pip install -U .[test]
|
||||
- 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:
|
||||
path: test-reports
|
||||
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
5
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -2,5 +2,8 @@
|
||||
blank_issues_enabled: false # default: true
|
||||
contact_links:
|
||||
- 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
|
||||
about: For Q&A purpose, please use sphinx-users mailing list.
|
||||
about: For general discussion, please use sphinx-users mailing list.
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -7,7 +7,7 @@ Subject: <short purpose of this pull request>
|
||||
- Critical or severe bugs: X.Y.Z
|
||||
- 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
|
||||
|
21
.github/workflows/builddoc.yml
vendored
Normal file
21
.github/workflows/builddoc.yml
vendored
Normal 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
22
.github/workflows/lint.yml
vendored
Normal 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 }}
|
61
.github/workflows/main.yml
vendored
61
.github/workflows/main.yml
vendored
@ -1,9 +1,64 @@
|
||||
name: CI on Windows
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
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
|
||||
strategy:
|
||||
matrix:
|
||||
@ -18,4 +73,4 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pip install -U tox
|
||||
- name: Run Tox
|
||||
run: tox -e py
|
||||
run: tox -e py -- -vv
|
||||
|
21
.github/workflows/nodejs.yml
vendored
Normal file
21
.github/workflows/nodejs.yml
vendored
Normal 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
8
.readthedocs.yml
Normal file
@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
python:
|
||||
version: 3
|
||||
install:
|
||||
- method: pip
|
||||
path: .
|
||||
extra_requirements:
|
||||
- docs
|
54
.travis.yml
54
.travis.yml
@ -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
596
CHANGES
@ -1,9 +1,555 @@
|
||||
Release 3.1.0 (in development)
|
||||
Release 3.5.0 (in development)
|
||||
==============================
|
||||
|
||||
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
|
||||
|
||||
Incompatible changes
|
||||
@ -51,6 +597,8 @@ Features added
|
||||
builtin base classes
|
||||
* #2106: autodoc: Support multiple signatures on docstring
|
||||
* #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
|
||||
* #7490: autosummary: Add ``:caption:`` option to autosummary directive to set a
|
||||
caption to the toctree
|
||||
@ -61,7 +609,8 @@ Features added
|
||||
variables for custom templates
|
||||
* #7530: html: Support nested <kbd> elements
|
||||
* #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
|
||||
:confval:`globaltoc_includehidden` to control the behavior of globaltoc in
|
||||
sidebar
|
||||
@ -73,6 +622,8 @@ Features added
|
||||
* #7542: html theme: Make admonition/topic/sidebar scrollable
|
||||
* #7543: html theme: Add top and bottom margins to tables
|
||||
* #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++, parse parameterized noexcept specifiers.
|
||||
* #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:`,
|
||||
:rst:dir:`py:exception:` and :rst:dir:`py:method:` directives
|
||||
* #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
|
||||
* #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
|
||||
handlers to raise specified exceptions
|
||||
* #7295: C++, parse (trailing) requires clauses.
|
||||
@ -113,6 +669,7 @@ Bugs fixed
|
||||
* #7668: autodoc: wrong retann value is passed to a handler of
|
||||
autodoc-proccess-signature
|
||||
* #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
|
||||
* #7661: autosummary: autosummary directive emits warnings twices if failed to
|
||||
import the target module
|
||||
@ -121,8 +678,12 @@ Bugs fixed
|
||||
* #7671: autosummary: The location of import failure warning is missing
|
||||
* #7535: sphinx-autogen: crashes when custom template uses inheritance
|
||||
* #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
|
||||
* #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
|
||||
* #7628: imgconverter: runs imagemagick once unnecessary for builders not
|
||||
supporting images
|
||||
@ -130,7 +691,10 @@ Bugs fixed
|
||||
* #7646: handle errors on event handlers
|
||||
* #4187: LaTeX: EN DASH disappears from PDF bookmarks in Japanese documents
|
||||
* #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
|
||||
* #7760: coverage: Add :confval:`coverage_show_missing_items` to show coverage
|
||||
result to console
|
||||
* C++, fix rendering and xrefs in nested names explicitly starting
|
||||
in global scope, e.g., ``::A::B``.
|
||||
* 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
|
||||
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)
|
||||
=====================================
|
||||
|
||||
@ -470,7 +1010,7 @@ Release 2.4.1 (released Feb 11, 2020)
|
||||
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
|
||||
|
||||
Release 2.4.0 (released Feb 09, 2020)
|
||||
@ -616,7 +1156,7 @@ Features added
|
||||
* #6548: html: Use favicon for OpenSearch if available
|
||||
* #6729: html theme: agogo theme now supports ``rightsidebar`` option
|
||||
* #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`
|
||||
* #1331: Add new config variable: :confval:`user_agent`
|
||||
* #6000: LaTeX: have backslash also be an inline literal word wrap break
|
||||
|
@ -8,10 +8,11 @@ reports/feature requests.
|
||||
|
||||
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
|
||||
``doc/internals/contributing/``
|
||||
``doc/internals/contributing.rst``
|
||||
|
||||
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.
|
||||
|
6
EXAMPLES
6
EXAMPLES
@ -230,6 +230,7 @@ Documentation using sphinx_rtd_theme
|
||||
* `MyHDL <http://docs.myhdl.org/>`__
|
||||
* `Nextflow <https://www.nextflow.io/docs/latest/index.html>`__
|
||||
* `NICOS <https://forge.frm2.tum.de/nicos/doc/nicos-master/>`__ (customized)
|
||||
* `OpenFAST <https://openfast.readthedocs.io/>`__
|
||||
* `Pelican <http://docs.getpelican.com/>`__
|
||||
* `picamera <https://picamera.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/>`__
|
||||
* `Doctrine <https://www.doctrine-project.org/>`__
|
||||
* `Enterprise Toolkit for Acrobat products <https://www.adobe.com/devnet-docs/acrobatetk/>`__
|
||||
* `FreeFEM <https://doc.freefem.org/introduction/>`__
|
||||
* `Gameduino <http://excamera.com/sphinx/gameduino/>`__
|
||||
* `gensim <https://radimrehurek.com/gensim/>`__
|
||||
* `GeoServer <http://docs.geoserver.org/>`__
|
||||
@ -330,6 +332,7 @@ Documentation using a custom theme or integrated in a website
|
||||
* `Lasso <http://lassoguide.com/>`__
|
||||
* `Mako <http://docs.makotemplates.org/>`__
|
||||
* `MirrorBrain <http://mirrorbrain.org/docs/>`__
|
||||
* `Mitiq <https://mitiq.readthedocs.io/>`__
|
||||
* `MongoDB <https://docs.mongodb.com/>`__
|
||||
* `Music21 <https://web.mit.edu/music21/doc/>`__
|
||||
* `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/>`__
|
||||
* `SaltStack <https://docs.saltstack.com/>`__
|
||||
* `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/>`__
|
||||
* `Seaborn <https://seaborn.pydata.org/>`__
|
||||
* `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)
|
||||
* `PyXLL <https://www.pyxll.com/>`__ (sphinx_bootstrap_theme, customized)
|
||||
* `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)
|
||||
* `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)
|
||||
|
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
||||
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.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
10
Makefile
10
Makefile
@ -64,17 +64,13 @@ type-check:
|
||||
doclinter:
|
||||
python utils/doclinter.py CHANGES *.rst doc/
|
||||
|
||||
.PHONY: pylint
|
||||
pylint:
|
||||
@pylint --rcfile utils/pylintrc sphinx
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@$(PYTHON) -m pytest -v $(TEST)
|
||||
@$(PYTHON) -X dev -m pytest -v $(TEST)
|
||||
|
||||
.PHONY: 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
|
||||
build:
|
||||
@ -83,6 +79,6 @@ build:
|
||||
.PHONY: docs
|
||||
docs:
|
||||
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
|
||||
$(MAKE) -C doc $(target)
|
||||
|
@ -30,6 +30,10 @@
|
||||
:target: https://opensource.org/licenses/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
|
||||
documentation for Python projects (or other documents consisting of multiple
|
||||
reStructuredText sources), written by Georg Brandl. It was originally created
|
||||
|
@ -13,3 +13,9 @@ texlive-anyfontsize [platform:rpm]
|
||||
texlive-ctablestack [platform:rpm]
|
||||
texlive-gnu-freefont [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]
|
||||
|
4
doc/_static/Makefile
vendored
4
doc/_static/Makefile
vendored
@ -1,4 +1,6 @@
|
||||
translation.png: translation.puml
|
||||
plantuml -tpng $<
|
||||
translation.svg: translation.puml
|
||||
plantuml -tsvg $<
|
||||
clean:
|
||||
rm translation.svg
|
||||
rm -f translation.png translation.svg
|
||||
|
8
doc/_static/favicon.svg
vendored
Normal file
8
doc/_static/favicon.svg
vendored
Normal 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
BIN
doc/_static/translation.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
2
doc/_static/translation.puml
vendored
2
doc/_static/translation.puml
vendored
@ -12,5 +12,5 @@ SphinxProject -r-> .rst
|
||||
.pot -r-> .po : Pootle
|
||||
.po -d-> .mo : msgfmt
|
||||
.mo -l-> TranslatedBuild
|
||||
.rst -d-> TranslatedBuild : "sphinx-buid -Dlanguage="
|
||||
.rst -d-> TranslatedBuild : "sphinx-build -Dlanguage="
|
||||
@enduml
|
||||
|
25
doc/_static/translation.svg
vendored
25
doc/_static/translation.svg
vendored
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 |
11
doc/conf.py
11
doc/conf.py
@ -4,7 +4,6 @@ import re
|
||||
|
||||
import sphinx
|
||||
|
||||
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo',
|
||||
'sphinx.ext.autosummary', 'sphinx.ext.extlinks',
|
||||
'sphinx.ext.intersphinx',
|
||||
@ -15,7 +14,7 @@ templates_path = ['_templates']
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
project = 'Sphinx'
|
||||
copyright = '2007-2020, Georg Brandl and the Sphinx team'
|
||||
copyright = '2007-2021, Georg Brandl and the Sphinx team'
|
||||
version = sphinx.__display_version__
|
||||
release = version
|
||||
show_authors = True
|
||||
@ -28,6 +27,7 @@ html_sidebars = {'index': ['indexsidebar.html', 'searchbox.html']}
|
||||
html_additional_pages = {'index': 'index.html'}
|
||||
html_use_opensearch = 'https://www.sphinx-doc.org/en/master'
|
||||
html_baseurl = 'https://www.sphinx-doc.org/en/master/'
|
||||
html_favicon = '_static/favicon.svg'
|
||||
|
||||
htmlhelp_basename = 'Sphinxdoc'
|
||||
|
||||
@ -110,9 +110,10 @@ texinfo_documents = [
|
||||
1),
|
||||
]
|
||||
|
||||
# We're not using intersphinx right now, but if we did, this would be part of
|
||||
# the mapping:
|
||||
intersphinx_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:
|
||||
locale_dirs = ['locale/']
|
||||
|
@ -10,7 +10,6 @@ Sphinx documentation contents
|
||||
development/index
|
||||
man/index
|
||||
|
||||
theming
|
||||
templating
|
||||
latex
|
||||
extdev/index
|
||||
|
34
doc/development/builders.rst
Normal file
34
doc/development/builders.rst
Normal 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
|
@ -2,12 +2,22 @@
|
||||
Extending Sphinx
|
||||
================
|
||||
|
||||
This guide is aimed at those wishing to develop their own extensions for
|
||||
Sphinx. Sphinx possesses significant extensibility capabilities including the
|
||||
ability to hook into almost every point of the build process. If you simply
|
||||
wish to use Sphinx with existing extensions, refer to :doc:`/usage/index`.
|
||||
This guide is aimed at giving a quick introduction for those wishing to
|
||||
develop their own extensions for Sphinx. Sphinx possesses significant
|
||||
extensibility capabilities including the ability to hook into almost every
|
||||
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::
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
tutorials/index
|
||||
builders
|
||||
|
||||
.. toctree::
|
||||
:caption: Theming
|
||||
:maxdepth: 2
|
||||
|
||||
theming
|
||||
|
32
doc/development/overview.rst
Normal file
32
doc/development/overview.rst
Normal 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
336
doc/development/theming.rst
Normal 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.
|
@ -4,8 +4,7 @@ from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.domains import Domain
|
||||
from sphinx.domains import Index
|
||||
from sphinx.domains import Domain, Index
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.util.nodes import make_refnode
|
||||
|
||||
|
@ -61,6 +61,13 @@ def purge_todos(app, env, 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):
|
||||
if not app.config.todo_include_todos:
|
||||
for node in doctree.traverse(todo):
|
||||
@ -119,6 +126,7 @@ def setup(app):
|
||||
app.add_directive('todolist', TodolistDirective)
|
||||
app.connect('doctree-resolved', process_todo_nodes)
|
||||
app.connect('env-purge-doc', purge_todos)
|
||||
app.connect('env-merge-info', merge_todos)
|
||||
|
||||
return {
|
||||
'version': '0.1',
|
||||
|
@ -1,8 +1,11 @@
|
||||
.. _extension-tutorials-index:
|
||||
|
||||
Extension tutorials
|
||||
===================
|
||||
|
||||
Refer to the following tutorials to get started with extension development.
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Directive tutorials
|
||||
:maxdepth: 1
|
||||
|
@ -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
|
||||
entries make it into the output.
|
||||
|
||||
* New event handlers: one for the :event:`doctree-resolved` event, to replace
|
||||
the todo and todolist nodes, and one for :event:`env-purge-doc` (the reason
|
||||
for that will be covered later).
|
||||
* New event handlers: one for the :event:`doctree-resolved` event, to
|
||||
replace the todo and todolist nodes, one for :event:`env-merge-info`
|
||||
to merge intermediate results from parallel builds, and one for
|
||||
:event:`env-purge-doc` (the reason for that will be covered later).
|
||||
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
.. literalinclude:: examples/todo.py
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 64-103
|
||||
:lines: 71-113
|
||||
|
||||
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
|
||||
@ -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
|
||||
entry, containing text that gives the location, and a link (reference node
|
||||
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)
|
||||
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
|
||||
:language: python
|
||||
:linenos:
|
||||
:lines: 106-
|
||||
:lines: 116-
|
||||
|
||||
The calls in this function refer to the classes and functions we added earlier.
|
||||
What the individual calls do is the following:
|
||||
|
@ -25,75 +25,75 @@ package.
|
||||
|
||||
.. 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
|
||||
|
||||
@ -107,9 +107,9 @@ Emitting events
|
||||
.. class:: Sphinx
|
||||
:noindex:
|
||||
|
||||
.. automethod:: emit(event, \*arguments)
|
||||
.. automethod:: emit
|
||||
|
||||
.. automethod:: emit_firstresult(event, \*arguments)
|
||||
.. automethod:: emit_firstresult
|
||||
|
||||
|
||||
Sphinx runtime information
|
||||
@ -157,6 +157,42 @@ connect handlers to the events. Example:
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
.. 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)
|
||||
|
||||
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
|
||||
``'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
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
|
@ -26,6 +26,167 @@ The following is a list of deprecated interfaces.
|
||||
- (will be) Removed
|
||||
- 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
|
||||
``sphinx.ext.autosummary.generate.AutosummaryRenderer`` has been changed
|
||||
to Sphinx object
|
||||
|
@ -1,7 +1,7 @@
|
||||
.. _domain-api:
|
||||
|
||||
Domain API
|
||||
----------
|
||||
==========
|
||||
|
||||
.. module:: sphinx.domains
|
||||
|
||||
@ -12,3 +12,16 @@ Domain API
|
||||
|
||||
.. autoclass:: Index
|
||||
:members:
|
||||
|
||||
|
||||
Python Domain
|
||||
-------------
|
||||
|
||||
.. module:: sphinx.domains.python
|
||||
|
||||
.. autoclass:: PythonDomain
|
||||
|
||||
.. autoattribute:: objects
|
||||
.. autoattribute:: modules
|
||||
.. automethod:: note_object
|
||||
.. automethod:: note_module
|
||||
|
@ -3,54 +3,41 @@
|
||||
Developing extensions for Sphinx
|
||||
================================
|
||||
|
||||
Since many projects will need special features in their documentation, Sphinx is
|
||||
designed to be extensible on several levels.
|
||||
Since many projects will need special features in their documentation, Sphinx
|
||||
is designed to be extensible on several levels.
|
||||
|
||||
This is what you can do in an extension: First, you can add new
|
||||
: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.
|
||||
Here are a few things you can do in an extension:
|
||||
|
||||
An extension is simply a Python module. When an extension is loaded, Sphinx
|
||||
imports this module and executes its ``setup()`` function, which in turn
|
||||
notifies Sphinx of everything the extension offers -- see the extension tutorial
|
||||
for examples.
|
||||
* Add new :term:`builder`\s to support new output formats or actions on the
|
||||
parsed documents.
|
||||
* Register custom reStructuredText roles and directives, extending the markup
|
||||
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
|
||||
``setup()`` function. All other extensions to load must be listed in the
|
||||
:confval:`extensions` configuration value.
|
||||
An extension is simply a Python module with a ``setup()`` function. A user
|
||||
activates the extension by placing the extension's module name
|
||||
(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
|
||||
that they do not have to be listed in the :confval:`extensions` configuration
|
||||
value.
|
||||
The configuration file itself can be treated as an extension if it
|
||||
contains a ``setup()`` function. All other extensions to load must 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``::
|
||||
|
||||
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
|
||||
The rest of this page describes some high-level aspects of developing
|
||||
extensions and various parts of Sphinx's behavior that you can control.
|
||||
For some examples of how extensions can be built and used to control different
|
||||
parts of Sphinx, see the :ref:`extension-tutorials-index`.
|
||||
|
||||
.. _important-objects:
|
||||
|
||||
@ -192,6 +179,11 @@ as metadata of the extension. Metadata keys currently recognized are:
|
||||
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::
|
||||
:maxdepth: 2
|
||||
|
||||
|
@ -9,8 +9,8 @@ Glossary
|
||||
A class (inheriting from :class:`~sphinx.builders.Builder`) that takes
|
||||
parsed documents and performs an action on them. Normally, builders
|
||||
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
|
||||
documentation, or build coverage information.
|
||||
use builders that e.g. check for broken links in the documentation, or
|
||||
build coverage information.
|
||||
|
||||
See :doc:`/usage/builders/index` for an overview over Sphinx's built-in
|
||||
builders.
|
||||
|
@ -12,6 +12,9 @@ Getting help
|
||||
|
||||
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>
|
||||
Mailing list for user support.
|
||||
|
||||
@ -21,6 +24,7 @@ sphinx-dev <sphinx-dev@googlegroups.com>
|
||||
#sphinx-doc on irc.freenode.net
|
||||
IRC channel for development questions and user support.
|
||||
|
||||
.. _python-sphinx: https://stackoverflow.com/questions/tagged/python-sphinx
|
||||
|
||||
Bug Reports and Feature Requests
|
||||
--------------------------------
|
||||
@ -134,10 +138,7 @@ Coding style
|
||||
|
||||
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
|
||||
`Pocoo Styleguide`__ for more information.
|
||||
|
||||
__ http://flask.pocoo.org/docs/styleguide/
|
||||
* Try to use the same code style as used in the rest of the project.
|
||||
|
||||
* For non-trivial changes, please update the :file:`CHANGES` file. If your
|
||||
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``.
|
||||
|
||||
The Sphinx core messages can also be translated on `Transifex
|
||||
<https://www.transifex.com/sphinx-doc/>`_. There ``tx`` client tool, which is
|
||||
provided by the ``transifex_client`` Python package, can be used to pull
|
||||
translations in ``.po`` format from Transifex. To do this, go to
|
||||
<https://www.transifex.com/sphinx-doc/sphinx-1/>`_. There ``tx`` client tool,
|
||||
which is provided by the ``transifex_client`` Python package, can be used 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
|
||||
existing language identifier. It is good practice to run ``python setup.py
|
||||
update_catalog`` afterwards to make sure the ``.po`` file has the canonical
|
||||
|
@ -95,6 +95,12 @@ Keys that you may want to override include:
|
||||
A string which will be positioned early in the preamble, designed to
|
||||
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: ``''``
|
||||
|
||||
.. versionadded:: 1.4
|
||||
|
@ -20,7 +20,7 @@ Options
|
||||
|
||||
.. 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.
|
||||
|
||||
.. option:: -h, --help, --version
|
||||
@ -33,6 +33,10 @@ Options
|
||||
|
||||
If specified, separate source and build directories.
|
||||
|
||||
.. option:: --no-sep
|
||||
|
||||
If specified, create build directroy under source directroy.
|
||||
|
||||
.. option:: --dot=DOT
|
||||
|
||||
Inside the root directory, two more directories will be created;
|
||||
|
@ -7,7 +7,7 @@ Templating
|
||||
==========
|
||||
|
||||
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
|
||||
excellent documentation for those who need to make themselves familiar with it.
|
||||
|
||||
|
159
doc/theming.rst
159
doc/theming.rst
@ -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.
|
@ -6,10 +6,10 @@ Internationalization
|
||||
.. versionadded:: 1.1
|
||||
|
||||
Complementary to translations provided for Sphinx-generated messages such as
|
||||
navigation bars, Sphinx provides mechanisms facilitating *document* translations
|
||||
in itself. See the :ref:`intl-options` for details on configuration.
|
||||
navigation bars, Sphinx provides mechanisms facilitating the translation of
|
||||
*documents*. See the :ref:`intl-options` for details on configuration.
|
||||
|
||||
.. figure:: /_static/translation.svg
|
||||
.. figure:: /_static/translation.*
|
||||
:width: 100%
|
||||
|
||||
Workflow visualization of translations in Sphinx. (The figure is created by
|
||||
|
@ -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.
|
||||
|
||||
.. versionchanged:: 3.4
|
||||
|
||||
The linkcheck builder retries links when servers apply rate limits.
|
||||
|
||||
.. module:: sphinx.builders.xml
|
||||
.. class:: XMLBuilder
|
||||
|
||||
|
@ -70,9 +70,14 @@ Project information
|
||||
The author name(s) of the document. The default value is ``'unknown'``.
|
||||
|
||||
.. confval:: copyright
|
||||
.. confval:: project_copyright
|
||||
|
||||
A copyright statement in the style ``'2008, Author Name'``.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
As an alias, ``project_copyright`` is also allowed.
|
||||
|
||||
.. confval:: version
|
||||
|
||||
The major project version, used as the replacement for ``|version|``. For
|
||||
@ -316,6 +321,7 @@ General configuration
|
||||
* ``toc.circular``
|
||||
* ``toc.secnum``
|
||||
* ``epub.unknown_project_files``
|
||||
* ``epub.duplicated_toc_entry``
|
||||
* ``autosectionlabel.*``
|
||||
|
||||
You can choose from these types.
|
||||
@ -340,6 +346,10 @@ General configuration
|
||||
|
||||
Added ``autosectionlabel.*``
|
||||
|
||||
.. versionchanged:: 3.3.0
|
||||
|
||||
Added ``epub.duplicated_toc_entry``
|
||||
|
||||
.. confval:: needs_sphinx
|
||||
|
||||
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
|
||||
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
|
||||
format for the selected locale).
|
||||
|
||||
@ -572,12 +582,27 @@ General configuration
|
||||
|
||||
.. confval:: highlight_options
|
||||
|
||||
A dictionary of options that modify how the lexer specified by
|
||||
:confval:`highlight_language` generates highlighted source code. These are
|
||||
lexer-specific; for the options understood by each, see the
|
||||
`Pygments documentation <https://pygments.org/docs/lexers>`_.
|
||||
A dictionary that maps language names to options for the lexer modules of
|
||||
Pygments. These are lexer-specific; for the options understood by each,
|
||||
see the `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
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Allow to configure highlight options for multiple languages
|
||||
|
||||
.. 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
|
||||
substitute individual paragraphs from your documents with the translation
|
||||
sets obtained from :confval:`locale_dirs`. Sphinx will search
|
||||
language-specific figures named by `figure_language_filename` and substitute
|
||||
them for original figures. In the LaTeX 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.
|
||||
language-specific figures named by :confval:`figure_language_filename`
|
||||
(e.g. the German version of ``myfigure.png`` will be ``myfigure.de.png``
|
||||
by default setting) and substitute them for original figures. In the LaTeX
|
||||
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
|
||||
|
||||
@ -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
|
||||
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
|
||||
domain. With this option set to ``False``, it is ``markup/code``.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
The string value is now accepted.
|
||||
|
||||
.. confval:: gettext_uuid
|
||||
|
||||
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``
|
||||
* ``{path}`` - the directory path component of the filename, with a trailing
|
||||
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
|
||||
components, e.g. ``filename``
|
||||
* ``{ext}`` - the file extension, e.g. ``.png``
|
||||
@ -833,6 +867,9 @@ documentation on :ref:`intl` for details.
|
||||
.. versionchanged:: 1.5
|
||||
Added ``{path}`` and ``{basename}`` tokens.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
Added ``{docpath}`` token.
|
||||
|
||||
|
||||
.. _math-options:
|
||||
|
||||
@ -912,7 +949,7 @@ that use Sphinx's HTMLWriter class.
|
||||
|
||||
.. 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
|
||||
:confval:`html_title`.
|
||||
|
||||
@ -920,11 +957,23 @@ that use Sphinx's HTMLWriter class.
|
||||
|
||||
.. confval:: html_baseurl
|
||||
|
||||
The URL which points to the root of the HTML documentation. It is used to
|
||||
indicate the location of document like ``canonical_url``.
|
||||
The base URL which points to the root of the HTML documentation. It is used
|
||||
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
|
||||
|
||||
.. 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
|
||||
|
||||
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',
|
||||
('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
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Support priority attribute
|
||||
|
||||
.. confval:: html_js_files
|
||||
|
||||
@ -986,7 +1042,14 @@ that use Sphinx's HTMLWriter class.
|
||||
'https://example.com/scripts/custom.js',
|
||||
('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
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Support priority attribute
|
||||
|
||||
.. 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.
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
.. confval:: man_make_section_directory
|
||||
|
||||
If true, make a section directory on build man page. Default is False.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
|
||||
.. _texinfo-options:
|
||||
|
||||
@ -2390,6 +2476,32 @@ Options for the linkcheck builder
|
||||
|
||||
.. 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
|
||||
|
||||
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
|
||||
|
||||
.. 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
|
||||
---------------------------
|
||||
@ -2509,6 +2638,23 @@ Options for the C domain
|
||||
|
||||
.. 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:
|
||||
|
||||
|
@ -136,15 +136,28 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
:undoc-members:
|
||||
|
||||
* "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
|
||||
.. versionchanged:: 3.2
|
||||
The option can now take arguments.
|
||||
|
||||
* autodoc considers a member private if its docstring contains
|
||||
``:meta private:`` in its :ref:`info-field-lists`.
|
||||
For example:
|
||||
|
||||
.. code-block:: rst
|
||||
.. code-block:: python
|
||||
|
||||
def my_function(my_arg, my_other_arg):
|
||||
"""blah blah blah
|
||||
@ -159,7 +172,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
an underscore.
|
||||
For example:
|
||||
|
||||
.. code-block:: rst
|
||||
.. code-block:: python
|
||||
|
||||
def _my_function(my_arg, my_other_arg):
|
||||
"""blah blah blah
|
||||
@ -169,6 +182,16 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
|
||||
|
||||
.. 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
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
* 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
|
||||
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
|
||||
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
|
||||
into a comment with special formatting (using a ``#:`` to start the comment
|
||||
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.
|
||||
.. versionchanged:: 2.0
|
||||
:rst:dir:`autodecorator` added.
|
||||
.. versionchanged:: 3.4
|
||||
:rst:dir:`autodata` and :rst:dir:`autoattribute` now have a ``no-value``
|
||||
option.
|
||||
|
||||
.. note::
|
||||
|
||||
@ -496,6 +537,44 @@ There are also config values that you can set:
|
||||
|
||||
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
|
||||
|
||||
This value controls the behavior of :option:`sphinx-build -W` during
|
||||
|
@ -175,7 +175,7 @@ also use these config values:
|
||||
|
||||
.. 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).
|
||||
|
||||
.. versionadded:: 3.0
|
||||
@ -195,6 +195,15 @@ also use these config values:
|
||||
|
||||
.. 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
|
||||
---------------------
|
||||
@ -295,7 +304,7 @@ The following variables available in the templates:
|
||||
.. data:: modules
|
||||
|
||||
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
|
||||
|
||||
|
@ -51,4 +51,11 @@ should check:
|
||||
|
||||
.. versionadded:: 1.1
|
||||
|
||||
.. 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
|
@ -67,7 +67,7 @@ a comma-separated list of group names.
|
||||
default set of flags is specified by the :confval:`doctest_default_flags`
|
||||
configuration variable.
|
||||
|
||||
This directive supports three options:
|
||||
This directive supports five options:
|
||||
|
||||
* ``hide``, a flag option, hides the doctest block in other builders. By
|
||||
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
|
||||
|
||||
* ``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
|
||||
signal a blank line in the expected output. The ``<BLANKLINE>`` is removed
|
||||
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.
|
||||
|
||||
This directive supports one option:
|
||||
This directive supports three options:
|
||||
|
||||
* ``hide``, a flag option, hides the code block in other builders. By
|
||||
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::
|
||||
|
||||
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
|
||||
: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
|
||||
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
|
||||
(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::
|
||||
|
||||
.. testcode::
|
||||
|
@ -294,3 +294,21 @@ class ExampleClass:
|
||||
|
||||
def _private_without_docstring(self):
|
||||
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
|
@ -75,8 +75,9 @@ linking:
|
||||
A dictionary mapping unique identifiers to a tuple ``(target, inventory)``.
|
||||
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
|
||||
inventory file can be found: it can be ``None`` (at the same location as
|
||||
the base URI) or another local or HTTP URI.
|
||||
inventory file can be found: it can be ``None`` (an :file:`objects.inv` file
|
||||
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
|
||||
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
|
||||
as new objects are added to the Python documentation.
|
||||
|
||||
**Multiple target for the inventory**
|
||||
**Multiple targets for the inventory**
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
@ -120,6 +121,16 @@ linking:
|
||||
intersphinx_mapping = {'python': ('https://docs.python.org/3',
|
||||
(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
|
||||
|
||||
The maximum number of days to cache remote inventories. The default is
|
||||
|
@ -115,6 +115,7 @@ All of the following section headers are supported:
|
||||
* ``Parameters``
|
||||
* ``Return`` *(alias of Returns)*
|
||||
* ``Returns``
|
||||
* ``Raise`` *(alias of Raises)*
|
||||
* ``Raises``
|
||||
* ``References``
|
||||
* ``See Also``
|
||||
@ -122,6 +123,7 @@ All of the following section headers are supported:
|
||||
* ``Todo``
|
||||
* ``Warning``
|
||||
* ``Warnings`` *(alias of Warning)*
|
||||
* ``Warn`` *(alias of Warns)*
|
||||
* ``Warns``
|
||||
* ``Yield`` *(alias of Yields)*
|
||||
* ``Yields``
|
||||
@ -201,7 +203,8 @@ Type Annotations
|
||||
This is an alternative to expressing types directly in docstrings.
|
||||
One benefit of expressing types according to `PEP 484`_ is that
|
||||
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::
|
||||
|
||||
@ -220,6 +223,19 @@ Google style with Python 3 type annotations::
|
||||
"""
|
||||
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::
|
||||
|
||||
def func(arg1, arg2):
|
||||
@ -237,6 +253,16 @@ Google style with types in docstrings::
|
||||
"""
|
||||
return True
|
||||
|
||||
class Class:
|
||||
"""Summary line.
|
||||
|
||||
Extended description of class
|
||||
|
||||
Attributes:
|
||||
attr1 (int): Description of attr1
|
||||
attr2 (str): Description of attr2
|
||||
"""
|
||||
|
||||
.. Note::
|
||||
`Python 2/3 compatible annotations`_ aren't currently
|
||||
supported by Sphinx and won't show up in the docs.
|
||||
@ -244,6 +270,9 @@ Google style with types in docstrings::
|
||||
.. _PEP 484:
|
||||
https://www.python.org/dev/peps/pep-0484/
|
||||
|
||||
.. _PEP 526:
|
||||
https://www.python.org/dev/peps/pep-0526/
|
||||
|
||||
.. _Python 2/3 compatible annotations:
|
||||
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_param = True
|
||||
napoleon_use_rtype = True
|
||||
napoleon_type_aliases = None
|
||||
napoleon_attr_annotations = True
|
||||
|
||||
.. _Google style:
|
||||
https://google.github.io/styleguide/pyguide.html
|
||||
.. _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
|
||||
|
||||
@ -433,7 +464,7 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
|
||||
:param arg1: Description of `arg1`
|
||||
:type arg1: str
|
||||
:param arg2: Description of `arg2`, defaults to 0
|
||||
:type arg2: int, optional
|
||||
:type arg2: :class:`int`, *optional*
|
||||
|
||||
**If False**::
|
||||
|
||||
@ -478,3 +509,65 @@ sure that "sphinx.ext.napoleon" is enabled in `conf.py`::
|
||||
**If False**::
|
||||
|
||||
: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``
|
@ -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
|
||||
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
|
||||
:doc:`installation guide </usage/installation>` followed by the intro to the
|
||||
default markup format used by Sphinx, :doc:`reStucturedText
|
||||
|
@ -114,9 +114,9 @@ tables of contents. The ``toctree`` directive is the central element.
|
||||
|
||||
**Additional options**
|
||||
|
||||
You can use ``caption`` option to provide a toctree caption and you can use
|
||||
``name`` option to provide implicit target name that can be referenced by
|
||||
using :rst:role:`ref`::
|
||||
You can use the ``caption`` option to provide a toctree caption and you can
|
||||
use the ``name`` option to provide an implicit target name that can be
|
||||
referenced by using :rst:role:`ref`::
|
||||
|
||||
.. toctree::
|
||||
:caption: Table of Contents
|
||||
@ -246,7 +246,7 @@ The special document names (and pages generated for them) are:
|
||||
|
||||
* 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
|
||||
``_`` 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.'
|
||||
|
||||
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
|
||||
|
||||
.. 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
|
||||
:dedent: 4
|
||||
@ -582,6 +598,8 @@ __ http://pygments.org/docs/lexers
|
||||
some ruby code
|
||||
|
||||
.. versionadded:: 1.3
|
||||
.. versionchanged:: 3.5
|
||||
Support automatic dedent.
|
||||
|
||||
.. rst:directive:option:: force
|
||||
: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
|
||||
similar way, but the lines containing the matched string are included.
|
||||
|
||||
With lines selected using ``start-after`` it is still possible to use
|
||||
``lines``, the first allowed line having by convention the line number
|
||||
``1``.
|
||||
``start-after``/``start-at`` and ``end-before``/``end-at`` can have same string.
|
||||
``start-after``/``start-at`` filter lines before the line that contains
|
||||
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
|
||||
numbers in ``emphasize-lines`` refer to those selected lines, counted
|
||||
@ -708,6 +760,9 @@ __ http://pygments.org/docs/lexers
|
||||
.. versionchanged:: 2.1
|
||||
Added the ``force`` option.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
Support automatic dedent.
|
||||
|
||||
.. _glossary-directive:
|
||||
|
||||
Glossary
|
||||
@ -1165,20 +1220,29 @@ the definition of the symbol. There is this directive:
|
||||
the following definition. If the definition spans multiple lines, each
|
||||
continuation line must begin with a colon placed at the same column as in
|
||||
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
|
||||
distinguish different sets of production lists that belong to different
|
||||
grammars. Multiple production lists with the same *productionGroup* thus
|
||||
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
|
||||
(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`.
|
||||
However, if you have given a *productionGroup* argument you must prefix the
|
||||
Outside of the production list,
|
||||
if you have given a *productionGroup* argument you must prefix the
|
||||
token name in the cross-reference with the group name and a colon,
|
||||
e.g., "``myGroup:sum``" instead of just "``sum``".
|
||||
If the group should not be shown in the title of the link either
|
||||
|
@ -42,9 +42,22 @@ Basic Markup
|
||||
Most domains provide a number of :dfn:`object description directives`, used to
|
||||
describe specific objects provided by modules. Each directive requires one or
|
||||
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
|
||||
general index; if no index entry is desired, you can give the directive option
|
||||
flag ``:noindex:``. An example using a Python domain directive::
|
||||
the content should be the description. A domain will typically keep an
|
||||
internal index of all entites to aid cross-referencing. Typically it will
|
||||
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)
|
||||
ham(eggs)
|
||||
@ -699,6 +712,53 @@ Explicit ref: :c:var:`Data.@data.a`. Short-hand ref: :c:var:`Data.a`.
|
||||
.. 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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1038,7 +1098,7 @@ Options
|
||||
|
||||
Some directives support options:
|
||||
|
||||
- ``:noindex:``, see :ref:`basic-domain-markup`.
|
||||
- ``:noindexentry:``, see :ref:`basic-domain-markup`.
|
||||
- ``:tparam-line-spec:``, for templated declarations.
|
||||
If specified, each template parameter will be rendered on a separate line.
|
||||
|
||||
|
@ -9,7 +9,14 @@ fields marked up like this::
|
||||
|
||||
: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:
|
||||
|
||||
@ -17,11 +24,20 @@ File-wide metadata
|
||||
------------------
|
||||
|
||||
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
|
||||
other metadata. However, in Sphinx, a field list preceding any other markup is
|
||||
moved from the *docinfo* to the Sphinx environment as document metadata and is
|
||||
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.
|
||||
*docinfo* and shown on the page. However, in Sphinx, a field list preceding
|
||||
any other markup is moved from the *docinfo* to the Sphinx environment as
|
||||
document metadata, and is not 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:
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
.. _html-themes:
|
||||
|
||||
HTML
|
||||
====
|
||||
HTML Theming
|
||||
============
|
||||
|
||||
Sphinx provides a number of builders for HTML and HTML-based formats.
|
||||
|
||||
@ -21,7 +21,8 @@ Themes
|
||||
.. note::
|
||||
|
||||
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
|
||||
theme is a collection of HTML templates, stylesheet(s) and other static files.
|
||||
@ -80,7 +81,7 @@ zipfile-based theme::
|
||||
html_theme = "dotted"
|
||||
|
||||
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:
|
||||
|
||||
@ -172,6 +173,12 @@ These themes are:
|
||||
|
||||
.. 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 theme`_ is a modified "Kr" Sphinx theme from @kennethreitz
|
||||
(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,
|
||||
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__.
|
||||
|
||||
.. cssclass:: clear
|
||||
@ -357,6 +364,8 @@ sphinx-themes.org__.
|
||||
.. versionchanged:: 1.4
|
||||
**sphinx_rtd_theme** has become optional.
|
||||
|
||||
|
||||
.. __: https://pypi.org/search/?q=&o=&c=Framework+%3A%3A+Sphinx+%3A%3A+Theme
|
||||
.. __: https://github.com/search?utf8=%E2%9C%93&q=sphinx+theme&type=
|
||||
.. __: https://gitlab.com/explore?name=sphinx+theme
|
||||
.. __: https://sphinx-themes.org/
|
||||
|
28
package-lock.json
generated
28
package-lock.json
generated
@ -385,12 +385,6 @@
|
||||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
|
||||
"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": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
@ -535,14 +529,22 @@
|
||||
}
|
||||
},
|
||||
"http-proxy": {
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
|
||||
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "^3.0.0",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"follow-redirects": "^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": {
|
||||
@ -702,9 +704,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.14",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
|
||||
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
|
||||
"version": "4.17.19",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
|
||||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
|
||||
"dev": true
|
||||
},
|
||||
"log4js": {
|
||||
|
10
setup.cfg
10
setup.cfg
@ -29,9 +29,11 @@ directory = sphinx/locale/
|
||||
[flake8]
|
||||
max-line-length = 95
|
||||
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
|
||||
import-order-style = smarkets
|
||||
per-file-ignores =
|
||||
tests/*: E501
|
||||
|
||||
[flake8:local-plugins]
|
||||
extension =
|
||||
@ -39,6 +41,9 @@ extension =
|
||||
paths =
|
||||
.
|
||||
|
||||
[isort]
|
||||
line_length = 95
|
||||
|
||||
[mypy]
|
||||
python_version = 3.5
|
||||
disallow_incomplete_defs = True
|
||||
@ -55,12 +60,11 @@ filterwarnings =
|
||||
all
|
||||
ignore::DeprecationWarning:docutils.io
|
||||
ignore::DeprecationWarning:pyximport.pyximport
|
||||
ignore::ImportWarning:importlib._bootstrap
|
||||
ignore::PendingDeprecationWarning:sphinx.util.pycompat
|
||||
markers =
|
||||
sphinx
|
||||
apidoc
|
||||
setup_command
|
||||
test_params
|
||||
testpaths = tests
|
||||
|
||||
[coverage:run]
|
||||
|
18
setup.py
18
setup.py
@ -43,15 +43,15 @@ extras_require = {
|
||||
],
|
||||
'lint': [
|
||||
'flake8>=3.5.0',
|
||||
'flake8-import-order',
|
||||
'mypy>=0.770',
|
||||
'isort',
|
||||
'mypy>=0.800',
|
||||
'docutils-stubs',
|
||||
],
|
||||
'test': [
|
||||
'pytest',
|
||||
'pytest-cov',
|
||||
'html5lib',
|
||||
'typed_ast', # for py35-37
|
||||
"typed_ast; python_version < '3.8'",
|
||||
'cython',
|
||||
],
|
||||
}
|
||||
@ -76,9 +76,10 @@ class Tee:
|
||||
|
||||
|
||||
try:
|
||||
from babel.messages.pofile import read_po
|
||||
from babel.messages.frontend import compile_catalog
|
||||
from json import dump
|
||||
|
||||
from babel.messages.frontend import compile_catalog
|
||||
from babel.messages.pofile import read_po
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
@ -139,7 +140,7 @@ else:
|
||||
domain + '.js'))
|
||||
|
||||
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)
|
||||
|
||||
if catalog.fuzzy and not self.use_fuzzy:
|
||||
@ -157,13 +158,13 @@ else:
|
||||
msgid = msgid[0]
|
||||
jscatalog[msgid] = message.string
|
||||
|
||||
with open(js_file, 'wt') as outfile:
|
||||
with open(js_file, 'wt', encoding='utf8') as outfile:
|
||||
outfile.write('Documentation.addTranslations(')
|
||||
dump({
|
||||
'messages': jscatalog,
|
||||
'plural_expr': catalog.plural_expr,
|
||||
'locale': str(catalog.locale)
|
||||
}, outfile, sort_keys=True)
|
||||
}, outfile, sort_keys=True, indent=4)
|
||||
outfile.write(');')
|
||||
|
||||
cmdclass['compile_catalog'] = compile_catalog_plusjs
|
||||
@ -203,6 +204,7 @@ setup(
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
'Framework :: Setuptools Plugin',
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -32,8 +32,8 @@ if 'PYTHONWARNINGS' not in os.environ:
|
||||
warnings.filterwarnings('ignore', "'U' mode is deprecated",
|
||||
DeprecationWarning, module='docutils.io')
|
||||
|
||||
__version__ = '3.1.0+'
|
||||
__released__ = '3.1.0' # used when Sphinx builds its own docs
|
||||
__version__ = '3.5.0+'
|
||||
__released__ = '3.5.0' # used when Sphinx builds its own docs
|
||||
|
||||
#: Version info for better programmatic use.
|
||||
#:
|
||||
@ -43,7 +43,7 @@ __released__ = '3.1.0' # used when Sphinx builds its own docs
|
||||
#:
|
||||
#: .. versionadded:: 1.2
|
||||
#: 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__))
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -21,6 +21,33 @@ if False:
|
||||
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):
|
||||
"""Node which supports translation.
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -18,16 +18,17 @@ import warnings
|
||||
from collections import deque
|
||||
from io import StringIO
|
||||
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.nodes import Element, TextElement
|
||||
from docutils.parsers import Parser
|
||||
from docutils.parsers.rst import Directive, roles
|
||||
from docutils.transforms import Transform
|
||||
from pygments.lexer import Lexer
|
||||
|
||||
import sphinx
|
||||
from sphinx import package_dir, locale
|
||||
from sphinx import locale, package_dir
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.domains import Domain, Index
|
||||
@ -42,9 +43,7 @@ from sphinx.project import Project
|
||||
from sphinx.registry import SphinxComponentRegistry
|
||||
from sphinx.roles import XRefRole
|
||||
from sphinx.theming import Theme
|
||||
from sphinx.util import docutils
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import progress_message
|
||||
from sphinx.util import docutils, logging, progress_message
|
||||
from sphinx.util.build_phase import BuildPhase
|
||||
from sphinx.util.console import bold # type: ignore
|
||||
from sphinx.util.i18n import CatalogRepository
|
||||
@ -55,8 +54,10 @@ from sphinx.util.typing import RoleFunction, TitleGetter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
from docutils.nodes import Node # NOQA
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
from docutils.nodes import Node # NOQA
|
||||
|
||||
from sphinx.builders import Builder
|
||||
|
||||
|
||||
@ -134,7 +135,7 @@ class Sphinx:
|
||||
: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,
|
||||
status: IO = sys.stdout, warning: IO = sys.stderr,
|
||||
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):
|
||||
raise ApplicationError(__('Output directory (%s) is not a directory') %
|
||||
self.srcdir)
|
||||
self.outdir)
|
||||
|
||||
if self.srcdir == self.outdir:
|
||||
raise ApplicationError(__('Source directory and destination '
|
||||
@ -293,7 +294,10 @@ class Sphinx:
|
||||
if catalog.domain == 'sphinx' and catalog.is_outdated():
|
||||
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)
|
||||
if has_translation or self.config.language == 'en':
|
||||
# "en" never needs to be translated
|
||||
@ -400,9 +404,10 @@ class Sphinx:
|
||||
def require_sphinx(self, version: str) -> None:
|
||||
"""Check the Sphinx version if requested.
|
||||
|
||||
Compare *version* (which must be a ``major.minor`` version string, e.g.
|
||||
``'1.1'``) with the version of the running Sphinx, and abort the build
|
||||
when it is too old.
|
||||
Compare *version* with the version of the running Sphinx, and abort the
|
||||
build when it is too old.
|
||||
|
||||
:param version: The required version in the form of ``major.minor``.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
"""
|
||||
@ -416,11 +421,11 @@ class Sphinx:
|
||||
For details on available core events and the arguments of callback
|
||||
functions, please see :ref:`events`.
|
||||
|
||||
Registered callbacks will be invoked on event in the order of *priority* and
|
||||
registration. The priority is ascending order.
|
||||
|
||||
The method returns a "listener ID" that can be used as an argument to
|
||||
:meth:`disconnect`.
|
||||
:param event: The name of target event
|
||||
:param callback: Callback function for the event
|
||||
:param priority: The priority of the callback. The callbacks will be invoked
|
||||
in the order of *priority* in asending.
|
||||
:return: A listener ID. It can be used for :meth:`disconnect`.
|
||||
|
||||
.. versionchanged:: 3.0
|
||||
|
||||
@ -432,7 +437,10 @@ class Sphinx:
|
||||
return listener_id
|
||||
|
||||
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)
|
||||
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
|
||||
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
|
||||
|
||||
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``.
|
||||
|
||||
: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
|
||||
.. versionchanged:: 3.1
|
||||
|
||||
@ -468,8 +484,9 @@ class Sphinx:
|
||||
def add_builder(self, builder: "Type[Builder]", override: bool = False) -> None:
|
||||
"""Register a new builder.
|
||||
|
||||
*builder* must be a class that inherits from
|
||||
:class:`~sphinx.builders.Builder`.
|
||||
:param builder: A builder class
|
||||
:param override: If true, install the builder forcedly even if another builder
|
||||
is already installed as the same name
|
||||
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -493,6 +510,10 @@ class Sphinx:
|
||||
documents.
|
||||
* ``''`` 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
|
||||
Changed *rebuild* from a simple boolean (equivalent to ``''`` or
|
||||
``'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
|
||||
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
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -560,6 +586,9 @@ class Sphinx:
|
||||
Obviously, translators for which you don't specify visitor methods will
|
||||
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
|
||||
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
|
||||
: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
|
||||
"""
|
||||
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:
|
||||
"""Register a Docutils directive.
|
||||
|
||||
*name* must be the prospective directive name. *cls* is a directive
|
||||
class which inherits ``docutils.parsers.rst.Directive``. For more
|
||||
details, see `the Docutils docs
|
||||
<http://docutils.sourceforge.net/docs/howto/rst-directives.html>`_ .
|
||||
:param name: The name of directive
|
||||
:param cls: A directive class
|
||||
:param override: If true, install the directive forcedly even if another directive
|
||||
is already installed as the same name
|
||||
|
||||
For example, the (already existing) :rst:dir:`literalinclude` directive
|
||||
would be added like this:
|
||||
For example, a custom directive named ``my-directive`` would be added
|
||||
like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
|
||||
class LiteralIncludeDirective(Directive):
|
||||
class MyDirective(Directive):
|
||||
has_content = True
|
||||
required_arguments = 1
|
||||
optional_arguments = 0
|
||||
@ -628,7 +660,11 @@ class Sphinx:
|
||||
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
|
||||
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:
|
||||
"""Register a Docutils role.
|
||||
|
||||
*name* must be the role name that occurs in the source, *role* the role
|
||||
function. Refer to the `Docutils documentation
|
||||
<http://docutils.sourceforge.net/docs/howto/rst-roles.html>`_ for
|
||||
more information.
|
||||
:param name: The name of role
|
||||
:param cls: A role function
|
||||
:param override: If true, install the role forcedly even if another role is already
|
||||
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
|
||||
Add *override* keyword.
|
||||
@ -667,6 +706,9 @@ class Sphinx:
|
||||
Register a Docutils role that does nothing but wrap its contents in the
|
||||
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
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -686,6 +728,9 @@ class Sphinx:
|
||||
Make the given *domain* (which must be a class; more precisely, a
|
||||
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
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -699,6 +744,9 @@ class Sphinx:
|
||||
Like :meth:`add_directive`, but the directive is added to the 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
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -712,6 +760,9 @@ class Sphinx:
|
||||
Like :meth:`add_role`, but the role is added to the domain named
|
||||
*domain*.
|
||||
|
||||
If *override* is True, the given *role* is forcedly installed even if
|
||||
a role named as *name* is already installed.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -725,6 +776,9 @@ class Sphinx:
|
||||
Add a custom *index* class to the domain named *domain*. *index* must
|
||||
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
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -788,6 +842,9 @@ class Sphinx:
|
||||
For the role content, you have the same syntactical possibilities as
|
||||
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
|
||||
Add *override* keyword.
|
||||
"""
|
||||
@ -824,6 +881,9 @@ class Sphinx:
|
||||
(Of course, the element following the ``topic`` directive needn't be a
|
||||
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
|
||||
Add *override* keyword.
|
||||
"""
|
||||
@ -873,22 +933,24 @@ class Sphinx:
|
||||
"""
|
||||
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`."""
|
||||
warnings.warn('The app.add_javascript() is deprecated. '
|
||||
'Please use app.add_js_file() instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
self.add_js_file(filename, **kwargs)
|
||||
|
||||
def add_js_file(self, filename: str, **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.
|
||||
|
||||
Add *filename* to the list of JavaScript files that the default HTML
|
||||
template will include. The filename must be relative to the HTML
|
||||
static path , or a full URI with scheme. If the keyword argument
|
||||
``body`` is given, its value will be added between the
|
||||
``<script>`` tags. Extra keyword arguments are included as
|
||||
attributes of the ``<script>`` tag.
|
||||
template will include in order of *priority* (ascending). The filename
|
||||
must be relative to the HTML static path , or a full URI with scheme.
|
||||
If the priority of JavaScript file is the same as others, the JavaScript
|
||||
files will be included in order of the registration. If the keyword
|
||||
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::
|
||||
|
||||
@ -901,23 +963,43 @@ class Sphinx:
|
||||
app.add_js_file(None, body="var myVariable = 'foo';")
|
||||
# => <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
|
||||
|
||||
.. versionchanged:: 1.8
|
||||
Renamed from ``app.add_javascript()``.
|
||||
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.
|
||||
|
||||
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,
|
||||
or a full URI with scheme. The keyword arguments are also accepted for
|
||||
attributes of ``<link>`` tag.
|
||||
will include in order of *priority* (ascending). The filename must be
|
||||
relative to the HTML static path, or a full URI with scheme. If the
|
||||
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::
|
||||
|
||||
@ -932,6 +1014,19 @@ class Sphinx:
|
||||
# => <link rel="alternate stylesheet" href="_static/fancy.css"
|
||||
# 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
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
@ -944,11 +1039,14 @@ class Sphinx:
|
||||
.. versionchanged:: 1.8
|
||||
Renamed from ``app.add_stylesheet()``.
|
||||
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)
|
||||
self.registry.add_css_files(filename, **kwargs)
|
||||
self.registry.add_css_files(filename, priority=priority, **kwargs)
|
||||
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
|
||||
) -> None:
|
||||
@ -957,7 +1055,7 @@ class Sphinx:
|
||||
'Please use app.add_css_file() instead.',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
|
||||
attributes = {} # type: Dict[str, str]
|
||||
attributes = {} # type: Dict[str, Any]
|
||||
if alternate:
|
||||
attributes['rel'] = 'alternate stylesheet'
|
||||
else:
|
||||
@ -1004,7 +1102,7 @@ class Sphinx:
|
||||
logger.debug('[app] adding lexer: %r', (alias, lexer))
|
||||
if isinstance(lexer, Lexer):
|
||||
warnings.warn('app.add_lexer() API changed; '
|
||||
'Please give lexer class instead instance',
|
||||
'Please give lexer class instead of instance',
|
||||
RemovedInSphinx40Warning, stacklevel=2)
|
||||
lexers[alias] = lexer
|
||||
else:
|
||||
@ -1019,6 +1117,9 @@ class Sphinx:
|
||||
new types of objects. See the source of the autodoc module for
|
||||
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
|
||||
|
||||
.. versionadded:: 0.6
|
||||
@ -1057,7 +1158,7 @@ class Sphinx:
|
||||
.. versionadded:: 1.1
|
||||
"""
|
||||
logger.debug('[app] adding search language: %r', cls)
|
||||
from sphinx.search import languages, SearchLanguage
|
||||
from sphinx.search import SearchLanguage, languages
|
||||
assert issubclass(cls, SearchLanguage)
|
||||
languages[cls.lang] = cls
|
||||
|
||||
@ -1067,13 +1168,19 @@ class Sphinx:
|
||||
Same as :confval:`source_suffix`. The users can override this
|
||||
using the setting.
|
||||
|
||||
If *override* is True, the given *suffix* is forcedly installed even if
|
||||
a same suffix is already installed.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
"""
|
||||
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.
|
||||
|
||||
If *override* is True, the given *parser* is forcedly installed even if
|
||||
a parser for the same suffix is already installed.
|
||||
|
||||
.. versionadded:: 1.4
|
||||
.. versionchanged:: 1.8
|
||||
*suffix* argument is deprecated. It only accepts *parser* argument.
|
||||
@ -1081,7 +1188,7 @@ class Sphinx:
|
||||
.. versionchanged:: 1.8
|
||||
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:
|
||||
"""Register an environment collector class.
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -17,26 +17,24 @@ from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
|
||||
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.errors import SphinxError
|
||||
from sphinx.events import EventManager
|
||||
from sphinx.io import read_doc
|
||||
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.console import bold # type: ignore
|
||||
from sphinx.util.docutils import sphinx_domains
|
||||
from sphinx.util.i18n import CatalogInfo, CatalogRepository, docname_to_domain
|
||||
from sphinx.util.osutil import SEP, ensuredir, relative_uri, relpath
|
||||
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, \
|
||||
parallel_available
|
||||
from sphinx.util.parallel import ParallelTasks, SerialTasks, make_chunks, parallel_available
|
||||
from sphinx.util.tags import Tags
|
||||
|
||||
# side effect: registers roles and directives
|
||||
from sphinx import roles # noqa
|
||||
from sphinx import directives # noqa
|
||||
|
||||
from sphinx import directives # NOQA isort:skip
|
||||
from sphinx import roles # NOQA isort:skip
|
||||
try:
|
||||
import multiprocessing
|
||||
except ImportError:
|
||||
@ -45,6 +43,7 @@ except ImportError:
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -25,11 +25,10 @@ from sphinx import addnodes
|
||||
from sphinx.builders.html import BuildInfo, StandaloneHTMLBuilder
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import status_iterator
|
||||
from sphinx.util import logging, status_iterator
|
||||
from sphinx.util.fileutil import copy_asset_file
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.osutil import ensuredir, copyfile
|
||||
from sphinx.util.osutil import copyfile, ensuredir
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
@ -208,7 +207,12 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
appeared = set() # type: Set[str]
|
||||
for node in nodes:
|
||||
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:
|
||||
appeared.add(node['refuri'])
|
||||
|
||||
@ -388,7 +392,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
|
||||
return ext in VECTOR_GRAPHICS_EXTENSIONS
|
||||
|
||||
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 format and resizing the image if necessary/possible.
|
||||
"""
|
||||
|
@ -4,30 +4,33 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinxcontrib.applehelp import (
|
||||
AppleHelpCodeSigningFailed,
|
||||
AppleHelpIndexerFailed,
|
||||
AppleHelpBuilder,
|
||||
)
|
||||
from sphinxcontrib.applehelp import (AppleHelpBuilder, AppleHelpCodeSigningFailed,
|
||||
AppleHelpIndexerFailed)
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
|
||||
deprecated_alias('sphinx.builders.applehelp',
|
||||
{
|
||||
'AppleHelpCodeSigningFailed': AppleHelpCodeSigningFailed,
|
||||
'AppleHelpIndexerFailed': AppleHelpIndexerFailed,
|
||||
'AppleHelpBuilder': AppleHelpBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'AppleHelpCodeSigningFailed':
|
||||
'sphinxcontrib.applehelp.AppleHelpCodeSigningFailed',
|
||||
'AppleHelpIndexerFailed':
|
||||
'sphinxcontrib.applehelp.AppleHelpIndexerFailed',
|
||||
'AppleHelpBuilder': 'sphinxcontrib.applehelp.AppleHelpBuilder',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
@ -4,14 +4,13 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import html
|
||||
from os import path
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import cast
|
||||
from typing import Any, Dict, List, Tuple, cast
|
||||
|
||||
from sphinx import package_dir
|
||||
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.osutil import ensuredir, os_path
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
.. _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.
|
||||
"""
|
||||
|
||||
@ -18,12 +18,14 @@ from sphinxcontrib.devhelp import DevhelpBuilder
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
|
||||
deprecated_alias('sphinx.builders.devhelp',
|
||||
{
|
||||
'DevhelpBuilder': DevhelpBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'DevhelpBuilder': 'sphinxcontrib.devhelp.DevhelpBuilder'
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -51,7 +51,10 @@ deprecated_alias('sphinx.builders.html',
|
||||
{
|
||||
'DirectoryHTMLBuilder': DirectoryHTMLBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'DirectoryHTMLBuilder': 'sphinx.builders.dirhtml.DirectoryHTMLBuilder',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
Build epub3 files.
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -18,7 +18,7 @@ from typing import Any, Dict, List, Set, Tuple
|
||||
from sphinx import package_dir
|
||||
from sphinx.application import Sphinx
|
||||
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.locale import __
|
||||
from sphinx.util import logging, xmlname_checker
|
||||
|
@ -4,33 +4,32 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
from codecs import open
|
||||
from collections import defaultdict, OrderedDict
|
||||
from datetime import datetime, tzinfo, timedelta
|
||||
from os import path, walk, getenv
|
||||
from collections import OrderedDict, defaultdict
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from os import getenv, path, walk
|
||||
from time import time
|
||||
from typing import Any, Dict, Iterable, Generator, List, Set, Tuple, Union
|
||||
from typing import Any, Dict, Generator, Iterable, List, Set, Tuple, Union
|
||||
from uuid import uuid4
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx import package_dir
|
||||
from sphinx import addnodes, package_dir
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.domains.python import pairindextypes
|
||||
from sphinx.errors import ThemeError
|
||||
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.i18n import CatalogInfo, docname_to_domain
|
||||
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.template import SphinxRenderer
|
||||
|
||||
@ -278,7 +277,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
origin = MsgOrigin(template, line)
|
||||
self.catalogs['sphinx'].add(msg, origin)
|
||||
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
|
||||
self._extract_from_template()
|
||||
@ -316,7 +315,7 @@ class MessageCatalogBuilder(I18nBuilder):
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
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_uuid', False, 'gettext')
|
||||
app.add_config_value('gettext_auto_build', True, 'env')
|
||||
|
@ -4,17 +4,19 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import html
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
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.core import publish_parts
|
||||
@ -23,10 +25,10 @@ from docutils.io import DocTreeInput, StringOutput
|
||||
from docutils.nodes import Node
|
||||
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.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.domains import Domain, Index, IndexEntry
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
@ -37,15 +39,15 @@ from sphinx.highlighting import PygmentsBridge
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.search import js_index
|
||||
from sphinx.theming import HTMLThemeFactory
|
||||
from sphinx.util import logging, 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.fileutil import copy_asset
|
||||
from sphinx.util.i18n import format_date
|
||||
from sphinx.util.inventory import InventoryFile
|
||||
from sphinx.util.matching import patmatch, Matcher, DOTFILES
|
||||
from sphinx.util.osutil import os_path, relative_uri, ensuredir, movefile, copyfile
|
||||
from sphinx.util.matching import DOTFILES, Matcher, patmatch
|
||||
from sphinx.util.osutil import copyfile, ensuredir, os_path, relative_uri
|
||||
from sphinx.util.tags import Tags
|
||||
from sphinx.writers.html import HTMLWriter, HTMLTranslator
|
||||
from sphinx.writers.html import HTMLTranslator, HTMLWriter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
@ -88,10 +90,13 @@ class Stylesheet(str):
|
||||
|
||||
attributes = None # type: Dict[str, str]
|
||||
filename = None # type: str
|
||||
priority = None # type: int
|
||||
|
||||
def __new__(cls, filename: str, *args: str, **attributes: str) -> "Stylesheet":
|
||||
self = str.__new__(cls, filename) # type: ignore
|
||||
def __new__(cls, filename: str, *args: str, priority: int = 500, **attributes: Any
|
||||
) -> "Stylesheet":
|
||||
self = str.__new__(cls, filename)
|
||||
self.filename = filename
|
||||
self.priority = priority
|
||||
self.attributes = attributes
|
||||
self.attributes.setdefault('rel', 'stylesheet')
|
||||
self.attributes.setdefault('type', 'text/css')
|
||||
@ -111,10 +116,12 @@ class JavaScript(str):
|
||||
|
||||
attributes = None # type: Dict[str, str]
|
||||
filename = None # type: str
|
||||
priority = None # type: int
|
||||
|
||||
def __new__(cls, filename: str, **attributes: str) -> "JavaScript":
|
||||
self = str.__new__(cls, filename) # type: ignore
|
||||
def __new__(cls, filename: str, priority: int = 500, **attributes: str) -> "JavaScript":
|
||||
self = str.__new__(cls, filename)
|
||||
self.filename = filename
|
||||
self.priority = priority
|
||||
self.attributes = attributes
|
||||
|
||||
return self
|
||||
@ -140,7 +147,7 @@ class BuildInfo:
|
||||
build_info.tags_hash = lines[3].split()[1].strip()
|
||||
return build_info
|
||||
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
|
||||
self.config_hash = ''
|
||||
@ -288,30 +295,31 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.add_css_file(filename, **attrs)
|
||||
|
||||
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)
|
||||
|
||||
def add_css_file(self, filename: str, **kwargs: str) -> None:
|
||||
def add_css_file(self, filename: str, **kwargs: Any) -> None:
|
||||
if '://' not in filename:
|
||||
filename = posixpath.join('_static', filename)
|
||||
|
||||
self.css_files.append(Stylesheet(filename, **kwargs)) # type: ignore
|
||||
|
||||
def init_js_files(self) -> None:
|
||||
self.add_js_file('jquery.js')
|
||||
self.add_js_file('underscore.js')
|
||||
self.add_js_file('doctools.js')
|
||||
self.add_js_file('language_data.js')
|
||||
self.add_js_file('jquery.js', priority=200)
|
||||
self.add_js_file('underscore.js', priority=200)
|
||||
self.add_js_file('doctools.js', priority=200)
|
||||
|
||||
for filename, attrs in self.app.registry.js_files:
|
||||
self.add_js_file(filename, **attrs)
|
||||
|
||||
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)
|
||||
|
||||
if self.config.language and self._get_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:
|
||||
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 ''
|
||||
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()
|
||||
|
||||
rellinks = [] # type: List[Tuple[str, str, str, str]]
|
||||
@ -461,6 +466,10 @@ class StandaloneHTMLBuilder(Builder):
|
||||
rellinks.append((indexname, indexcls.localname,
|
||||
'', 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:
|
||||
stylename = self.config.html_style
|
||||
elif self.theme:
|
||||
@ -640,17 +649,17 @@ class StandaloneHTMLBuilder(Builder):
|
||||
def gen_additional_pages(self) -> None:
|
||||
# additional pages from conf.py
|
||||
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)
|
||||
|
||||
# the search page
|
||||
if self.search:
|
||||
logger.info(' search', nonl=True)
|
||||
logger.info('search ', nonl=True)
|
||||
self.handle_page('search', {}, 'search.html')
|
||||
|
||||
# the opensearch xml file
|
||||
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')
|
||||
self.handle_page('opensearch', {}, 'opensearch.xml', outfilename=fn)
|
||||
|
||||
@ -668,7 +677,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
'genindexcounts': indexcounts,
|
||||
'split_index': self.config.html_split_index,
|
||||
}
|
||||
logger.info(' genindex', nonl=True)
|
||||
logger.info('genindex ', nonl=True)
|
||||
|
||||
if self.config.html_split_index:
|
||||
self.handle_page('genindex', genindexcontext,
|
||||
@ -690,7 +699,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
'content': content,
|
||||
'collapse_index': collapse,
|
||||
}
|
||||
logger.info(' ' + indexname, nonl=True)
|
||||
logger.info(indexname + ' ', nonl=True)
|
||||
self.handle_page(indexname, indexcontext, 'domainindex.html')
|
||||
|
||||
def copy_image_files(self) -> None:
|
||||
@ -750,18 +759,27 @@ class StandaloneHTMLBuilder(Builder):
|
||||
copyfile(jsfile, path.join(self.outdir, '_static', '_stemmer.js'))
|
||||
|
||||
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:
|
||||
for entry in self.theme.get_theme_dirs()[::-1]:
|
||||
copy_asset(path.join(entry, '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 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 + ["**/.*"])
|
||||
for entry in self.config.html_static_path:
|
||||
copy_asset(path.join(self.confdir, entry),
|
||||
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:
|
||||
if self.config.html_logo:
|
||||
@ -775,7 +793,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
|
||||
def copy_static_files(self) -> None:
|
||||
try:
|
||||
with progress_message(__('copying static files... ')):
|
||||
with progress_message(__('copying static files')):
|
||||
ensuredir(path.join(self.outdir, '_static'))
|
||||
|
||||
# prepare context for templates
|
||||
@ -886,6 +904,8 @@ class StandaloneHTMLBuilder(Builder):
|
||||
def _get_local_toctree(self, docname: str, collapse: bool = True, **kwargs: Any) -> str:
|
||||
if 'includehidden' not in kwargs:
|
||||
kwargs['includehidden'] = False
|
||||
if kwargs.get('maxdepth') == '':
|
||||
kwargs.pop('maxdepth')
|
||||
return self.render_partial(TocTree(self.env).get_toctree_for(
|
||||
docname, self, collapse, **kwargs))['fragment']
|
||||
|
||||
@ -945,7 +965,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
# --------- these are overwritten by the serialization builder
|
||||
|
||||
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',
|
||||
outfilename: str = None, event_arg: Any = None) -> None:
|
||||
@ -1000,12 +1020,20 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.add_sidebars(pagename, ctx)
|
||||
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)
|
||||
newtmpl = self.app.emit_firstresult('html-page-context', pagename,
|
||||
templatename, ctx, event_arg)
|
||||
if 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:
|
||||
output = self.templates.render(templatename, ctx)
|
||||
except UnicodeError:
|
||||
@ -1015,7 +1043,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
return
|
||||
except Exception as exc:
|
||||
raise ThemeError(__("An error happened in rendering the page %s.\nReason: %r") %
|
||||
(pagename, exc))
|
||||
(pagename, exc)) from exc
|
||||
|
||||
if not outfilename:
|
||||
outfilename = self.get_outfilename(pagename)
|
||||
@ -1059,7 +1087,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
else:
|
||||
with open(searchindexfn + '.tmp', 'wb') as fb:
|
||||
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:
|
||||
@ -1177,10 +1205,21 @@ def validate_html_favicon(app: Sphinx, config: Config) -> None:
|
||||
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
|
||||
import sphinxcontrib.serializinghtml # NOQA
|
||||
|
||||
import sphinx.builders.dirhtml # NOQA
|
||||
import sphinx.builders.singlehtml # NOQA
|
||||
import sphinxcontrib.serializinghtml # NOQA
|
||||
|
||||
|
||||
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_additional_pages', {}, 'html')
|
||||
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_split_index', False, '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_scaled_image_link', True, '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('html4_writer', False, 'html')
|
||||
|
||||
# events
|
||||
app.add_event('html-collect-pages')
|
||||
app.add_event('html-page-context')
|
||||
|
||||
# event handlers
|
||||
app.connect('config-inited', convert_html_css_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_static_path, priority=800)
|
||||
app.connect('config-inited', validate_html_logo, priority=800)
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from docutils import nodes
|
||||
|
||||
@ -28,7 +28,7 @@ class KeyboardTransform(SphinxPostTransform):
|
||||
|
||||
After::
|
||||
|
||||
<literal class="kbd">
|
||||
<literal class="kbd compound">
|
||||
<literal class="kbd">
|
||||
Control
|
||||
-
|
||||
@ -37,17 +37,29 @@ class KeyboardTransform(SphinxPostTransform):
|
||||
"""
|
||||
default_priority = 400
|
||||
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:
|
||||
matcher = NodeMatcher(nodes.literal, classes=["kbd"])
|
||||
for node in self.document.traverse(matcher): # type: nodes.literal
|
||||
parts = self.pattern.split(node[-1].astext())
|
||||
if len(parts) == 1:
|
||||
if len(parts) == 1 or self.is_multiwords_key(parts):
|
||||
continue
|
||||
|
||||
node['classes'].append('compound')
|
||||
node.pop()
|
||||
while parts:
|
||||
if self.is_multiwords_key(parts):
|
||||
key = ''.join(parts[:3])
|
||||
parts[:3] = []
|
||||
else:
|
||||
key = parts.pop(0)
|
||||
node += nodes.literal('', key, classes=["kbd"])
|
||||
|
||||
@ -58,6 +70,16 @@ class KeyboardTransform(SphinxPostTransform):
|
||||
except IndexError:
|
||||
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]:
|
||||
app.add_post_transform(KeyboardTransform)
|
||||
|
@ -5,21 +5,19 @@
|
||||
Build HTML help support files.
|
||||
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.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from typing import Any, Dict
|
||||
|
||||
from sphinxcontrib.htmlhelp import (
|
||||
chm_locales, chm_htmlescape, HTMLHelpBuilder, default_htmlhelp_basename
|
||||
)
|
||||
from sphinxcontrib.htmlhelp import (HTMLHelpBuilder, chm_htmlescape, chm_locales,
|
||||
default_htmlhelp_basename)
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
|
||||
deprecated_alias('sphinx.builders.htmlhelp',
|
||||
{
|
||||
'chm_locales': chm_locales,
|
||||
@ -27,7 +25,14 @@ deprecated_alias('sphinx.builders.htmlhelp',
|
||||
'HTMLHelpBuilder': HTMLHelpBuilder,
|
||||
'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]:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -17,18 +17,18 @@ from docutils.frontend import OptionParser
|
||||
from docutils.nodes import Node
|
||||
|
||||
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.builders import Builder
|
||||
from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, SHORTHANDOFF
|
||||
from sphinx.builders.latex.theming import Theme, ThemeFactory
|
||||
from sphinx.builders.latex.util import ExtBabel
|
||||
from sphinx.config import Config, ENUM
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.config import ENUM, Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, RemovedInSphinx50Warning
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.errors import NoUri, SphinxError
|
||||
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.docutils import SphinxFileOutput, new_document
|
||||
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.osutil import SEP, make_filename_from_project
|
||||
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
|
||||
from docutils import nodes # NOQA
|
||||
|
||||
from docutils import nodes # isort:skip
|
||||
|
||||
XINDY_LANG_OPTIONS = {
|
||||
# language codes from docutils.writers.latex2e.Babel
|
||||
@ -128,8 +127,6 @@ class LaTeXBuilder(Builder):
|
||||
self.docnames = [] # type: Iterable[str]
|
||||
self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]]
|
||||
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()
|
||||
|
||||
self.init_context()
|
||||
@ -179,10 +176,6 @@ class LaTeXBuilder(Builder):
|
||||
key = (self.config.latex_engine, self.config.language[:2])
|
||||
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
|
||||
self.context.update(self.config.latex_elements)
|
||||
self.context['release'] = self.config.release
|
||||
@ -203,6 +196,13 @@ class LaTeXBuilder(Builder):
|
||||
# Show the release label only if release value exists
|
||||
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:
|
||||
self.babel = ExtBabel(self.config.language, not self.context['babel'])
|
||||
if self.config.language and not self.babel.is_supported_language():
|
||||
@ -290,6 +290,7 @@ class LaTeXBuilder(Builder):
|
||||
doctree['tocdepth'] = tocdepth
|
||||
self.post_process_images(doctree)
|
||||
self.update_doc_context(title, author, theme)
|
||||
self.update_context()
|
||||
|
||||
with progress_message(__("writing")):
|
||||
docsettings._author = author
|
||||
@ -448,6 +449,18 @@ class LaTeXBuilder(Builder):
|
||||
filename = path.join(package_dir, 'templates', 'latex', 'sphinxmessages.sty_t')
|
||||
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:
|
||||
"""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)
|
||||
|
||||
|
||||
def install_pakcages_for_ja(app: Sphinx) -> None:
|
||||
def install_packages_for_ja(app: Sphinx) -> None:
|
||||
"""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)
|
||||
|
||||
|
||||
@ -556,7 +569,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_builder(LaTeXBuilder)
|
||||
app.connect('config-inited', validate_config_values, 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,
|
||||
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex'))
|
||||
|
@ -4,13 +4,12 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
PDFLATEX_DEFAULT_FONTPKG = r'''
|
||||
\usepackage{times}
|
||||
\expandafter\ifx\csname T@LGR\endcsname\relax
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -87,10 +87,12 @@ class UserTheme(Theme):
|
||||
try:
|
||||
value = self.config.get('theme', key)
|
||||
setattr(self, key, value)
|
||||
except configparser.NoSectionError:
|
||||
raise ThemeError(__('%r doesn\'t have "theme" setting') % filename)
|
||||
except configparser.NoSectionError as exc:
|
||||
raise ThemeError(__('%r doesn\'t have "theme" setting') %
|
||||
filename) from 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:
|
||||
try:
|
||||
|
@ -4,21 +4,20 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Set, Tuple
|
||||
from typing import cast
|
||||
from typing import Any, Dict, List, Set, Tuple, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
from docutils.transforms.references import Substitutions
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders.latex.nodes import (
|
||||
captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography
|
||||
)
|
||||
from sphinx.builders.latex.nodes import (captioned_literal_block, footnotemark, footnotetext,
|
||||
math_reference, thebibliography)
|
||||
from sphinx.domains.citation import CitationDomain
|
||||
from sphinx.transforms import SphinxTransform
|
||||
from sphinx.transforms.post_transforms import SphinxPostTransform
|
||||
@ -38,6 +37,18 @@ class FootnoteDocnameUpdater(SphinxTransform):
|
||||
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):
|
||||
"""Expand references to inline text or footnotes.
|
||||
|
||||
@ -602,6 +613,7 @@ class IndexInSectionTitleTransform(SphinxTransform):
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_transform(FootnoteDocnameUpdater)
|
||||
app.add_post_transform(SubstitutionDefinitionsRemover)
|
||||
app.add_post_transform(BibliographyTransform)
|
||||
app.add_post_transform(CitationReferenceTransform)
|
||||
app.add_post_transform(DocumentTargetTransform)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -13,28 +13,56 @@ import queue
|
||||
import re
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import warnings
|
||||
from datetime import datetime, timezone
|
||||
from email.utils import parsedate_to_datetime
|
||||
from html.parser import HTMLParser
|
||||
from os import path
|
||||
from typing import Any, Dict, List, Set, Tuple
|
||||
from urllib.parse import unquote
|
||||
from typing import Any, Dict, List, NamedTuple, Optional, Set, Tuple, cast
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
from requests.exceptions import HTTPError
|
||||
from docutils.nodes import Element
|
||||
from requests import Response
|
||||
from requests.exceptions import HTTPError, TooManyRedirects
|
||||
|
||||
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.util import encode_uri, requests, logging
|
||||
from sphinx.util.console import ( # type: ignore
|
||||
purple, red, darkgreen, darkgray, turquoise
|
||||
)
|
||||
from sphinx.transforms.post_transforms import SphinxPostTransform
|
||||
from sphinx.util import encode_uri, logging, requests
|
||||
from sphinx.util.console import darkgray, darkgreen, purple, red, turquoise # type: ignore
|
||||
from sphinx.util.nodes import get_node_line
|
||||
from sphinx.util.requests import is_ssl_error
|
||||
|
||||
|
||||
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):
|
||||
"""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
|
||||
|
||||
|
||||
class CheckExternalLinksBuilder(Builder):
|
||||
class CheckExternalLinksBuilder(DummyBuilder):
|
||||
"""
|
||||
Checks for broken external links.
|
||||
"""
|
||||
@ -79,14 +107,15 @@ class CheckExternalLinksBuilder(Builder):
|
||||
'%(outdir)s/output.txt')
|
||||
|
||||
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.anchors_ignore = [re.compile(x)
|
||||
for x in self.app.config.linkcheck_anchors_ignore]
|
||||
self.auth = [(re.compile(pattern), auth_info) for pattern, auth_info
|
||||
in self.app.config.linkcheck_auth]
|
||||
self.good = set() # type: Set[str]
|
||||
self.broken = {} # type: Dict[str, str]
|
||||
self.redirected = {} # type: Dict[str, Tuple[str, int]]
|
||||
self._good = set() # type: Set[str]
|
||||
self._broken = {} # type: Dict[str, str]
|
||||
self._redirected = {} # type: Dict[str, Tuple[str, int]]
|
||||
# set a timeout for non-responding servers
|
||||
socket.setdefaulttimeout(5.0)
|
||||
# create output file
|
||||
@ -95,25 +124,62 @@ class CheckExternalLinksBuilder(Builder):
|
||||
open(path.join(self.outdir, 'output.json'), 'w').close()
|
||||
|
||||
# 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.workers = [] # type: List[threading.Thread]
|
||||
for i in range(self.app.config.linkcheck_workers):
|
||||
thread = threading.Thread(target=self.check_thread)
|
||||
thread.setDaemon(True)
|
||||
thread = threading.Thread(target=self.check_thread, daemon=True)
|
||||
thread.start()
|
||||
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:
|
||||
kwargs = {
|
||||
'allow_redirects': True,
|
||||
'headers': {
|
||||
'Accept': 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',
|
||||
},
|
||||
}
|
||||
kwargs = {}
|
||||
if 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]:
|
||||
# split off anchor
|
||||
if '#' in uri:
|
||||
@ -139,11 +205,15 @@ class CheckExternalLinksBuilder(Builder):
|
||||
else:
|
||||
auth_info = None
|
||||
|
||||
# update request headers for the URL
|
||||
kwargs['headers'] = get_request_headers()
|
||||
|
||||
try:
|
||||
if anchor and self.app.config.linkcheck_anchors:
|
||||
# Read the whole document and see if #anchor exists
|
||||
response = requests.get(req_url, stream=True, config=self.app.config,
|
||||
auth=auth_info, **kwargs)
|
||||
response.raise_for_status()
|
||||
found = check_anchor(response, unquote(anchor))
|
||||
|
||||
if not found:
|
||||
@ -152,29 +222,42 @@ class CheckExternalLinksBuilder(Builder):
|
||||
try:
|
||||
# try a HEAD request first, which should be easier on
|
||||
# the server and the network
|
||||
response = requests.head(req_url, config=self.app.config,
|
||||
auth=auth_info, **kwargs)
|
||||
response = requests.head(req_url, allow_redirects=True,
|
||||
config=self.app.config, auth=auth_info,
|
||||
**kwargs)
|
||||
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
|
||||
# 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)
|
||||
response.raise_for_status()
|
||||
except HTTPError as err:
|
||||
if err.response.status_code == 401:
|
||||
# We'll take "Unauthorized" as working.
|
||||
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:
|
||||
# We'll take "Service Unavailable" as ignored.
|
||||
return 'ignored', str(err), 0
|
||||
else:
|
||||
return 'broken', str(err), 0
|
||||
except Exception as err:
|
||||
if is_ssl_error(err):
|
||||
return 'ignored', str(err), 0
|
||||
else:
|
||||
return 'broken', str(err), 0
|
||||
else:
|
||||
netloc = urlparse(req_url).netloc
|
||||
try:
|
||||
del self.rate_limits[netloc]
|
||||
except KeyError:
|
||||
pass
|
||||
if response.url.rstrip('/') == req_url.rstrip('/'):
|
||||
return 'working', '', 0
|
||||
else:
|
||||
@ -188,18 +271,31 @@ class CheckExternalLinksBuilder(Builder):
|
||||
else:
|
||||
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
|
||||
if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'ftp:')):
|
||||
if len(uri) == 0 or uri.startswith(('#', 'mailto:', 'tel:')):
|
||||
return 'unchecked', '', 0
|
||||
elif not uri.startswith(('http:', 'https:')):
|
||||
return 'local', '', 0
|
||||
elif uri in self.good:
|
||||
if uri_re.match(uri):
|
||||
# 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
|
||||
elif uri in self.broken:
|
||||
return 'broken', self.broken[uri], 0
|
||||
elif uri in self.redirected:
|
||||
return 'redirected', self.redirected[uri][0], self.redirected[uri][1]
|
||||
elif uri in self._broken:
|
||||
return 'broken', self._broken[uri], 0
|
||||
elif uri in self._redirected:
|
||||
return 'redirected', self._redirected[uri][0], self._redirected[uri][1]
|
||||
for rex in self.to_ignore:
|
||||
if rex.match(uri):
|
||||
return 'ignored', '', 0
|
||||
@ -211,20 +307,78 @@ class CheckExternalLinksBuilder(Builder):
|
||||
break
|
||||
|
||||
if status == "working":
|
||||
self.good.add(uri)
|
||||
self._good.add(uri)
|
||||
elif status == "broken":
|
||||
self.broken[uri] = info
|
||||
self._broken[uri] = info
|
||||
elif status == "redirected":
|
||||
self.redirected[uri] = (info, code)
|
||||
self._redirected[uri] = (info, code)
|
||||
|
||||
return (status, info, code)
|
||||
|
||||
while True:
|
||||
uri, docname, lineno = self.wqueue.get()
|
||||
next_check, uri, docname, lineno = self.wqueue.get()
|
||||
if uri is None:
|
||||
break
|
||||
status, info, code = check()
|
||||
netloc = urlparse(uri).netloc
|
||||
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:
|
||||
uri, docname, lineno, status, info, code = result
|
||||
@ -279,44 +433,6 @@ class CheckExternalLinksBuilder(Builder):
|
||||
lineno, uri + ' to ' + info)
|
||||
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,
|
||||
uri: str) -> None:
|
||||
with open(path.join(self.outdir, 'output.txt'), 'a') as output:
|
||||
@ -328,15 +444,62 @@ class CheckExternalLinksBuilder(Builder):
|
||||
output.write('\n')
|
||||
|
||||
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:
|
||||
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]:
|
||||
app.add_builder(CheckExternalLinksBuilder)
|
||||
app.add_post_transform(HyperlinkCollector)
|
||||
|
||||
app.add_config_value('linkcheck_ignore', [], 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_timeout', None, None, [int])
|
||||
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
|
||||
# commonly used for dynamic pages
|
||||
app.add_config_value('linkcheck_anchors_ignore', ["^!"], None)
|
||||
app.add_config_value('linkcheck_rate_limit_timeout', 300.0, None)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -20,13 +20,11 @@ from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import NoUri
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import progress_message
|
||||
from sphinx.util import logging, progress_message
|
||||
from sphinx.util.console import darkgreen # type: ignore
|
||||
from sphinx.util.nodes import inline_all_toctrees
|
||||
from sphinx.util.osutil import make_filename_from_project
|
||||
from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator
|
||||
|
||||
from sphinx.util.osutil import ensuredir, make_filename_from_project
|
||||
from sphinx.writers.manpage import ManualPageTranslator, ManualPageWriter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -80,7 +78,12 @@ class ManualPageBuilder(Builder):
|
||||
docsettings.authors = authors
|
||||
docsettings.section = 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)
|
||||
destination = FileOutput(
|
||||
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_show_urls', False, None)
|
||||
app.add_config_value('man_make_section_directory', False, None)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -17,13 +17,16 @@ import sphinx
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
|
||||
|
||||
deprecated_alias('sphinx.builders.qthelp',
|
||||
{
|
||||
'render_file': render_file,
|
||||
'QtHelpBuilder': QtHelpBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'render_file': 'sphinxcontrib.qthelp.render_file',
|
||||
'QtHelpBuilder': 'sphinxcontrib.qthelp.QtHelpBuilder',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -19,8 +19,7 @@ from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.environment.adapters.toctree import TocTree
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import progress_message
|
||||
from sphinx.util import logging, progress_message
|
||||
from sphinx.util.console import darkgreen # type: ignore
|
||||
from sphinx.util.nodes import inline_all_toctrees
|
||||
|
||||
@ -193,7 +192,11 @@ deprecated_alias('sphinx.builders.html',
|
||||
{
|
||||
'SingleFileHTMLBuilder': SingleFileHTMLBuilder,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'SingleFileHTMLBuilder':
|
||||
'sphinx.builders.singlehtml.SingleFileHTMLBuilder',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -16,23 +16,20 @@ from docutils import nodes
|
||||
from docutils.frontend import OptionParser
|
||||
from docutils.io import FileOutput
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx import package_dir
|
||||
from sphinx import addnodes, package_dir
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.config import Config
|
||||
from sphinx.environment.adapters.asset import ImageAdapter
|
||||
from sphinx.errors import NoUri
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import progress_message, status_iterator
|
||||
from sphinx.util import logging, progress_message, status_iterator
|
||||
from sphinx.util.console import darkgreen # type: ignore
|
||||
from sphinx.util.docutils import new_document
|
||||
from sphinx.util.fileutil import copy_asset_file
|
||||
from sphinx.util.nodes import inline_all_toctrees
|
||||
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__)
|
||||
template_dir = os.path.join(package_dir, 'templates', 'texinfo')
|
||||
@ -182,7 +179,8 @@ class TexinfoBuilder(Builder):
|
||||
try:
|
||||
imagedir = path.join(self.outdir, targetname + '-figures')
|
||||
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:
|
||||
logger.warning(__('cannot copy image file %r: %s'),
|
||||
path.join(self.srcdir, src), err)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -19,7 +19,7 @@ from sphinx.builders import Builder
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
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__)
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -21,7 +21,7 @@ from sphinx.builders import Builder
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.osutil import ensuredir, os_path
|
||||
from sphinx.writers.xml import XMLWriter, PseudoXMLWriter
|
||||
from sphinx.writers.xml import PseudoXMLWriter, XMLWriter
|
||||
|
||||
if False:
|
||||
# For type annotation
|
||||
|
@ -4,6 +4,6 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -16,7 +16,7 @@ import os
|
||||
import pdb
|
||||
import sys
|
||||
import traceback
|
||||
from typing import Any, IO, List
|
||||
from typing import IO, Any, List
|
||||
|
||||
from docutils.utils import SystemMessage
|
||||
|
||||
@ -26,7 +26,7 @@ from sphinx.application import Sphinx
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.locale import __
|
||||
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
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
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).
|
||||
|
||||
: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.
|
||||
"""
|
||||
|
||||
@ -22,10 +22,9 @@ from typing import List
|
||||
|
||||
import sphinx
|
||||
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
|
||||
|
||||
|
||||
BUILDERS = [
|
||||
("", "html", "to make standalone HTML files"),
|
||||
("", "dirhtml", "to make HTML files named index.html in directories"),
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -37,9 +37,8 @@ import sphinx.locale
|
||||
from sphinx import __display_version__, package_dir
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.locale import __
|
||||
from sphinx.util.console import ( # type: ignore
|
||||
colorize, bold, red, turquoise, nocolor, color_terminal
|
||||
)
|
||||
from sphinx.util.console import (bold, color_terminal, colorize, nocolor, red, # type: ignore
|
||||
turquoise)
|
||||
from sphinx.util.osutil import ensuredir
|
||||
from sphinx.util.template import SphinxRenderer
|
||||
|
||||
@ -489,8 +488,10 @@ def get_parser() -> argparse.ArgumentParser:
|
||||
help=__('project root'))
|
||||
|
||||
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'))
|
||||
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='_',
|
||||
help=__('replacement for dot in _templates etc.'))
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -13,10 +13,9 @@ import traceback
|
||||
import types
|
||||
import warnings
|
||||
from collections import OrderedDict
|
||||
from os import path, getenv
|
||||
from typing import (
|
||||
Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple, Union
|
||||
)
|
||||
from os import getenv, path
|
||||
from typing import (Any, Callable, Dict, Generator, Iterator, List, NamedTuple, Set, Tuple,
|
||||
Union)
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.errors import ConfigError, ExtensionError
|
||||
@ -99,7 +98,8 @@ class Config:
|
||||
# general options
|
||||
'project': ('Python', 'env', []),
|
||||
'author': ('unknown', 'env', []),
|
||||
'copyright': ('', 'html', []),
|
||||
'project_copyright': ('', 'html', [str]),
|
||||
'copyright': (lambda c: c.project_copyright, 'html', [str]),
|
||||
'version': ('', 'env', []),
|
||||
'release': ('', 'env', []),
|
||||
'today': ('', 'env', []),
|
||||
@ -131,7 +131,7 @@ class Config:
|
||||
'rst_epilog': (None, 'env', [str]),
|
||||
'rst_prolog': (None, 'env', [str]),
|
||||
'trim_doctest_flags': (True, 'env', []),
|
||||
'primary_domain': ('py', 'env', [NoneType]), # type: ignore
|
||||
'primary_domain': ('py', 'env', [NoneType]),
|
||||
'needs_sphinx': (None, None, [str]),
|
||||
'needs_extensions': ({}, None, []),
|
||||
'manpages_url': (None, 'env', []),
|
||||
@ -181,6 +181,14 @@ class Config:
|
||||
defvalue = self.values[name][0]
|
||||
if self.values[name][2] == Any:
|
||||
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]:
|
||||
if value == '0':
|
||||
# given falsy string from command line option
|
||||
@ -196,9 +204,9 @@ class Config:
|
||||
elif isinstance(defvalue, int):
|
||||
try:
|
||||
return int(value)
|
||||
except ValueError:
|
||||
except ValueError as exc:
|
||||
raise ValueError(__('invalid number %r for config value %r, ignoring') %
|
||||
(value, name))
|
||||
(value, name)) from exc
|
||||
elif hasattr(defvalue, '__call__'):
|
||||
return value
|
||||
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)
|
||||
except SyntaxError as err:
|
||||
msg = __("There is a syntax error in your configuration file: %s\n")
|
||||
raise ConfigError(msg % err)
|
||||
except SystemExit:
|
||||
raise ConfigError(msg % err) from err
|
||||
except SystemExit as exc:
|
||||
msg = __("The configuration file (or one of the modules it imports) "
|
||||
"called sys.exit()")
|
||||
raise ConfigError(msg)
|
||||
raise ConfigError(msg) from exc
|
||||
except ConfigError:
|
||||
# pass through ConfigError from conf.py as is. It will be shown in console.
|
||||
raise
|
||||
except Exception:
|
||||
except Exception as exc:
|
||||
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
|
||||
|
||||
@ -359,6 +367,18 @@ def convert_source_suffix(app: "Sphinx", config: Config) -> None:
|
||||
"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:
|
||||
"""Initialize :confval:`numfig_format`."""
|
||||
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]:
|
||||
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', correct_copyright_year, priority=800)
|
||||
app.connect('config-inited', check_confval_types, priority=800)
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -26,31 +26,47 @@ class RemovedInSphinx50Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInSphinx60Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
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)
|
||||
sys.modules[modname] = _ModuleWrapper(module, modname, objects, warning) # type: ignore
|
||||
sys.modules[modname] = _ModuleWrapper( # type: ignore
|
||||
module, modname, objects, warning, names)
|
||||
|
||||
|
||||
class _ModuleWrapper:
|
||||
def __init__(self, module: Any, modname: str, objects: Dict, warning: "Type[Warning]"
|
||||
) -> None:
|
||||
def __init__(self, module: Any, modname: str,
|
||||
objects: Dict[str, object],
|
||||
warning: "Type[Warning]",
|
||||
names: Dict[str, str]) -> None:
|
||||
self._module = module
|
||||
self._modname = modname
|
||||
self._objects = objects
|
||||
self._warning = warning
|
||||
self._names = names
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
if name in self._objects:
|
||||
warnings.warn("%s.%s is deprecated. Check CHANGES for Sphinx "
|
||||
"API modifications." % (self._modname, name),
|
||||
if name not in self._objects:
|
||||
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]
|
||||
|
||||
return getattr(self._module, name)
|
||||
|
||||
|
||||
class DeprecatedDict(dict):
|
||||
"""A deprecated dict which warns on each access."""
|
||||
|
@ -4,13 +4,12 @@
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import cast
|
||||
from typing import Any, Dict, Generic, List, Tuple, TypeVar, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
@ -18,9 +17,8 @@ from docutils.parsers.rst import directives, roles
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.addnodes import desc_signature
|
||||
from sphinx.deprecation import (
|
||||
RemovedInSphinx40Warning, RemovedInSphinx50Warning, deprecated_alias
|
||||
)
|
||||
from sphinx.deprecation import (RemovedInSphinx40Warning, RemovedInSphinx50Warning,
|
||||
deprecated_alias)
|
||||
from sphinx.util import docutils
|
||||
from sphinx.util.docfields import DocFieldTransformer, Field, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
@ -35,6 +33,8 @@ if False:
|
||||
nl_escape_re = re.compile(r'\\\n')
|
||||
strip_backslash_re = re.compile(r'\\(.)')
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
def optional_int(argument: str) -> int:
|
||||
"""
|
||||
@ -49,7 +49,7 @@ def optional_int(argument: str) -> int:
|
||||
return value
|
||||
|
||||
|
||||
class ObjectDescription(SphinxDirective):
|
||||
class ObjectDescription(SphinxDirective, Generic[T]):
|
||||
"""
|
||||
Directive to describe a class, function or similar object. Not used
|
||||
directly, but subclassed (in domain-specific directives) to add custom
|
||||
@ -99,7 +99,7 @@ class ObjectDescription(SphinxDirective):
|
||||
else:
|
||||
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
|
||||
*signode*. If ValueError is raised, parsing is aborted and the whole
|
||||
@ -111,7 +111,7 @@ class ObjectDescription(SphinxDirective):
|
||||
"""
|
||||
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.
|
||||
|
||||
@ -175,7 +175,7 @@ class ObjectDescription(SphinxDirective):
|
||||
if self.domain:
|
||||
node['classes'].append(self.domain)
|
||||
|
||||
self.names = [] # type: List[Any]
|
||||
self.names = [] # type: List[T]
|
||||
signatures = self.get_signatures()
|
||||
for i, sig in enumerate(signatures):
|
||||
# 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)
|
||||
return []
|
||||
|
||||
from sphinx.directives.code import ( # noqa
|
||||
Highlight, CodeBlock, LiteralInclude
|
||||
)
|
||||
from sphinx.directives.other import ( # noqa
|
||||
TocTree, Author, VersionChange, SeeAlso,
|
||||
TabularColumns, Centered, Acks, HList, Only, Include, Class
|
||||
)
|
||||
from sphinx.directives.patches import ( # noqa
|
||||
Figure, Meta
|
||||
)
|
||||
from sphinx.directives.code import CodeBlock, Highlight, LiteralInclude # noqa
|
||||
from sphinx.directives.other import (Acks, Author, Centered, Class, HList, Include, # noqa
|
||||
Only, SeeAlso, TabularColumns, TocTree, VersionChange)
|
||||
from sphinx.directives.patches import Figure, Meta # noqa
|
||||
from sphinx.domains.index import IndexDirective # noqa
|
||||
|
||||
deprecated_alias('sphinx.directives',
|
||||
@ -298,13 +292,35 @@ deprecated_alias('sphinx.directives',
|
||||
'Figure': Figure,
|
||||
'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',
|
||||
{
|
||||
'DescDirective': ObjectDescription,
|
||||
},
|
||||
RemovedInSphinx50Warning)
|
||||
RemovedInSphinx50Warning,
|
||||
{
|
||||
'DescDirective': 'sphinx.directives.ObjectDescription',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
|
@ -2,11 +2,12 @@
|
||||
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.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import textwrap
|
||||
import warnings
|
||||
from difflib import unified_diff
|
||||
from typing import Any, Dict, List, Tuple
|
||||
@ -19,9 +20,9 @@ from docutils.statemachine import StringList
|
||||
from sphinx import addnodes
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
from sphinx.directives import optional_int
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
from sphinx.util import parselinenos
|
||||
from sphinx.util import logging, parselinenos
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
|
||||
if False:
|
||||
@ -69,10 +70,10 @@ class HighlightLang(Highlight):
|
||||
|
||||
def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:
|
||||
if not dedent:
|
||||
return lines
|
||||
return textwrap.dedent(''.join(lines)).splitlines(True)
|
||||
|
||||
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 = []
|
||||
for line in lines:
|
||||
@ -118,7 +119,7 @@ class CodeBlock(SphinxDirective):
|
||||
option_spec = {
|
||||
'force': directives.flag,
|
||||
'linenos': directives.flag,
|
||||
'dedent': int,
|
||||
'dedent': optional_int,
|
||||
'lineno-start': int,
|
||||
'emphasize-lines': directives.unchanged_required,
|
||||
'caption': directives.unchanged_required,
|
||||
@ -227,12 +228,13 @@ class LiteralIncludeReader:
|
||||
text = text.expandtabs(self.options['tab-width'])
|
||||
|
||||
return text.splitlines(True)
|
||||
except OSError:
|
||||
raise OSError(__('Include file %r not found or reading it failed') % filename)
|
||||
except UnicodeError:
|
||||
except OSError as exc:
|
||||
raise OSError(__('Include file %r not found or reading it failed') %
|
||||
filename) from exc
|
||||
except UnicodeError as exc:
|
||||
raise UnicodeError(__('Encoding %r used for reading included file %r seems to '
|
||||
'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]:
|
||||
if 'diff' in self.options:
|
||||
@ -391,7 +393,7 @@ class LiteralInclude(SphinxDirective):
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = True
|
||||
option_spec = {
|
||||
'dedent': int,
|
||||
'dedent': optional_int,
|
||||
'linenos': directives.flag,
|
||||
'lineno-start': int,
|
||||
'lineno-match': directives.flag,
|
||||
|
@ -2,13 +2,12 @@
|
||||
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.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Any, Dict, List
|
||||
from typing import cast
|
||||
from typing import Any, Dict, List, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node
|
||||
@ -21,7 +20,7 @@ from sphinx import addnodes
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.domains.changeset import VersionChange # NOQA # for compatibility
|
||||
from sphinx.locale import _
|
||||
from sphinx.util import url_re, docname_join
|
||||
from sphinx.util import docname_join, url_re
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.matching import Matcher, patfilter
|
||||
from sphinx.util.nodes import explicit_title_re
|
||||
@ -368,7 +367,10 @@ deprecated_alias('sphinx.directives.other',
|
||||
{
|
||||
'Index': IndexDirective,
|
||||
},
|
||||
RemovedInSphinx40Warning)
|
||||
RemovedInSphinx40Warning,
|
||||
{
|
||||
'Index': 'sphinx.domains.index.IndexDirective',
|
||||
})
|
||||
|
||||
|
||||
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||
|
@ -2,17 +2,16 @@
|
||||
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.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import cast
|
||||
from typing import Any, Dict, List, Tuple, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node, make_id, system_message
|
||||
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.directives import optional_int
|
||||
|
@ -5,13 +5,12 @@
|
||||
Support for domains, which are groupings of description directives
|
||||
and roles describing e.g. constructs of one programming language.
|
||||
|
||||
: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.
|
||||
"""
|
||||
|
||||
import copy
|
||||
from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Union
|
||||
from typing import cast
|
||||
from typing import Any, Callable, Dict, Iterable, List, NamedTuple, Tuple, Union, cast
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, system_message
|
||||
@ -26,6 +25,7 @@ from sphinx.util.typing import RoleFunction
|
||||
if False:
|
||||
# For type annotation
|
||||
from typing import Type # for python3.5.1
|
||||
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.environment import BuildEnvironment
|
||||
|
||||
|
@ -4,42 +4,49 @@
|
||||
|
||||
The C language domain.
|
||||
|
||||
: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.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import (
|
||||
Any, Callable, Dict, Generator, Iterator, List, Type, Tuple, Union
|
||||
)
|
||||
from typing import cast
|
||||
from typing import (Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar,
|
||||
Union, cast)
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Element, Node, TextElement, system_message
|
||||
from docutils.parsers.rst import directives
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.addnodes import pending_xref
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.deprecation import RemovedInSphinx50Warning
|
||||
from sphinx.directives import ObjectDescription
|
||||
from sphinx.domains import Domain, ObjType
|
||||
from sphinx.environment import BuildEnvironment
|
||||
from sphinx.locale import _, __
|
||||
from sphinx.roles import SphinxRole, XRefRole
|
||||
from sphinx.transforms import SphinxTransform
|
||||
from sphinx.transforms.post_transforms import ReferencesResolver
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.cfamily import (
|
||||
NoOldIdError, ASTBaseBase, verify_description_mode, StringifyTransform,
|
||||
BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,
|
||||
identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,
|
||||
hex_literal_re, binary_literal_re, integers_literal_suffix_re,
|
||||
float_literal_re, float_literal_suffix_re,
|
||||
char_literal_re
|
||||
)
|
||||
from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList, BaseParser,
|
||||
DefinitionError, NoOldIdError, StringifyTransform,
|
||||
UnsupportedMultiCharacterCharLiteral, anon_identifier_re,
|
||||
binary_literal_re, char_literal_re, float_literal_re,
|
||||
float_literal_suffix_re, hex_literal_re, identifier_re,
|
||||
integer_literal_re, integers_literal_suffix_re,
|
||||
octal_literal_re, verify_description_mode)
|
||||
from sphinx.util.docfields import Field, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.nodes import make_refnode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
T = TypeVar('T')
|
||||
|
||||
DeclarationType = Union[
|
||||
"ASTStruct", "ASTUnion", "ASTEnum", "ASTEnumerator",
|
||||
"ASTType", "ASTTypeWithInit", "ASTMacro",
|
||||
]
|
||||
|
||||
# https://en.cppreference.com/w/c/keyword
|
||||
_keywords = [
|
||||
@ -106,6 +113,9 @@ class ASTIdentifier(ASTBaseBase):
|
||||
assert len(identifier) != 0
|
||||
self.identifier = identifier
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
return type(other) is ASTIdentifier and self.identifier == other.identifier
|
||||
|
||||
def is_anon(self) -> bool:
|
||||
return self.identifier[0] == '@'
|
||||
|
||||
@ -127,8 +137,7 @@ class ASTIdentifier(ASTBaseBase):
|
||||
reftype='identifier',
|
||||
reftarget=targetText, modname=None,
|
||||
classname=None)
|
||||
# key = symbol.get_lookup_key()
|
||||
# pnode['c:parent_key'] = key
|
||||
pnode['c:parent_key'] = symbol.get_lookup_key()
|
||||
if self.is_anon():
|
||||
pnode += nodes.strong(text="[anonymous]")
|
||||
else:
|
||||
@ -627,6 +636,10 @@ class ASTFunctionParameter(ASTBase):
|
||||
self.arg = arg
|
||||
self.ellipsis = ellipsis
|
||||
|
||||
def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
|
||||
# the anchor will be our parent
|
||||
return symbol.parent.declaration.get_id(version, prefixed=False)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
if self.ellipsis:
|
||||
return '...'
|
||||
@ -643,8 +656,9 @@ class ASTFunctionParameter(ASTBase):
|
||||
|
||||
|
||||
class ASTParameters(ASTBase):
|
||||
def __init__(self, args: List[ASTFunctionParameter]) -> None:
|
||||
def __init__(self, args: List[ASTFunctionParameter], attrs: List[ASTAttribute]) -> None:
|
||||
self.args = args
|
||||
self.attrs = attrs
|
||||
|
||||
@property
|
||||
def function_params(self) -> List[ASTFunctionParameter]:
|
||||
@ -660,6 +674,9 @@ class ASTParameters(ASTBase):
|
||||
first = False
|
||||
res.append(str(a))
|
||||
res.append(')')
|
||||
for attr in self.attrs:
|
||||
res.append(' ')
|
||||
res.append(transform(attr))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode: TextElement, mode: str,
|
||||
@ -674,6 +691,9 @@ class ASTParameters(ASTBase):
|
||||
arg.describe_signature(param, 'markType', env, symbol=symbol)
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
for attr in self.attrs:
|
||||
signode += nodes.Text(' ')
|
||||
attr.describe_signature(signode)
|
||||
|
||||
|
||||
class ASTDeclSpecsSimple(ASTBaseBase):
|
||||
@ -1053,7 +1073,7 @@ class ASTDeclaratorParen(ASTDeclarator):
|
||||
# Initializer
|
||||
################################################################################
|
||||
|
||||
class ASTParenExprList(ASTBase):
|
||||
class ASTParenExprList(ASTBaseParenExprList):
|
||||
def __init__(self, exprs: List[ASTExpression]) -> None:
|
||||
self.exprs = exprs
|
||||
|
||||
@ -1133,6 +1153,9 @@ class ASTType(ASTBase):
|
||||
def name(self) -> ASTNestedName:
|
||||
return self.decl.name
|
||||
|
||||
def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
|
||||
return symbol.get_full_nested_name().get_id(version)
|
||||
|
||||
@property
|
||||
def function_params(self) -> List[ASTFunctionParameter]:
|
||||
return self.decl.function_params
|
||||
@ -1175,6 +1198,9 @@ class ASTTypeWithInit(ASTBase):
|
||||
def name(self) -> ASTNestedName:
|
||||
return self.type.name
|
||||
|
||||
def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
|
||||
return self.type.get_id(version, objectType, symbol)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = []
|
||||
res.append(transform(self.type))
|
||||
@ -1191,13 +1217,17 @@ class ASTTypeWithInit(ASTBase):
|
||||
|
||||
|
||||
class ASTMacroParameter(ASTBase):
|
||||
def __init__(self, arg: ASTNestedName, ellipsis: bool = False) -> None:
|
||||
def __init__(self, arg: ASTNestedName, ellipsis: bool = False,
|
||||
variadic: bool = False) -> None:
|
||||
self.arg = arg
|
||||
self.ellipsis = ellipsis
|
||||
self.variadic = variadic
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
if self.ellipsis:
|
||||
return '...'
|
||||
elif self.variadic:
|
||||
return transform(self.arg) + '...'
|
||||
else:
|
||||
return transform(self.arg)
|
||||
|
||||
@ -1206,6 +1236,9 @@ class ASTMacroParameter(ASTBase):
|
||||
verify_description_mode(mode)
|
||||
if self.ellipsis:
|
||||
signode += nodes.Text('...')
|
||||
elif self.variadic:
|
||||
name = str(self)
|
||||
signode += nodes.emphasis(name, name)
|
||||
else:
|
||||
self.arg.describe_signature(signode, mode, env, symbol=symbol)
|
||||
|
||||
@ -1219,6 +1252,9 @@ class ASTMacro(ASTBase):
|
||||
def name(self) -> ASTNestedName:
|
||||
return self.ident
|
||||
|
||||
def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
|
||||
return symbol.get_full_nested_name().get_id(version)
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
res = []
|
||||
res.append(transform(self.ident))
|
||||
@ -1319,7 +1355,8 @@ class ASTEnumerator(ASTBase):
|
||||
|
||||
|
||||
class ASTDeclaration(ASTBaseBase):
|
||||
def __init__(self, objectType: str, directiveType: str, declaration: Any,
|
||||
def __init__(self, objectType: str, directiveType: str,
|
||||
declaration: Union[DeclarationType, ASTFunctionParameter],
|
||||
semicolon: bool = False) -> None:
|
||||
self.objectType = objectType
|
||||
self.directiveType = directiveType
|
||||
@ -1330,20 +1367,26 @@ class ASTDeclaration(ASTBaseBase):
|
||||
# set by CObject._add_enumerator_to_parent
|
||||
self.enumeratorScopedSymbol = None # type: Symbol
|
||||
|
||||
def clone(self) -> "ASTDeclaration":
|
||||
return ASTDeclaration(self.objectType, self.directiveType,
|
||||
self.declaration.clone(), self.semicolon)
|
||||
|
||||
@property
|
||||
def name(self) -> ASTNestedName:
|
||||
return self.declaration.name
|
||||
decl = cast(DeclarationType, self.declaration)
|
||||
return decl.name
|
||||
|
||||
@property
|
||||
def function_params(self) -> List[ASTFunctionParameter]:
|
||||
if self.objectType != 'function':
|
||||
return None
|
||||
return self.declaration.function_params
|
||||
decl = cast(ASTType, self.declaration)
|
||||
return decl.function_params
|
||||
|
||||
def get_id(self, version: int, prefixed: bool = True) -> str:
|
||||
if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
|
||||
return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed)
|
||||
id_ = self.symbol.get_full_nested_name().get_id(version)
|
||||
id_ = self.declaration.get_id(version, self.objectType, self.symbol)
|
||||
if prefixed:
|
||||
return _id_prefix[version] + id_
|
||||
else:
|
||||
@ -1386,7 +1429,8 @@ class ASTDeclaration(ASTBaseBase):
|
||||
elif self.objectType == 'enumerator':
|
||||
mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ')
|
||||
elif self.objectType == 'type':
|
||||
prefix = self.declaration.get_type_declaration_prefix()
|
||||
decl = cast(ASTType, self.declaration)
|
||||
prefix = decl.get_type_declaration_prefix()
|
||||
prefix += ' '
|
||||
mainDeclNode += addnodes.desc_annotation(prefix, prefix)
|
||||
else:
|
||||
@ -1419,6 +1463,16 @@ class Symbol:
|
||||
debug_lookup = False
|
||||
debug_show_tree = False
|
||||
|
||||
def __copy__(self):
|
||||
assert False # shouldn't happen
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
if self.parent:
|
||||
assert False # shouldn't happen
|
||||
else:
|
||||
# the domain base class makes a copy of the initial data, which is fine
|
||||
return Symbol(None, None, None, None, None)
|
||||
|
||||
@staticmethod
|
||||
def debug_print(*args: Any) -> None:
|
||||
print(Symbol.debug_indent_string * Symbol.debug_indent, end="")
|
||||
@ -1440,7 +1494,7 @@ class Symbol:
|
||||
return super().__setattr__(key, value)
|
||||
|
||||
def __init__(self, parent: "Symbol", ident: ASTIdentifier,
|
||||
declaration: ASTDeclaration, docname: str) -> None:
|
||||
declaration: ASTDeclaration, docname: str, line: int) -> None:
|
||||
self.parent = parent
|
||||
# declarations in a single directive are linked together
|
||||
self.siblingAbove = None # type: Symbol
|
||||
@ -1448,6 +1502,7 @@ class Symbol:
|
||||
self.ident = ident
|
||||
self.declaration = declaration
|
||||
self.docname = docname
|
||||
self.line = line
|
||||
self.isRedeclaration = False
|
||||
self._assert_invariants()
|
||||
|
||||
@ -1463,15 +1518,18 @@ class Symbol:
|
||||
# Do symbol addition after self._children has been initialised.
|
||||
self._add_function_params()
|
||||
|
||||
def _fill_empty(self, declaration: ASTDeclaration, docname: str) -> None:
|
||||
def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None:
|
||||
self._assert_invariants()
|
||||
assert not self.declaration
|
||||
assert not self.docname
|
||||
assert declaration
|
||||
assert docname
|
||||
assert self.declaration is None
|
||||
assert self.docname is None
|
||||
assert self.line is None
|
||||
assert declaration is not None
|
||||
assert docname is not None
|
||||
assert line is not None
|
||||
self.declaration = declaration
|
||||
self.declaration.symbol = self
|
||||
self.docname = docname
|
||||
self.line = line
|
||||
self._assert_invariants()
|
||||
# and symbol addition should be done as well
|
||||
self._add_function_params()
|
||||
@ -1495,7 +1553,7 @@ class Symbol:
|
||||
decl = ASTDeclaration('functionParam', None, p)
|
||||
assert not nn.rooted
|
||||
assert len(nn.names) == 1
|
||||
self._add_symbols(nn, decl, self.docname)
|
||||
self._add_symbols(nn, decl, self.docname, self.line)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
|
||||
@ -1507,26 +1565,27 @@ class Symbol:
|
||||
self.parent = None
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
newChildren = [] # type: List[Symbol]
|
||||
for sChild in self._children:
|
||||
sChild.clear_doc(docname)
|
||||
if sChild.declaration and sChild.docname == docname:
|
||||
sChild.declaration = None
|
||||
sChild.docname = None
|
||||
sChild.line = None
|
||||
if sChild.siblingAbove is not None:
|
||||
sChild.siblingAbove.siblingBelow = sChild.siblingBelow
|
||||
if sChild.siblingBelow is not None:
|
||||
sChild.siblingBelow.siblingAbove = sChild.siblingAbove
|
||||
sChild.siblingAbove = None
|
||||
sChild.siblingBelow = None
|
||||
newChildren.append(sChild)
|
||||
self._children = newChildren
|
||||
|
||||
def get_all_symbols(self) -> Iterator["Symbol"]:
|
||||
yield self
|
||||
for sChild in self._children:
|
||||
for s in sChild.get_all_symbols():
|
||||
yield s
|
||||
yield from sChild.get_all_symbols()
|
||||
|
||||
@property
|
||||
def children(self) -> Iterator["Symbol"]:
|
||||
yield from self._children
|
||||
|
||||
@property
|
||||
def children_recurse_anon(self) -> Iterator["Symbol"]:
|
||||
@ -1703,7 +1762,7 @@ class Symbol:
|
||||
return SymbolLookupResult(symbols, parentSymbol, ident)
|
||||
|
||||
def _add_symbols(self, nestedName: ASTNestedName,
|
||||
declaration: ASTDeclaration, docname: str) -> "Symbol":
|
||||
declaration: ASTDeclaration, docname: str, line: int) -> "Symbol":
|
||||
# TODO: further simplification from C++ to C
|
||||
# Used for adding a whole path of symbols, where the last may or may not
|
||||
# be an actual declaration.
|
||||
@ -1714,7 +1773,7 @@ class Symbol:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("nn: ", nestedName)
|
||||
Symbol.debug_print("decl: ", declaration)
|
||||
Symbol.debug_print("doc: ", docname)
|
||||
Symbol.debug_print("location: {}:{}".format(docname, line))
|
||||
|
||||
def onMissingQualifiedSymbol(parentSymbol: "Symbol", ident: ASTIdentifier) -> "Symbol":
|
||||
if Symbol.debug_lookup:
|
||||
@ -1724,7 +1783,7 @@ class Symbol:
|
||||
Symbol.debug_print("ident: ", ident)
|
||||
Symbol.debug_indent -= 2
|
||||
return Symbol(parent=parentSymbol, ident=ident,
|
||||
declaration=None, docname=None)
|
||||
declaration=None, docname=None, line=None)
|
||||
|
||||
lookupResult = self._symbol_lookup(nestedName,
|
||||
onMissingQualifiedSymbol,
|
||||
@ -1740,12 +1799,12 @@ class Symbol:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("ident: ", lookupResult.ident)
|
||||
Symbol.debug_print("declaration: ", declaration)
|
||||
Symbol.debug_print("docname: ", docname)
|
||||
Symbol.debug_print("location: {}:{}".format(docname, line))
|
||||
Symbol.debug_indent -= 1
|
||||
symbol = Symbol(parent=lookupResult.parentSymbol,
|
||||
ident=lookupResult.ident,
|
||||
declaration=declaration,
|
||||
docname=docname)
|
||||
docname=docname, line=line)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 2
|
||||
return symbol
|
||||
@ -1758,7 +1817,7 @@ class Symbol:
|
||||
|
||||
if not declaration:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("no delcaration")
|
||||
Symbol.debug_print("no declaration")
|
||||
Symbol.debug_indent -= 2
|
||||
# good, just a scope creation
|
||||
# TODO: what if we have more than one symbol?
|
||||
@ -1793,7 +1852,7 @@ class Symbol:
|
||||
symbol = Symbol(parent=lookupResult.parentSymbol,
|
||||
ident=lookupResult.ident,
|
||||
declaration=declaration,
|
||||
docname=docname)
|
||||
docname=docname, line=line)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_print("end: creating candidate symbol")
|
||||
return symbol
|
||||
@ -1859,7 +1918,7 @@ class Symbol:
|
||||
# .. namespace:: Test
|
||||
# .. namespace:: nullptr
|
||||
# .. class:: Test
|
||||
symbol._fill_empty(declaration, docname)
|
||||
symbol._fill_empty(declaration, docname, line)
|
||||
return symbol
|
||||
|
||||
def merge_with(self, other: "Symbol", docnames: List[str],
|
||||
@ -1880,13 +1939,15 @@ class Symbol:
|
||||
continue
|
||||
if otherChild.declaration and otherChild.docname in docnames:
|
||||
if not ourChild.declaration:
|
||||
ourChild._fill_empty(otherChild.declaration, otherChild.docname)
|
||||
ourChild._fill_empty(otherChild.declaration,
|
||||
otherChild.docname, otherChild.line)
|
||||
elif ourChild.docname != otherChild.docname:
|
||||
name = str(ourChild.declaration)
|
||||
msg = __("Duplicate declaration, also defined in '%s'.\n"
|
||||
"Declaration is '%s'.")
|
||||
msg = msg % (ourChild.docname, name)
|
||||
logger.warning(msg, location=otherChild.docname)
|
||||
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
|
||||
"Declaration is '.. c:%s:: %s'.")
|
||||
msg = msg % (ourChild.docname, ourChild.line,
|
||||
ourChild.declaration.directiveType, name)
|
||||
logger.warning(msg, location=(otherChild.docname, otherChild.line))
|
||||
else:
|
||||
# Both have declarations, and in the same docname.
|
||||
# This can apparently happen, it should be safe to
|
||||
@ -1900,19 +1961,21 @@ class Symbol:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("add_name:")
|
||||
res = self._add_symbols(nestedName, declaration=None, docname=None)
|
||||
res = self._add_symbols(nestedName, declaration=None, docname=None, line=None)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
return res
|
||||
|
||||
def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol":
|
||||
def add_declaration(self, declaration: ASTDeclaration,
|
||||
docname: str, line: int) -> "Symbol":
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("add_declaration:")
|
||||
assert declaration
|
||||
assert docname
|
||||
assert declaration is not None
|
||||
assert docname is not None
|
||||
assert line is not None
|
||||
nestedName = declaration.name
|
||||
res = self._add_symbols(nestedName, declaration, docname)
|
||||
res = self._add_symbols(nestedName, declaration, docname, line)
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
return res
|
||||
@ -2300,7 +2363,8 @@ class DefinitionParser(BaseParser):
|
||||
errs = []
|
||||
errs.append((exCast, "If type cast expression"))
|
||||
errs.append((exUnary, "If unary expression"))
|
||||
raise self._make_multi_error(errs, "Error in cast expression.")
|
||||
raise self._make_multi_error(errs,
|
||||
"Error in cast expression.") from exUnary
|
||||
else:
|
||||
return self._parse_unary_expression()
|
||||
|
||||
@ -2544,7 +2608,15 @@ class DefinitionParser(BaseParser):
|
||||
self.fail(
|
||||
'Expecting "," or ")" in parameters, '
|
||||
'got "%s".' % self.current_char)
|
||||
return ASTParameters(args)
|
||||
|
||||
attrs = []
|
||||
while True:
|
||||
attr = self._parse_attribute()
|
||||
if attr is None:
|
||||
break
|
||||
attrs.append(attr)
|
||||
|
||||
return ASTParameters(args, attrs)
|
||||
|
||||
def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple:
|
||||
"""Just parse the simple ones."""
|
||||
@ -2767,7 +2839,7 @@ class DefinitionParser(BaseParser):
|
||||
msg += " (e.g., 'void (*f(int arg))(double)')"
|
||||
prevErrors.append((exNoPtrParen, msg))
|
||||
header = "Error in declarator"
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
raise self._make_multi_error(prevErrors, header) from exNoPtrParen
|
||||
pos = self.pos
|
||||
try:
|
||||
return self._parse_declarator_name_suffix(named, paramMode, typed)
|
||||
@ -2775,7 +2847,7 @@ class DefinitionParser(BaseParser):
|
||||
self.pos = pos
|
||||
prevErrors.append((e, "If declarator-id"))
|
||||
header = "Error in declarator or parameters"
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
raise self._make_multi_error(prevErrors, header) from e
|
||||
|
||||
def _parse_initializer(self, outer: str = None, allowFallback: bool = True
|
||||
) -> ASTInitializer:
|
||||
@ -2843,7 +2915,7 @@ class DefinitionParser(BaseParser):
|
||||
if True:
|
||||
header = "Type must be either just a name or a "
|
||||
header += "typedef-like declaration."
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
raise self._make_multi_error(prevErrors, header) from exTyped
|
||||
else:
|
||||
# For testing purposes.
|
||||
# do it again to get the proper traceback (how do you
|
||||
@ -2894,9 +2966,16 @@ class DefinitionParser(BaseParser):
|
||||
if not self.match(identifier_re):
|
||||
self.fail("Expected identifier in macro parameters.")
|
||||
nn = ASTNestedName([ASTIdentifier(self.matched_text)], rooted=False)
|
||||
arg = ASTMacroParameter(nn)
|
||||
args.append(arg)
|
||||
# Allow named variadic args:
|
||||
# https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
|
||||
self.skip_ws()
|
||||
if self.skip_string_and_ws('...'):
|
||||
args.append(ASTMacroParameter(nn, False, True))
|
||||
self.skip_ws()
|
||||
if not self.skip_string(')'):
|
||||
self.fail('Expected ")" after "..." in macro parameters.')
|
||||
break
|
||||
args.append(ASTMacroParameter(nn))
|
||||
if self.skip_string_and_ws(','):
|
||||
continue
|
||||
elif self.skip_string_and_ws(')'):
|
||||
@ -2931,6 +3010,23 @@ class DefinitionParser(BaseParser):
|
||||
init = ASTInitializer(initVal)
|
||||
return ASTEnumerator(name, init)
|
||||
|
||||
def parse_pre_v3_type_definition(self) -> ASTDeclaration:
|
||||
self.skip_ws()
|
||||
declaration = None # type: DeclarationType
|
||||
if self.skip_word('struct'):
|
||||
typ = 'struct'
|
||||
declaration = self._parse_struct()
|
||||
elif self.skip_word('union'):
|
||||
typ = 'union'
|
||||
declaration = self._parse_union()
|
||||
elif self.skip_word('enum'):
|
||||
typ = 'enum'
|
||||
declaration = self._parse_enum()
|
||||
else:
|
||||
self.fail("Could not parse pre-v3 type directive."
|
||||
" Must start with 'struct', 'union', or 'enum'.")
|
||||
return ASTDeclaration(typ, typ, declaration, False)
|
||||
|
||||
def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration:
|
||||
if objectType not in ('function', 'member',
|
||||
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
|
||||
@ -2939,7 +3035,7 @@ class DefinitionParser(BaseParser):
|
||||
'macro', 'struct', 'union', 'enum', 'enumerator', 'type'):
|
||||
raise Exception('Internal error, unknown directiveType "%s".' % directiveType)
|
||||
|
||||
declaration = None # type: Any
|
||||
declaration = None # type: DeclarationType
|
||||
if objectType == 'member':
|
||||
declaration = self._parse_type_with_init(named=True, outer='member')
|
||||
elif objectType == 'function':
|
||||
@ -2994,7 +3090,7 @@ class DefinitionParser(BaseParser):
|
||||
errs = []
|
||||
errs.append((exExpr, "If expression"))
|
||||
errs.append((exType, "If type"))
|
||||
raise self._make_multi_error(errs, header)
|
||||
raise self._make_multi_error(errs, header) from exType
|
||||
return res
|
||||
|
||||
|
||||
@ -3002,7 +3098,7 @@ def _make_phony_error_name() -> ASTNestedName:
|
||||
return ASTNestedName([ASTIdentifier("PhonyNameDueToError")], rooted=False)
|
||||
|
||||
|
||||
class CObject(ObjectDescription):
|
||||
class CObject(ObjectDescription[ASTDeclaration]):
|
||||
"""
|
||||
Description of a C language object.
|
||||
"""
|
||||
@ -3017,6 +3113,10 @@ class CObject(ObjectDescription):
|
||||
names=('rtype',)),
|
||||
]
|
||||
|
||||
option_spec = {
|
||||
'noindexentry': directives.flag,
|
||||
}
|
||||
|
||||
def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None:
|
||||
assert ast.objectType == 'enumerator'
|
||||
# find the parent, if it exists && is an enum
|
||||
@ -3052,7 +3152,7 @@ class CObject(ObjectDescription):
|
||||
declClone.enumeratorScopedSymbol = symbol
|
||||
Symbol(parent=targetSymbol, ident=symbol.ident,
|
||||
declaration=declClone,
|
||||
docname=self.env.docname)
|
||||
docname=self.env.docname, line=self.get_source_info()[1])
|
||||
|
||||
def add_target_and_index(self, ast: ASTDeclaration, sig: str,
|
||||
signode: TextElement) -> None:
|
||||
@ -3082,9 +3182,7 @@ class CObject(ObjectDescription):
|
||||
|
||||
self.state.document.note_explicit_target(signode)
|
||||
|
||||
domain = cast(CDomain, self.env.get_domain('c'))
|
||||
domain.note_object(name, self.objtype, newestId)
|
||||
|
||||
if 'noindexentry' not in self.options:
|
||||
indexText = self.get_index_text(name)
|
||||
self.indexnode['entries'].append(('single', indexText, newestId, '', None))
|
||||
|
||||
@ -3102,7 +3200,11 @@ class CObject(ObjectDescription):
|
||||
def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration:
|
||||
return parser.parse_declaration(self.object_type, self.objtype)
|
||||
|
||||
def describe_signature(self, signode: TextElement, ast: Any, options: Dict) -> None:
|
||||
def parse_pre_v3_type_definition(self, parser: DefinitionParser) -> ASTDeclaration:
|
||||
return parser.parse_pre_v3_type_definition()
|
||||
|
||||
def describe_signature(self, signode: TextElement, ast: ASTDeclaration,
|
||||
options: Dict) -> None:
|
||||
ast.describe_signature(signode, 'lastIsName', self.env, options)
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
@ -3122,9 +3224,28 @@ class CObject(ObjectDescription):
|
||||
parentSymbol = self.env.temp_data['c:parent_symbol'] # type: Symbol
|
||||
|
||||
parser = DefinitionParser(sig, location=signode, config=self.env.config)
|
||||
try:
|
||||
try:
|
||||
ast = self.parse_definition(parser)
|
||||
parser.assert_end()
|
||||
except DefinitionError as eOrig:
|
||||
if not self.env.config['c_allow_pre_v3']:
|
||||
raise
|
||||
if self.objtype != 'type':
|
||||
raise
|
||||
try:
|
||||
ast = self.parse_pre_v3_type_definition(parser)
|
||||
parser.assert_end()
|
||||
except DefinitionError:
|
||||
raise eOrig
|
||||
self.object_type = ast.objectType # type: ignore
|
||||
if self.env.config['c_warn_on_allowed_pre_v3']:
|
||||
msg = "{}: Pre-v3 C type directive '.. c:type:: {}' converted to " \
|
||||
"'.. c:{}:: {}'." \
|
||||
"\nThe original parsing error was:\n{}"
|
||||
msg = msg.format(RemovedInSphinx50Warning.__name__,
|
||||
sig, ast.objectType, ast, eOrig)
|
||||
logger.warning(msg, location=signode)
|
||||
except DefinitionError as e:
|
||||
logger.warning(e, location=signode)
|
||||
# It is easier to assume some phony name than handling the error in
|
||||
@ -3132,10 +3253,11 @@ class CObject(ObjectDescription):
|
||||
name = _make_phony_error_name()
|
||||
symbol = parentSymbol.add_name(name)
|
||||
self.env.temp_data['c:last_symbol'] = symbol
|
||||
raise ValueError
|
||||
raise ValueError from e
|
||||
|
||||
try:
|
||||
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
|
||||
symbol = parentSymbol.add_declaration(
|
||||
ast, docname=self.env.docname, line=self.get_source_info()[1])
|
||||
# append the new declaration to the sibling list
|
||||
assert symbol.siblingAbove is None
|
||||
assert symbol.siblingBelow is None
|
||||
@ -3148,7 +3270,10 @@ class CObject(ObjectDescription):
|
||||
# Assume we are actually in the old symbol,
|
||||
# instead of the newly created duplicate.
|
||||
self.env.temp_data['c:last_symbol'] = e.symbol
|
||||
logger.warning("Duplicate declaration, %s", sig, location=signode)
|
||||
msg = __("Duplicate C declaration, also defined at %s:%s.\n"
|
||||
"Declaration is '.. c:%s:: %s'.")
|
||||
msg = msg % (e.symbol.docname, e.symbol.line, self.display_object_type, sig)
|
||||
logger.warning(msg, location=signode)
|
||||
|
||||
if ast.objectType == 'enumerator':
|
||||
self._add_enumerator_to_parent(ast)
|
||||
@ -3309,6 +3434,134 @@ class CNamespacePopObject(SphinxDirective):
|
||||
return []
|
||||
|
||||
|
||||
class AliasNode(nodes.Element):
|
||||
def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironment" = None,
|
||||
parentKey: LookupKey = None) -> None:
|
||||
super().__init__()
|
||||
self.sig = sig
|
||||
self.maxdepth = maxdepth
|
||||
assert maxdepth >= 0
|
||||
self.document = document
|
||||
if env is not None:
|
||||
if 'c:parent_symbol' not in env.temp_data:
|
||||
root = env.domaindata['c']['root_symbol']
|
||||
env.temp_data['c:parent_symbol'] = root
|
||||
self.parentKey = env.temp_data['c:parent_symbol'].get_lookup_key()
|
||||
else:
|
||||
assert parentKey is not None
|
||||
self.parentKey = parentKey
|
||||
|
||||
def copy(self) -> 'AliasNode':
|
||||
return self.__class__(self.sig, self.maxdepth, self.document,
|
||||
env=None, parentKey=self.parentKey)
|
||||
|
||||
|
||||
class AliasTransform(SphinxTransform):
|
||||
default_priority = ReferencesResolver.default_priority - 1
|
||||
|
||||
def _render_symbol(self, s: Symbol, maxdepth: int, document: Any) -> List[Node]:
|
||||
nodes = [] # type: List[Node]
|
||||
options = dict() # type: ignore
|
||||
signode = addnodes.desc_signature('', '')
|
||||
nodes.append(signode)
|
||||
s.declaration.describe_signature(signode, 'markName', self.env, options)
|
||||
if maxdepth == 0:
|
||||
recurse = True
|
||||
elif maxdepth == 1:
|
||||
recurse = False
|
||||
else:
|
||||
maxdepth -= 1
|
||||
recurse = True
|
||||
if recurse:
|
||||
content = addnodes.desc_content()
|
||||
desc = addnodes.desc()
|
||||
content.append(desc)
|
||||
desc.document = document
|
||||
desc['domain'] = 'c'
|
||||
# 'desctype' is a backwards compatible attribute
|
||||
desc['objtype'] = desc['desctype'] = 'alias'
|
||||
desc['noindex'] = True
|
||||
|
||||
for sChild in s.children:
|
||||
childNodes = self._render_symbol(sChild, maxdepth, document)
|
||||
desc.extend(childNodes)
|
||||
|
||||
if len(desc.children) != 0:
|
||||
nodes.append(content)
|
||||
return nodes
|
||||
|
||||
def apply(self, **kwargs: Any) -> None:
|
||||
for node in self.document.traverse(AliasNode):
|
||||
sig = node.sig
|
||||
parentKey = node.parentKey
|
||||
try:
|
||||
parser = DefinitionParser(sig, location=node,
|
||||
config=self.env.config)
|
||||
name = parser.parse_xref_object()
|
||||
except DefinitionError as e:
|
||||
logger.warning(e, location=node)
|
||||
name = None
|
||||
|
||||
if name is None:
|
||||
# could not be parsed, so stop here
|
||||
signode = addnodes.desc_signature(sig, '')
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
|
||||
rootSymbol = self.env.domains['c'].data['root_symbol'] # type: Symbol
|
||||
parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
|
||||
if not parentSymbol:
|
||||
print("Target: ", sig)
|
||||
print("ParentKey: ", parentKey)
|
||||
print(rootSymbol.dump(1))
|
||||
assert parentSymbol # should be there
|
||||
|
||||
s = parentSymbol.find_declaration(
|
||||
name, 'any',
|
||||
matchSelf=True, recurseInAnon=True)
|
||||
if s is None:
|
||||
signode = addnodes.desc_signature(sig, '')
|
||||
node.append(signode)
|
||||
signode.clear()
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
|
||||
logger.warning("Could not find C declaration for alias '%s'." % name,
|
||||
location=node)
|
||||
node.replace_self(signode)
|
||||
continue
|
||||
|
||||
nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
|
||||
node.replace_self(nodes)
|
||||
|
||||
|
||||
class CAliasObject(ObjectDescription):
|
||||
option_spec = {
|
||||
'maxdepth': directives.nonnegative_int
|
||||
} # type: Dict
|
||||
|
||||
def run(self) -> List[Node]:
|
||||
if ':' in self.name:
|
||||
self.domain, self.objtype = self.name.split(':', 1)
|
||||
else:
|
||||
self.domain, self.objtype = '', self.name
|
||||
|
||||
node = addnodes.desc()
|
||||
node.document = self.state.document
|
||||
node['domain'] = self.domain
|
||||
# 'desctype' is a backwards compatible attribute
|
||||
node['objtype'] = node['desctype'] = self.objtype
|
||||
node['noindex'] = True
|
||||
|
||||
self.names = [] # type: List[str]
|
||||
maxdepth = self.options.get('maxdepth', 1)
|
||||
signatures = self.get_signatures()
|
||||
for i, sig in enumerate(signatures):
|
||||
node.append(AliasNode(sig, maxdepth, self.state.document, env=self.env))
|
||||
return [node]
|
||||
|
||||
|
||||
class CXRefRole(XRefRole):
|
||||
def process_link(self, env: BuildEnvironment, refnode: Element,
|
||||
has_explicit_title: bool, title: str, target: str) -> Tuple[str, str]:
|
||||
@ -3330,6 +3583,39 @@ class CXRefRole(XRefRole):
|
||||
title = title[dot + 1:]
|
||||
return title, target
|
||||
|
||||
def run(self) -> Tuple[List[Node], List[system_message]]:
|
||||
if not self.env.config['c_allow_pre_v3']:
|
||||
return super().run()
|
||||
|
||||
text = self.text.replace('\n', ' ')
|
||||
parser = DefinitionParser(text, location=self.get_source_info(),
|
||||
config=self.env.config)
|
||||
try:
|
||||
parser.parse_xref_object()
|
||||
# it succeeded, so let it through
|
||||
return super().run()
|
||||
except DefinitionError as eOrig:
|
||||
# try as if it was an c:expr
|
||||
parser.pos = 0
|
||||
try:
|
||||
ast = parser.parse_expression()
|
||||
except DefinitionError:
|
||||
# that didn't go well, just default back
|
||||
return super().run()
|
||||
classes = ['xref', 'c', 'c-texpr']
|
||||
parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None)
|
||||
if parentSymbol is None:
|
||||
parentSymbol = self.env.domaindata['c']['root_symbol']
|
||||
signode = nodes.inline(classes=classes)
|
||||
ast.describe_signature(signode, 'markType', self.env, parentSymbol)
|
||||
|
||||
if self.env.config['c_warn_on_allowed_pre_v3']:
|
||||
msg = "{}: Pre-v3 C type role ':c:type:`{}`' converted to ':c:expr:`{}`'."
|
||||
msg += "\nThe original parsing error was:\n{}"
|
||||
msg = msg.format(RemovedInSphinx50Warning.__name__, text, text, eOrig)
|
||||
logger.warning(msg, location=self.get_source_info())
|
||||
return [signode], []
|
||||
|
||||
|
||||
class CExprRole(SphinxRole):
|
||||
def __init__(self, asCode: bool) -> None:
|
||||
@ -3356,7 +3642,7 @@ class CExprRole(SphinxRole):
|
||||
location=self.get_source_info())
|
||||
# see below
|
||||
return [self.node_type(text, text, classes=classes)], []
|
||||
parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None)
|
||||
parentSymbol = self.env.temp_data.get('c:parent_symbol', None)
|
||||
if parentSymbol is None:
|
||||
parentSymbol = self.env.domaindata['c']['root_symbol']
|
||||
# ...most if not all of these classes should really apply to the individual references,
|
||||
@ -3371,11 +3657,18 @@ class CDomain(Domain):
|
||||
name = 'c'
|
||||
label = 'C'
|
||||
object_types = {
|
||||
'function': ObjType(_('function'), 'func'),
|
||||
'member': ObjType(_('member'), 'member'),
|
||||
'macro': ObjType(_('macro'), 'macro'),
|
||||
'type': ObjType(_('type'), 'type'),
|
||||
'var': ObjType(_('variable'), 'data'),
|
||||
# 'identifier' is the one used for xrefs generated in signatures, not in roles
|
||||
'member': ObjType(_('member'), 'var', 'member', 'data', 'identifier'),
|
||||
'var': ObjType(_('variable'), 'var', 'member', 'data', 'identifier'),
|
||||
'function': ObjType(_('function'), 'func', 'identifier', 'type'),
|
||||
'macro': ObjType(_('macro'), 'macro', 'identifier'),
|
||||
'struct': ObjType(_('struct'), 'struct', 'identifier', 'type'),
|
||||
'union': ObjType(_('union'), 'union', 'identifier', 'type'),
|
||||
'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
|
||||
'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
|
||||
'type': ObjType(_('type'), 'identifier', 'type'),
|
||||
# generated object types
|
||||
'functionParam': ObjType(_('function parameter'), 'identifier', 'var', 'member', 'data'), # noqa
|
||||
}
|
||||
|
||||
directives = {
|
||||
@ -3392,6 +3685,8 @@ class CDomain(Domain):
|
||||
'namespace': CNamespaceObject,
|
||||
'namespace-push': CNamespacePushObject,
|
||||
'namespace-pop': CNamespacePopObject,
|
||||
# other
|
||||
'alias': CAliasObject
|
||||
}
|
||||
roles = {
|
||||
'member': CXRefRole(),
|
||||
@ -3408,22 +3703,10 @@ class CDomain(Domain):
|
||||
'texpr': CExprRole(asCode=False)
|
||||
}
|
||||
initial_data = {
|
||||
'root_symbol': Symbol(None, None, None, None),
|
||||
'root_symbol': Symbol(None, None, None, None, None),
|
||||
'objects': {}, # fullname -> docname, node_id, objtype
|
||||
} # type: Dict[str, Union[Symbol, Dict[str, Tuple[str, str, str]]]]
|
||||
|
||||
@property
|
||||
def objects(self) -> Dict[str, Tuple[str, str, str]]:
|
||||
return self.data.setdefault('objects', {}) # fullname -> docname, node_id, objtype
|
||||
|
||||
def note_object(self, name: str, objtype: str, node_id: str, location: Any = None) -> None:
|
||||
if name in self.objects:
|
||||
docname = self.objects[name][0]
|
||||
logger.warning(__('Duplicate C object description of %s, '
|
||||
'other instance in %s, use :noindex: for one of them'),
|
||||
name, docname, location=location)
|
||||
self.objects[name] = (self.env.docname, node_id, objtype)
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
if Symbol.debug_show_tree:
|
||||
print("clear_doc:", docname)
|
||||
@ -3439,9 +3722,6 @@ class CDomain(Domain):
|
||||
print(self.data['root_symbol'].dump(1))
|
||||
print("\tafter end")
|
||||
print("clear_doc end:", docname)
|
||||
for fullname, (fn, _id, _l) in list(self.objects.items()):
|
||||
if fn == docname:
|
||||
del self.objects[fullname]
|
||||
|
||||
def process_doc(self, env: BuildEnvironment, docname: str,
|
||||
document: nodes.document) -> None:
|
||||
@ -3469,13 +3749,9 @@ class CDomain(Domain):
|
||||
ourObjects = self.data['objects']
|
||||
for fullname, (fn, id_, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
if fullname in ourObjects:
|
||||
msg = __("Duplicate declaration, also defined in '%s'.\n"
|
||||
"Name of declaration is '%s'.")
|
||||
msg = msg % (ourObjects[fullname], fullname)
|
||||
logger.warning(msg, location=fn)
|
||||
else:
|
||||
if fullname not in ourObjects:
|
||||
ourObjects[fullname] = (fn, id_, objtype)
|
||||
# no need to warn on duplicates, the symbol merge already does that
|
||||
|
||||
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
typ: str, target: str, node: pending_xref,
|
||||
@ -3531,14 +3807,28 @@ class CDomain(Domain):
|
||||
return []
|
||||
|
||||
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
|
||||
for refname, (docname, node_id, objtype) in list(self.objects.items()):
|
||||
yield (refname, refname, objtype, docname, node_id, 1)
|
||||
rootSymbol = self.data['root_symbol']
|
||||
for symbol in rootSymbol.get_all_symbols():
|
||||
if symbol.declaration is None:
|
||||
continue
|
||||
assert symbol.docname
|
||||
fullNestedName = symbol.get_full_nested_name()
|
||||
name = str(fullNestedName).lstrip('.')
|
||||
dispname = fullNestedName.get_display_string().lstrip('.')
|
||||
objectType = symbol.declaration.objectType
|
||||
docname = symbol.docname
|
||||
newestId = symbol.declaration.get_newest_id()
|
||||
yield (name, dispname, objectType, docname, newestId, 1)
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_domain(CDomain)
|
||||
app.add_config_value("c_id_attributes", [], 'env')
|
||||
app.add_config_value("c_paren_attributes", [], 'env')
|
||||
app.add_post_transform(AliasTransform)
|
||||
|
||||
app.add_config_value("c_allow_pre_v3", False, 'env')
|
||||
app.add_config_value("c_warn_on_allowed_pre_v3", True, 'env')
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user