mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '5.x'
# Conflicts: # CHANGES # doc/conf.py # sphinx/__init__.py # sphinx/builders/html/__init__.py # sphinx/domains/python.py # tests/test_build_html.py
This commit is contained in:
commit
f01d50d695
85
CHANGES
85
CHANGES
@ -21,16 +21,12 @@ Bugs fixed
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 5.2.0 (in development)
|
||||
Release 5.3.0 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* #10356: Sphinx now uses declarative metadata with ``pyproject.toml`` to
|
||||
create packages, using PyPA's ``build`` project as a build backend. Patch by
|
||||
Adam Turner.
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
@ -40,6 +36,47 @@ Deprecated
|
||||
Features added
|
||||
--------------
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 5.2.1 (released Sep 24, 2022)
|
||||
=====================================
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #10861: Always normalise the ``pycon3`` lexer to ``pycon``.
|
||||
* Fix using ``sphinx.ext.autosummary`` with modules containing titles in the
|
||||
module-level docstring.
|
||||
|
||||
Release 5.2.0.post0 (released Sep 24, 2022)
|
||||
===========================================
|
||||
|
||||
* Recreated source tarballs for Debian maintainers.
|
||||
|
||||
Release 5.2.0 (released Sep 24, 2022)
|
||||
=====================================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* #10356: Sphinx now uses declarative metadata with ``pyproject.toml`` to
|
||||
create packages, using PyPA's ``flit`` project as a build backend. Patch by
|
||||
Adam Turner.
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
|
||||
* #10843: Support for HTML 4 output. Patch by Adam Turner.
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #10738: napoleon: Add support for docstring types using 'of', like
|
||||
``type of type``. Example: ``tuple of int``.
|
||||
* #10286: C++, support requires clauses not just between the template
|
||||
parameter lists and the declaration.
|
||||
* #10755: linkcheck: Check the source URL of raw directives that use the ``url``
|
||||
@ -53,44 +90,18 @@ Features added
|
||||
* #6692: HTML Search: Include explicit :rst:dir:`index` directive index entries
|
||||
in the search index and search results. Patch by Adam Turner
|
||||
* #10816: imgmath: Allow embedding images in HTML as base64
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #10257: C++, ensure consistent non-specialization template argument
|
||||
representation.
|
||||
* #10729: C++, fix parsing of certain non-type template parameter packs.
|
||||
* #10715: Revert #10520: "Fix" use of sidebar classes in ``agogo.css_t``
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
||||
Release 5.1.2 (in development)
|
||||
==============================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
|
||||
Features added
|
||||
--------------
|
||||
|
||||
* #10738: napoleon: Add support for docstring types using 'of', like
|
||||
``type of type``. Example: ``tuple of int``.
|
||||
* #10854: HTML Search: Use browser localstorage for highlight control, stop
|
||||
storing highlight parameters in URL query strings. Patch by Adam Turner.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
||||
* #10723: LaTeX: 5.1.0 has made the 'sphinxsetup' ``verbatimwithframe=false``
|
||||
become without effect.
|
||||
|
||||
Testing
|
||||
--------
|
||||
* #10257: C++, ensure consistent non-specialization template argument
|
||||
representation.
|
||||
* #10729: C++, fix parsing of certain non-type template parameter packs.
|
||||
* #10715: Revert #10520: "Fix" use of sidebar classes in ``agogo.css_t``
|
||||
|
||||
Release 5.1.1 (released Jul 26, 2022)
|
||||
=====================================
|
||||
|
@ -11,5 +11,12 @@ Changelog
|
||||
.. raw:: latex
|
||||
|
||||
\addtocontents{toc}{\protect\setcounter{tocdepth}{1}}%
|
||||
\makeatletter
|
||||
\addtocontents{toc}%
|
||||
{\def\string\l@section{\string\@dottedtocline{1}{1.5em}{3.3em}}}
|
||||
\addtocontents{toc}%
|
||||
{\def\string\l@subsection{\string\@dottedtocline{2}{4.8em}{4em}}}
|
||||
\makeatother
|
||||
|
||||
|
||||
.. include:: ../CHANGES
|
||||
|
@ -48,6 +48,7 @@ epub_post_files = [('usage/installation.xhtml', 'Installing Sphinx'),
|
||||
('develop.xhtml', 'Sphinx development')]
|
||||
epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js',
|
||||
'_static/searchtools.js',
|
||||
'_static/sphinx_highlight.js',
|
||||
'_static/basic.css',
|
||||
'_static/language_data.js',
|
||||
'search.html', '_static/websupport.js']
|
||||
|
@ -22,6 +22,11 @@ The following is a list of deprecated interfaces.
|
||||
- (will be) Removed
|
||||
- Alternatives
|
||||
|
||||
* - HTML 4 support
|
||||
- 5.2
|
||||
- 7.0
|
||||
- N/A
|
||||
|
||||
* - ``sphinx.util.path_stabilize``
|
||||
- 5.1
|
||||
- 7.0
|
||||
|
@ -1300,6 +1300,12 @@ Macros
|
||||
``\sphinxtableofcontentshook``. This macro is also executed by the
|
||||
``'howto'`` docclass, but defaults to empty with it.
|
||||
|
||||
.. hint::
|
||||
|
||||
If adding to preamble the loading of ``tocloft`` package, also add to
|
||||
preamble ``\renewcommand\sphinxtableofcontentshook{}`` else it will reset
|
||||
``\l@section`` and ``\l@subsection`` cancelling ``tocloft`` customization.
|
||||
|
||||
- ``\sphinxmaketitle``: Used as the default setting of the ``'maketitle'``
|
||||
:confval:`latex_elements` key.
|
||||
Defined in the class files :file:`sphinxmanual.cls` and
|
||||
|
@ -15,8 +15,10 @@ module.exports = function(config) {
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'tests/js/documentation_options.js',
|
||||
'sphinx/themes/basic/static/doctools.js',
|
||||
'sphinx/themes/basic/static/searchtools.js',
|
||||
'sphinx/themes/basic/static/sphinx_highlight.js',
|
||||
'tests/js/*.js'
|
||||
],
|
||||
|
||||
|
@ -150,6 +150,7 @@ show_error_context = true
|
||||
strict_optional = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = true
|
||||
disallow_any_generics = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
@ -181,6 +182,30 @@ module = [
|
||||
]
|
||||
strict_optional = false
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"sphinx.application",
|
||||
"sphinx.builders.*",
|
||||
"sphinx.cmd.*",
|
||||
"sphinx.config",
|
||||
"sphinx.deprecation",
|
||||
"sphinx.domains.*",
|
||||
"sphinx.environment.*",
|
||||
"sphinx.events",
|
||||
"sphinx.ext.*",
|
||||
"sphinx.highlighting",
|
||||
"sphinx.jinja2glue",
|
||||
"sphinx.locale",
|
||||
"sphinx.pycode.*",
|
||||
"sphinx.registry",
|
||||
"sphinx.roles",
|
||||
"sphinx.search.*",
|
||||
"sphinx.testing.*",
|
||||
"sphinx.util.*",
|
||||
"sphinx.writers.*",
|
||||
]
|
||||
disallow_any_generics = false
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
filterwarnings = [
|
||||
"all",
|
||||
|
@ -1,4 +1,4 @@
|
||||
"""Additional docutils nodes."""
|
||||
"""Document tree nodes that Sphinx defines on top of those in Docutils."""
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence
|
||||
|
||||
@ -119,7 +119,7 @@ class toctree(nodes.General, nodes.Element, translatable):
|
||||
#############################################################
|
||||
|
||||
class _desc_classes_injector(nodes.Element, not_smartquotable):
|
||||
"""Helper base class for injecting a fixes list of classes.
|
||||
"""Helper base class for injecting a fixed list of classes.
|
||||
|
||||
Use as the first base class.
|
||||
"""
|
||||
@ -390,7 +390,7 @@ class index(nodes.Invisible, nodes.Inline, nodes.TextElement):
|
||||
|
||||
|
||||
class centered(nodes.Part, nodes.TextElement):
|
||||
"""Deprecated."""
|
||||
"""This node is deprecated."""
|
||||
|
||||
|
||||
class acks(nodes.Element):
|
||||
@ -455,13 +455,18 @@ class pending_xref(nodes.Inline, nodes.Element):
|
||||
|
||||
|
||||
class pending_xref_condition(nodes.Inline, nodes.TextElement):
|
||||
"""Node for cross-references that are used to choose appropriate
|
||||
content of the reference by conditions on the resolving phase.
|
||||
"""Node representing a potential way to create a cross-reference and the
|
||||
condition in which this way should be used.
|
||||
|
||||
When the :py:class:`pending_xref` node contains one or more
|
||||
**pending_xref_condition** nodes, the cross-reference resolver
|
||||
should choose the content of the reference using defined conditions
|
||||
in ``condition`` attribute of each pending_xref_condition nodes::
|
||||
This node is only allowed to be placed under a :py:class:`pending_xref`
|
||||
node. A **pending_xref** node must contain either no **pending_xref_condition**
|
||||
nodes or it must only contains **pending_xref_condition** nodes.
|
||||
|
||||
The cross-reference resolver will replace a :py:class:`pending_xref` which
|
||||
contains **pending_xref_condition** nodes by the content of exactly one of
|
||||
those **pending_xref_condition** nodes' content. It uses the **condition**
|
||||
attribute to decide which **pending_xref_condition** node's content to
|
||||
use. For example, let us consider how the cross-reference resolver acts on::
|
||||
|
||||
<pending_xref refdomain="py" reftarget="io.StringIO ...>
|
||||
<pending_xref_condition condition="resolved">
|
||||
@ -471,32 +476,26 @@ class pending_xref_condition(nodes.Inline, nodes.TextElement):
|
||||
<literal>
|
||||
io.StringIO
|
||||
|
||||
After the processing of cross-reference resolver, one of the content node
|
||||
under pending_xref_condition node is chosen by its condition and to be
|
||||
removed all of pending_xref_condition nodes::
|
||||
If the cross-reference resolver successfully resolves the cross-reference,
|
||||
then it rewrites the **pending_xref** as::
|
||||
|
||||
# When resolved the cross-reference successfully
|
||||
<reference>
|
||||
<literal>
|
||||
StringIO
|
||||
|
||||
# When resolution is failed
|
||||
Otherwise, if the cross-reference resolution failed, it rewrites the
|
||||
**pending_xref** as::
|
||||
|
||||
<reference>
|
||||
<literal>
|
||||
io.StringIO
|
||||
|
||||
.. note:: This node is only allowed to be placed under pending_xref node.
|
||||
It is not allows to place it under other nodes. In addition,
|
||||
pending_xref node must contain only pending_xref_condition
|
||||
nodes if it contains one or more pending_xref_condition nodes.
|
||||
|
||||
The pending_xref_condition node should have **condition** attribute.
|
||||
The **pending_xref_condition** node should have **condition** attribute.
|
||||
Domains can be store their individual conditions into the attribute to
|
||||
filter contents on resolving phase. As a reserved condition name,
|
||||
``condition="*"`` is used for the fallback of resolution failure.
|
||||
Additionally, as a recommended condition name, ``condition="resolved"``
|
||||
is used for the representation of resolstion success in the intersphinx
|
||||
module.
|
||||
represents a resolution success in the intersphinx module.
|
||||
|
||||
.. versionadded:: 4.0
|
||||
"""
|
||||
|
@ -636,8 +636,9 @@ class Sphinx:
|
||||
|
||||
:param name: The name of the directive
|
||||
:param cls: A directive class
|
||||
:param override: If true, install the directive forcedly even if another directive
|
||||
:param override: If false, do not install it if another directive
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the directive.
|
||||
|
||||
For example, a custom directive named ``my-directive`` would be added
|
||||
like this:
|
||||
@ -684,8 +685,9 @@ class Sphinx:
|
||||
|
||||
:param name: The name of role
|
||||
:param role: A role function
|
||||
:param override: If true, install the role forcedly even if another role is already
|
||||
installed as the same name
|
||||
:param override: If false, do not install it if another role
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the role.
|
||||
|
||||
For more details about role functions, see `the Docutils docs
|
||||
<https://docutils.sourceforge.io/docs/howto/rst-roles.html>`__ .
|
||||
@ -705,8 +707,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.
|
||||
:param override: If false, do not install it if another role
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the role.
|
||||
|
||||
.. versionadded:: 0.6
|
||||
.. versionchanged:: 1.8
|
||||
@ -725,8 +728,9 @@ class Sphinx:
|
||||
"""Register a domain.
|
||||
|
||||
:param domain: A domain class
|
||||
:param override: If true, install the domain forcedly even if another domain
|
||||
:param override: If false, do not install it if another domain
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the domain.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -744,8 +748,9 @@ class Sphinx:
|
||||
:param domain: The name of target domain
|
||||
:param name: A name of directive
|
||||
:param cls: A directive class
|
||||
:param override: If true, install the directive forcedly even if another directive
|
||||
:param override: If false, do not install it if another directive
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the directive.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -763,8 +768,9 @@ class Sphinx:
|
||||
:param domain: The name of the target domain
|
||||
:param name: The name of the role
|
||||
:param role: The role function
|
||||
:param override: If true, install the role forcedly even if another role is already
|
||||
installed as the same name
|
||||
:param override: If false, do not install it if another role
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the role.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -780,8 +786,9 @@ class Sphinx:
|
||||
|
||||
:param domain: The name of the target domain
|
||||
:param index: The index class
|
||||
:param override: If true, install the index forcedly even if another index is
|
||||
already installed as the same name
|
||||
:param override: If false, do not install it if another index
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the index.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
.. versionchanged:: 1.8
|
||||
@ -886,8 +893,10 @@ 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.
|
||||
|
||||
:param override: If false, do not install it if another cross-reference type
|
||||
is already installed as the same name
|
||||
If true, unconditionally install the cross-reference type.
|
||||
|
||||
.. versionchanged:: 1.8
|
||||
Add *override* keyword.
|
||||
@ -946,20 +955,22 @@ class Sphinx:
|
||||
loading_method: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""Register a JavaScript file to include in the HTML output.
|
||||
|
||||
:param filename: The filename of the JavaScript file. It must be relative to the HTML
|
||||
static path, a full URI with scheme, or ``None`` value. The ``None``
|
||||
value is used to create inline ``<script>`` tag. See the description
|
||||
of *kwargs* below.
|
||||
:param priority: The priority to determine the order of ``<script>`` tag for
|
||||
JavaScript files. See list of "prority range for JavaScript
|
||||
files" below. If the priority of the JavaScript files it the same
|
||||
as others, the JavaScript files will be loaded in order of
|
||||
registration.
|
||||
:param loading_method: The loading method of the JavaScript file. ``'async'`` or
|
||||
``'defer'`` is allowed.
|
||||
:param kwargs: Extra keyword arguments are included as attributes of the ``<script>``
|
||||
tag. A special keyword argument ``body`` is given, its value will be
|
||||
added between the ``<script>`` tag.
|
||||
:param filename: The name of a JavaScript file that the default HTML
|
||||
template will include. It must be relative to the HTML
|
||||
static path, or a full URI with scheme, or ``None`` .
|
||||
The ``None`` value is used to create an inline
|
||||
``<script>`` tag. See the description of *kwargs*
|
||||
below.
|
||||
:param priority: Files are included in ascending order of priority. If
|
||||
multiple JavaScript files have the same priority,
|
||||
those files will be included in order of registration.
|
||||
See list of "prority range for JavaScript files" below.
|
||||
:param loading_method: The loading method for the JavaScript file.
|
||||
Either ``'async'`` or ``'defer'`` are allowed.
|
||||
:param kwargs: Extra keyword arguments are included as attributes of the
|
||||
``<script>`` tag. If the special keyword argument
|
||||
``body`` is given, its value will be added as the content
|
||||
of the ``<script>`` tag.
|
||||
|
||||
Example::
|
||||
|
||||
@ -1012,14 +1023,15 @@ class Sphinx:
|
||||
def add_css_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None:
|
||||
"""Register a stylesheet to include in the HTML output.
|
||||
|
||||
:param filename: The filename of the CSS file. It must be relative to the HTML
|
||||
:param filename: The name of a CSS file that the default HTML
|
||||
template will include. It must be relative to the HTML
|
||||
static path, or a full URI with scheme.
|
||||
:param priority: The priority to determine the order of ``<link>`` tag for the
|
||||
CSS files. See list of "prority range for CSS files" below.
|
||||
If the priority of the CSS files it the same as others, the
|
||||
CSS files will be loaded in order of registration.
|
||||
:param kwargs: Extra keyword arguments are included as attributes of the ``<link>``
|
||||
tag.
|
||||
:param priority: Files are included in ascending order of priority. If
|
||||
multiple CSS files have the same priority,
|
||||
those files will be included in order of registration.
|
||||
See list of "prority range for CSS files" below.
|
||||
:param kwargs: Extra keyword arguments are included as attributes of the
|
||||
``<link>`` tag.
|
||||
|
||||
Example::
|
||||
|
||||
@ -1167,8 +1179,9 @@ class Sphinx:
|
||||
Same as :confval:`source_suffix`. The users can override this
|
||||
using the config setting.
|
||||
|
||||
If *override* is True, the given *suffix* is forcedly installed even if
|
||||
the same suffix is already installed.
|
||||
:param override: If false, do not install it the same suffix
|
||||
is already installed.
|
||||
If true, unconditionally install the suffix.
|
||||
|
||||
.. versionadded:: 1.8
|
||||
"""
|
||||
@ -1177,8 +1190,9 @@ class Sphinx:
|
||||
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.
|
||||
:param override: If false, do not install it if another parser
|
||||
is already installed for the same suffix.
|
||||
If true, unconditionally install the parser.
|
||||
|
||||
.. versionadded:: 1.4
|
||||
.. versionchanged:: 1.8
|
||||
|
@ -10,6 +10,7 @@ from typing import (TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Sequence
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.nodes import Node
|
||||
from docutils.utils import DependencyList
|
||||
|
||||
from sphinx.config import Config
|
||||
from sphinx.deprecation import RemovedInSphinx70Warning
|
||||
@ -490,6 +491,9 @@ class Builder:
|
||||
filename = self.env.doc2path(docname)
|
||||
filetype = get_filetype(self.app.config.source_suffix, filename)
|
||||
publisher = self.app.registry.get_publisher(self.app, filetype)
|
||||
# record_dependencies is mutable even though it is in settings,
|
||||
# explicitly re-initialise for each document
|
||||
publisher.settings.record_dependencies = DependencyList()
|
||||
with sphinx_domains(self.env), rst.default_role(docname, self.config.default_role):
|
||||
# set up error_handler for the target document
|
||||
codecs.register_error('sphinx', UnicodeDecodeErrorHandler(docname)) # type: ignore
|
||||
|
@ -349,6 +349,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
self.add_js_file('documentation_options.js', id="documentation_options",
|
||||
data_url_root='', priority=200)
|
||||
self.add_js_file('doctools.js', priority=200)
|
||||
self.add_js_file('sphinx_highlight.js', priority=200)
|
||||
|
||||
for filename, attrs in self.app.registry.js_files:
|
||||
self.add_js_file(filename, **attrs)
|
||||
@ -369,7 +370,7 @@ class StandaloneHTMLBuilder(Builder):
|
||||
@property
|
||||
def default_translator_class(self) -> Type[nodes.NodeVisitor]: # type: ignore
|
||||
if self.config.html4_writer:
|
||||
return HTMLTranslator
|
||||
return HTMLTranslator # RemovedInSphinx70Warning
|
||||
else:
|
||||
return HTML5Translator
|
||||
|
||||
@ -1303,6 +1304,15 @@ def validate_html_favicon(app: Sphinx, config: Config) -> None:
|
||||
config.html_favicon = None # type: ignore
|
||||
|
||||
|
||||
def deprecate_html_4(_app: Sphinx, config: Config) -> None:
|
||||
"""Warn on HTML 4."""
|
||||
# RemovedInSphinx70Warning
|
||||
if config.html4_writer:
|
||||
logger.warning(_('Support for emitting HTML 4 output is deprecated and '
|
||||
'will be removed in Sphinx 7. ("html4_writer=True '
|
||||
'detected in configuration options)'))
|
||||
|
||||
|
||||
# for compatibility
|
||||
import sphinxcontrib.serializinghtml # NOQA
|
||||
|
||||
@ -1375,6 +1385,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.connect('config-inited', validate_html_static_path, priority=800)
|
||||
app.connect('config-inited', validate_html_logo, priority=800)
|
||||
app.connect('config-inited', validate_html_favicon, priority=800)
|
||||
app.connect('config-inited', deprecate_html_4, priority=800)
|
||||
app.connect('builder-inited', validate_math_renderer)
|
||||
app.connect('html-page-context', setup_css_tag_helper)
|
||||
app.connect('html-page-context', setup_js_tag_helper)
|
||||
|
@ -30,7 +30,7 @@ class FootnoteDocnameUpdater(SphinxTransform):
|
||||
|
||||
|
||||
class SubstitutionDefinitionsRemover(SphinxPostTransform):
|
||||
"""Remove ``substitution_definition node from doctrees."""
|
||||
"""Remove ``substitution_definition`` nodes from doctrees."""
|
||||
|
||||
# should be invoked after Substitutions process
|
||||
default_priority = Substitutions.default_priority + 1
|
||||
|
@ -493,12 +493,12 @@ class ProductionList(SphinxDirective):
|
||||
lines = nl_escape_re.sub('', self.arguments[0]).split('\n')
|
||||
|
||||
productionGroup = ""
|
||||
i = 0
|
||||
first_rule_seen = False
|
||||
for rule in lines:
|
||||
if i == 0 and ':' not in rule:
|
||||
if not first_rule_seen and ':' not in rule:
|
||||
productionGroup = rule.strip()
|
||||
continue
|
||||
i += 1
|
||||
first_rule_seen = True
|
||||
try:
|
||||
name, tokens = rule.split(':', 1)
|
||||
except ValueError:
|
||||
|
@ -939,6 +939,7 @@ class ModuleDocumenter(Documenter):
|
||||
objtype = 'module'
|
||||
content_indent = ''
|
||||
titles_allowed = True
|
||||
_extra_indent = ' '
|
||||
|
||||
option_spec: OptionSpec = {
|
||||
'members': members_option, 'undoc-members': bool_option,
|
||||
@ -958,7 +959,7 @@ class ModuleDocumenter(Documenter):
|
||||
|
||||
def add_content(self, more_content: Optional[StringList]) -> None:
|
||||
old_indent = self.indent
|
||||
self.indent += ' '
|
||||
self.indent += self._extra_indent
|
||||
super().add_content(None)
|
||||
self.indent = old_indent
|
||||
if more_content:
|
||||
|
@ -362,6 +362,9 @@ class Autosummary(SphinxDirective):
|
||||
|
||||
# -- Grab the summary
|
||||
|
||||
# bodge for ModuleDocumenter
|
||||
documenter._extra_indent = '' # type: ignore[attr-defined]
|
||||
|
||||
documenter.add_content(None)
|
||||
summary = extract_summary(self.bridge.result.data[:], self.state.document)
|
||||
|
||||
|
@ -94,15 +94,9 @@ class TestDirective(SphinxDirective):
|
||||
# only save if it differs from code
|
||||
node['test'] = test
|
||||
if self.name == 'doctest':
|
||||
if self.config.highlight_language in ('py', 'python'):
|
||||
node['language'] = 'pycon'
|
||||
else:
|
||||
node['language'] = 'pycon3' # default
|
||||
node['language'] = 'pycon'
|
||||
elif self.name == 'testcode':
|
||||
if self.config.highlight_language in ('py', 'python'):
|
||||
node['language'] = 'python'
|
||||
else:
|
||||
node['language'] = 'python3' # default
|
||||
node['language'] = 'python'
|
||||
elif self.name == 'testoutput':
|
||||
# don't try to highlight output
|
||||
node['language'] = 'none'
|
||||
|
@ -244,7 +244,7 @@ def collect_pages(app: Sphinx) -> Generator[Tuple[str, Dict[str, Any], str], Non
|
||||
# construct a page name for the highlighted source
|
||||
pagename = posixpath.join(OUTPUT_DIRNAME, modname.replace('.', '/'))
|
||||
# highlight the source using the builder's highlighter
|
||||
if env.config.highlight_language in ('python3', 'default', 'none'):
|
||||
if env.config.highlight_language in {'default', 'none'}:
|
||||
lexer = env.config.highlight_language
|
||||
else:
|
||||
lexer = 'python'
|
||||
|
@ -34,7 +34,14 @@ class Extension:
|
||||
|
||||
|
||||
def verify_needs_extensions(app: "Sphinx", config: Config) -> None:
|
||||
"""Verify the required Sphinx extensions are loaded."""
|
||||
"""Check that extensions mentioned in :confval:`needs_extensions` satisfy the version
|
||||
requirement, and warn if an extension is not loaded.
|
||||
|
||||
Warns if an extension in :confval:`needs_extension` is not loaded.
|
||||
|
||||
:raises VersionRequirementError: if the version of an extension in
|
||||
:confval:`needs_extension` is unknown or older than the required version.
|
||||
"""
|
||||
if config.needs_extensions is None:
|
||||
return
|
||||
|
||||
|
@ -120,6 +120,8 @@ class PygmentsBridge:
|
||||
lang = 'pycon'
|
||||
else:
|
||||
lang = 'python'
|
||||
if lang == 'pycon3':
|
||||
lang = 'pycon'
|
||||
|
||||
if lang in lexers:
|
||||
# just return custom lexers here (without installing raiseonerror filter)
|
||||
|
@ -290,9 +290,11 @@ class IndexBuilder:
|
||||
self._titles = dict(zip(index2fn, frozen['titles']))
|
||||
self._all_titles = {}
|
||||
|
||||
for docname in self._titles.keys():
|
||||
self._all_titles[docname] = []
|
||||
for title, doc_tuples in frozen['alltitles'].items():
|
||||
for doc, titleid in doc_tuples:
|
||||
self._all_titles.setdefault(index2fn[doc], []).append((title, titleid))
|
||||
self._all_titles[index2fn[doc]].append((title, titleid))
|
||||
|
||||
def load_terms(mapping: Dict[str, Any]) -> Dict[str, Set[str]]:
|
||||
rv = {}
|
||||
@ -380,12 +382,12 @@ class IndexBuilder:
|
||||
alltitles: Dict[str, List[Tuple[int, str]]] = {}
|
||||
for docname, titlelist in self._all_titles.items():
|
||||
for title, titleid in titlelist:
|
||||
alltitles.setdefault(title, []).append((fn2index[docname], titleid))
|
||||
alltitles.setdefault(title, []).append((fn2index[docname], titleid))
|
||||
|
||||
index_entries: Dict[str, List[Tuple[int, str]]] = {}
|
||||
for docname, entries in self._index_entries.items():
|
||||
for entry, entry_id, main_entry in entries:
|
||||
index_entries.setdefault(entry.lower(), []).append((fn2index[docname], entry_id))
|
||||
index_entries.setdefault(entry.lower(), []).append((fn2index[docname], entry_id))
|
||||
|
||||
return dict(docnames=docnames, filenames=filenames, titles=titles, terms=terms,
|
||||
objects=objects, objtypes=objtypes, objnames=objnames,
|
||||
|
@ -10,6 +10,13 @@
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([
|
||||
"TEXTAREA",
|
||||
"INPUT",
|
||||
"SELECT",
|
||||
"BUTTON",
|
||||
]);
|
||||
|
||||
const _ready = (callback) => {
|
||||
if (document.readyState !== "loading") {
|
||||
callback();
|
||||
@ -18,73 +25,11 @@ const _ready = (callback) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* highlight a given string on a node by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
const _highlight = (node, addItems, text, className) => {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
const val = node.nodeValue;
|
||||
const parent = node.parentNode;
|
||||
const pos = val.toLowerCase().indexOf(text);
|
||||
if (
|
||||
pos >= 0 &&
|
||||
!parent.classList.contains(className) &&
|
||||
!parent.classList.contains("nohighlight")
|
||||
) {
|
||||
let span;
|
||||
|
||||
const closestNode = parent.closest("body, svg, foreignObject");
|
||||
const isInSVG = closestNode && closestNode.matches("svg");
|
||||
if (isInSVG) {
|
||||
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
||||
} else {
|
||||
span = document.createElement("span");
|
||||
span.classList.add(className);
|
||||
}
|
||||
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
parent.insertBefore(
|
||||
span,
|
||||
parent.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling
|
||||
)
|
||||
);
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
|
||||
if (isInSVG) {
|
||||
const rect = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"rect"
|
||||
);
|
||||
const bbox = parent.getBBox();
|
||||
rect.x.baseVal.value = bbox.x;
|
||||
rect.y.baseVal.value = bbox.y;
|
||||
rect.width.baseVal.value = bbox.width;
|
||||
rect.height.baseVal.value = bbox.height;
|
||||
rect.setAttribute("class", className);
|
||||
addItems.push({ parent: parent, target: rect });
|
||||
}
|
||||
}
|
||||
} else if (node.matches && !node.matches("button, select, textarea")) {
|
||||
node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
|
||||
}
|
||||
};
|
||||
const _highlightText = (thisNode, text, className) => {
|
||||
let addItems = [];
|
||||
_highlight(thisNode, addItems, text, className);
|
||||
addItems.forEach((obj) =>
|
||||
obj.parent.insertAdjacentElement("beforebegin", obj.target)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Small JavaScript module for the documentation.
|
||||
*/
|
||||
const Documentation = {
|
||||
init: () => {
|
||||
Documentation.highlightSearchWords();
|
||||
Documentation.initDomainIndexTable();
|
||||
Documentation.initOnKeyListeners();
|
||||
},
|
||||
@ -126,51 +71,6 @@ const Documentation = {
|
||||
Documentation.LOCALE = catalog.locale;
|
||||
},
|
||||
|
||||
/**
|
||||
* highlight the search words provided in the url in the text
|
||||
*/
|
||||
highlightSearchWords: () => {
|
||||
const highlight =
|
||||
new URLSearchParams(window.location.search).get("highlight") || "";
|
||||
const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
|
||||
if (terms.length === 0) return; // nothing to do
|
||||
|
||||
// There should never be more than one element matching "div.body"
|
||||
const divBody = document.querySelectorAll("div.body");
|
||||
const body = divBody.length ? divBody[0] : document.querySelector("body");
|
||||
window.setTimeout(() => {
|
||||
terms.forEach((term) => _highlightText(body, term, "highlighted"));
|
||||
}, 10);
|
||||
|
||||
const searchBox = document.getElementById("searchbox");
|
||||
if (searchBox === null) return;
|
||||
searchBox.appendChild(
|
||||
document
|
||||
.createRange()
|
||||
.createContextualFragment(
|
||||
'<p class="highlight-link">' +
|
||||
'<a href="javascript:Documentation.hideSearchWords()">' +
|
||||
Documentation.gettext("Hide Search Matches") +
|
||||
"</a></p>"
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to hide the search marks again
|
||||
*/
|
||||
hideSearchWords: () => {
|
||||
document
|
||||
.querySelectorAll("#searchbox .highlight-link")
|
||||
.forEach((el) => el.remove());
|
||||
document
|
||||
.querySelectorAll("span.highlighted")
|
||||
.forEach((el) => el.classList.remove("highlighted"));
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.delete("highlight");
|
||||
window.history.replaceState({}, "", url);
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to focus on search bar
|
||||
*/
|
||||
@ -210,15 +110,11 @@ const Documentation = {
|
||||
)
|
||||
return;
|
||||
|
||||
const blacklistedElements = new Set([
|
||||
"TEXTAREA",
|
||||
"INPUT",
|
||||
"SELECT",
|
||||
"BUTTON",
|
||||
]);
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (blacklistedElements.has(document.activeElement.tagName)) return; // bail for input elements
|
||||
if (event.altKey || event.ctrlKey || event.metaKey) return; // bail with special keys
|
||||
// bail for input elements
|
||||
if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
|
||||
// bail with special keys
|
||||
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
||||
|
||||
if (!event.shiftKey) {
|
||||
switch (event.key) {
|
||||
@ -240,10 +136,6 @@ const Documentation = {
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
case "Escape":
|
||||
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;
|
||||
Documentation.hideSearchWords();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ const _removeChildren = (element) => {
|
||||
const _escapeRegExp = (string) =>
|
||||
string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
|
||||
|
||||
const _displayItem = (item, highlightTerms, searchTerms) => {
|
||||
const _displayItem = (item, searchTerms) => {
|
||||
const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;
|
||||
const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT;
|
||||
const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;
|
||||
@ -82,10 +82,8 @@ const _displayItem = (item, highlightTerms, searchTerms) => {
|
||||
requestUrl = docUrlRoot + docName + docFileSuffix;
|
||||
linkUrl = docName + docLinkSuffix;
|
||||
}
|
||||
const params = new URLSearchParams();
|
||||
params.set("highlight", [...highlightTerms].join(" "));
|
||||
let linkEl = listItem.appendChild(document.createElement("a"));
|
||||
linkEl.href = linkUrl + "?" + params.toString() + anchor;
|
||||
linkEl.href = linkUrl + anchor;
|
||||
linkEl.dataset.score = score;
|
||||
linkEl.innerHTML = title;
|
||||
if (descr)
|
||||
@ -97,7 +95,7 @@ const _displayItem = (item, highlightTerms, searchTerms) => {
|
||||
.then((data) => {
|
||||
if (data)
|
||||
listItem.appendChild(
|
||||
Search.makeSearchSummary(data, searchTerms, highlightTerms)
|
||||
Search.makeSearchSummary(data, searchTerms)
|
||||
);
|
||||
});
|
||||
Search.output.appendChild(listItem);
|
||||
@ -117,15 +115,14 @@ const _finishSearch = (resultCount) => {
|
||||
const _displayNextItem = (
|
||||
results,
|
||||
resultCount,
|
||||
highlightTerms,
|
||||
searchTerms
|
||||
) => {
|
||||
// results left, load the summary and display it
|
||||
// this is intended to be dynamic (don't sub resultsCount)
|
||||
if (results.length) {
|
||||
_displayItem(results.pop(), highlightTerms, searchTerms);
|
||||
_displayItem(results.pop(), searchTerms);
|
||||
setTimeout(
|
||||
() => _displayNextItem(results, resultCount, highlightTerms, searchTerms),
|
||||
() => _displayNextItem(results, resultCount, searchTerms),
|
||||
5
|
||||
);
|
||||
}
|
||||
@ -271,6 +268,10 @@ const Search = {
|
||||
}
|
||||
});
|
||||
|
||||
if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js
|
||||
localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" "))
|
||||
}
|
||||
|
||||
// console.debug("SEARCH: searching for:");
|
||||
// console.info("required: ", [...searchTerms]);
|
||||
// console.info("excluded: ", [...excludedTerms]);
|
||||
@ -286,7 +287,7 @@ const Search = {
|
||||
let score = Math.round(100 * queryLower.length / title.length)
|
||||
results.push([
|
||||
docNames[file],
|
||||
`${titles[file]} > ${title}`,
|
||||
titles[file] !== title ? `${titles[file]} > ${title}` : title,
|
||||
id !== null ? "#" + id : "",
|
||||
null,
|
||||
score,
|
||||
@ -359,7 +360,7 @@ const Search = {
|
||||
// console.info("search results:", Search.lastresults);
|
||||
|
||||
// print the results
|
||||
_displayNextItem(results, results.length, highlightTerms, searchTerms);
|
||||
_displayNextItem(results, results.length, searchTerms);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -538,11 +539,9 @@ const Search = {
|
||||
/**
|
||||
* helper function to return a node containing the
|
||||
* search summary for a given text. keywords is a list
|
||||
* of stemmed words, highlightWords is the list of normal, unstemmed
|
||||
* words. the first one is used to find the occurrence, the
|
||||
* latter for highlighting it.
|
||||
* of stemmed words.
|
||||
*/
|
||||
makeSearchSummary: (htmlText, keywords, highlightWords) => {
|
||||
makeSearchSummary: (htmlText, keywords) => {
|
||||
const text = Search.htmlToText(htmlText);
|
||||
if (text === "") return null;
|
||||
|
||||
@ -560,10 +559,6 @@ const Search = {
|
||||
summary.classList.add("context");
|
||||
summary.textContent = top + text.substr(startWithContext, 240).trim() + tail;
|
||||
|
||||
highlightWords.forEach((highlightWord) =>
|
||||
_highlightText(summary, highlightWord, "highlighted")
|
||||
);
|
||||
|
||||
return summary;
|
||||
},
|
||||
};
|
||||
|
144
sphinx/themes/basic/static/sphinx_highlight.js
Normal file
144
sphinx/themes/basic/static/sphinx_highlight.js
Normal file
@ -0,0 +1,144 @@
|
||||
/* Highlighting utilities for Sphinx HTML documentation. */
|
||||
"use strict";
|
||||
|
||||
const SPHINX_HIGHLIGHT_ENABLED = true
|
||||
|
||||
/**
|
||||
* highlight a given string on a node by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
const _highlight = (node, addItems, text, className) => {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
const val = node.nodeValue;
|
||||
const parent = node.parentNode;
|
||||
const pos = val.toLowerCase().indexOf(text);
|
||||
if (
|
||||
pos >= 0 &&
|
||||
!parent.classList.contains(className) &&
|
||||
!parent.classList.contains("nohighlight")
|
||||
) {
|
||||
let span;
|
||||
|
||||
const closestNode = parent.closest("body, svg, foreignObject");
|
||||
const isInSVG = closestNode && closestNode.matches("svg");
|
||||
if (isInSVG) {
|
||||
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
||||
} else {
|
||||
span = document.createElement("span");
|
||||
span.classList.add(className);
|
||||
}
|
||||
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
parent.insertBefore(
|
||||
span,
|
||||
parent.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling
|
||||
)
|
||||
);
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
|
||||
if (isInSVG) {
|
||||
const rect = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"rect"
|
||||
);
|
||||
const bbox = parent.getBBox();
|
||||
rect.x.baseVal.value = bbox.x;
|
||||
rect.y.baseVal.value = bbox.y;
|
||||
rect.width.baseVal.value = bbox.width;
|
||||
rect.height.baseVal.value = bbox.height;
|
||||
rect.setAttribute("class", className);
|
||||
addItems.push({ parent: parent, target: rect });
|
||||
}
|
||||
}
|
||||
} else if (node.matches && !node.matches("button, select, textarea")) {
|
||||
node.childNodes.forEach((el) => _highlight(el, addItems, text, className));
|
||||
}
|
||||
};
|
||||
const _highlightText = (thisNode, text, className) => {
|
||||
let addItems = [];
|
||||
_highlight(thisNode, addItems, text, className);
|
||||
addItems.forEach((obj) =>
|
||||
obj.parent.insertAdjacentElement("beforebegin", obj.target)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Small JavaScript module for the documentation.
|
||||
*/
|
||||
const SphinxHighlight = {
|
||||
|
||||
/**
|
||||
* highlight the search words provided in localstorage in the text
|
||||
*/
|
||||
highlightSearchWords: () => {
|
||||
if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight
|
||||
|
||||
// get and clear terms from localstorage
|
||||
const url = new URL(window.location);
|
||||
const highlight =
|
||||
localStorage.getItem("sphinx_highlight_terms")
|
||||
|| url.searchParams.get("highlight")
|
||||
|| "";
|
||||
localStorage.removeItem("sphinx_highlight_terms")
|
||||
url.searchParams.delete("highlight");
|
||||
window.history.replaceState({}, "", url);
|
||||
|
||||
// get individual terms from highlight string
|
||||
const terms = highlight.toLowerCase().split(/\s+/).filter(x => x);
|
||||
if (terms.length === 0) return; // nothing to do
|
||||
|
||||
// There should never be more than one element matching "div.body"
|
||||
const divBody = document.querySelectorAll("div.body");
|
||||
const body = divBody.length ? divBody[0] : document.querySelector("body");
|
||||
window.setTimeout(() => {
|
||||
terms.forEach((term) => _highlightText(body, term, "highlighted"));
|
||||
}, 10);
|
||||
|
||||
const searchBox = document.getElementById("searchbox");
|
||||
if (searchBox === null) return;
|
||||
searchBox.appendChild(
|
||||
document
|
||||
.createRange()
|
||||
.createContextualFragment(
|
||||
'<p class="highlight-link">' +
|
||||
'<a href="javascript:SphinxHighlight.hideSearchWords()">' +
|
||||
_("Hide Search Matches") +
|
||||
"</a></p>"
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* helper function to hide the search marks again
|
||||
*/
|
||||
hideSearchWords: () => {
|
||||
document
|
||||
.querySelectorAll("#searchbox .highlight-link")
|
||||
.forEach((el) => el.remove());
|
||||
document
|
||||
.querySelectorAll("span.highlighted")
|
||||
.forEach((el) => el.classList.remove("highlighted"));
|
||||
localStorage.removeItem("sphinx_highlight_terms")
|
||||
},
|
||||
|
||||
initEscapeListener: () => {
|
||||
// only install a listener if it is really needed
|
||||
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return;
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
// bail for input elements
|
||||
if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;
|
||||
// bail with special keys
|
||||
if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
|
||||
if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) {
|
||||
SphinxHighlight.hideSearchWords();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
_ready(SphinxHighlight.highlightSearchWords);
|
||||
_ready(SphinxHighlight.initEscapeListener);
|
@ -109,9 +109,9 @@ class TrimDoctestFlagsTransform(SphinxTransform):
|
||||
return False # skip parsed-literal node
|
||||
|
||||
language = node.get('language')
|
||||
if language in ('pycon', 'pycon3'):
|
||||
if language in {'pycon', 'pycon3'}:
|
||||
return True
|
||||
elif language in ('py', 'py3', 'python', 'python3', 'default'):
|
||||
elif language in {'py', 'python', 'py3', 'python3', 'default'}:
|
||||
return node.rawsource.startswith('>>>')
|
||||
elif language == 'guess':
|
||||
try:
|
||||
|
@ -65,6 +65,7 @@ class HTMLWriter(Writer):
|
||||
self.clean_meta = ''.join(self.visitor.meta[2:])
|
||||
|
||||
|
||||
# RemovedInSphinx70Warning
|
||||
class HTMLTranslator(SphinxTranslator, BaseTranslator):
|
||||
"""
|
||||
Our custom HTML translator.
|
||||
|
1
tests/js/documentation_options.js
Normal file
1
tests/js/documentation_options.js
Normal file
@ -0,0 +1 @@
|
||||
const DOCUMENTATION_OPTIONS = {};
|
@ -1,5 +1,3 @@
|
||||
const DOCUMENTATION_OPTIONS = {};
|
||||
|
||||
describe('highlightText', function() {
|
||||
|
||||
const cyrillicTerm = 'шеллы';
|
4
tests/roots/test-environment-record-dependencies/api.rst
Normal file
4
tests/roots/test-environment-record-dependencies/api.rst
Normal file
@ -0,0 +1,4 @@
|
||||
API
|
||||
===
|
||||
|
||||
.. automodule:: example_module
|
5
tests/roots/test-environment-record-dependencies/conf.py
Normal file
5
tests/roots/test-environment-record-dependencies/conf.py
Normal file
@ -0,0 +1,5 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('.'))
|
||||
extensions = ['sphinx.ext.autodoc']
|
@ -0,0 +1,2 @@
|
||||
def example_function():
|
||||
return 42
|
@ -0,0 +1,3 @@
|
||||
.. toctree::
|
||||
|
||||
api
|
@ -131,6 +131,16 @@ def test_html4_output(app, status, warning):
|
||||
app.build()
|
||||
|
||||
|
||||
def test_html4_deprecation(make_app, tempdir):
|
||||
(tempdir / 'conf.py').write_text('', encoding='utf-8')
|
||||
app = make_app(
|
||||
buildername='html',
|
||||
srcdir=tempdir,
|
||||
confoverrides={'html4_writer': True},
|
||||
)
|
||||
assert 'HTML 4 output is deprecated and will be removed' in app._warning.getvalue()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fname,expect", flat_dict({
|
||||
'images.html': [
|
||||
(".//img[@src='_images/img.png']", ''),
|
||||
@ -1222,7 +1232,8 @@ def test_assets_order(app):
|
||||
|
||||
# js_files
|
||||
expected = ['_static/early.js',
|
||||
'_static/doctools.js', 'https://example.com/script.js', '_static/normal.js',
|
||||
'_static/doctools.js', '_static/sphinx_highlight.js',
|
||||
'https://example.com/script.js', '_static/normal.js',
|
||||
'_static/late.js', '_static/js/custom.js', '_static/lazy.js']
|
||||
pattern = '.*'.join('src="%s"' % f for f in expected)
|
||||
assert re.search(pattern, content, re.S)
|
||||
|
10
tests/test_environment_record_dependencies.py
Normal file
10
tests/test_environment_record_dependencies.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""Tests for ``record_dependencies``."""
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='environment-record-dependencies')
|
||||
def test_record_dependencies_cleared(app):
|
||||
app.builder.read()
|
||||
assert app.env.dependencies['index'] == set()
|
||||
assert app.env.dependencies['api'] == {'example_module.py'}
|
@ -29,16 +29,16 @@ def test_highlight_language_default(app, status, warning):
|
||||
app.build()
|
||||
doctree = app.env.get_doctree('doctest')
|
||||
for node in doctree.findall(nodes.literal_block):
|
||||
assert node['language'] in ('python3', 'pycon3', 'none')
|
||||
assert node['language'] in {'python', 'pycon', 'none'}
|
||||
|
||||
|
||||
@pytest.mark.sphinx('dummy', testroot='ext-doctest',
|
||||
confoverrides={'highlight_language': 'python'})
|
||||
def test_highlight_language_python2(app, status, warning):
|
||||
def test_highlight_language_python3(app, status, warning):
|
||||
app.build()
|
||||
doctree = app.env.get_doctree('doctest')
|
||||
for node in doctree.findall(nodes.literal_block):
|
||||
assert node['language'] in ('python', 'pycon', 'none')
|
||||
assert node['language'] in {'python', 'pycon', 'none'}
|
||||
|
||||
|
||||
def test_is_allowed_version():
|
||||
|
@ -81,14 +81,23 @@ def test_default_highlight(logger):
|
||||
ret = bridge.highlight_block('reST ``like`` text', 'default')
|
||||
assert ret == '<div class="highlight"><pre><span></span>reST ``like`` text\n</pre></div>\n'
|
||||
|
||||
# python3: highlights as python3
|
||||
ret = bridge.highlight_block('print "Hello sphinx world"', 'python3')
|
||||
assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span> '
|
||||
'<span class="s2">"Hello sphinx world"</span>\n</pre></div>\n')
|
||||
# python: highlights as python3
|
||||
ret = bridge.highlight_block('print("Hello sphinx world")', 'python')
|
||||
assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span>'
|
||||
'<span class="p">(</span>'
|
||||
'<span class="s2">"Hello sphinx world"</span>'
|
||||
'<span class="p">)</span>\n</pre></div>\n')
|
||||
|
||||
# python3: raises error if highlighting failed
|
||||
ret = bridge.highlight_block('reST ``like`` text', 'python3')
|
||||
# python3: highlights as python3
|
||||
ret = bridge.highlight_block('print("Hello sphinx world")', 'python3')
|
||||
assert ret == ('<div class="highlight"><pre><span></span><span class="nb">print</span>'
|
||||
'<span class="p">(</span>'
|
||||
'<span class="s2">"Hello sphinx world"</span>'
|
||||
'<span class="p">)</span>\n</pre></div>\n')
|
||||
|
||||
# python: raises error if highlighting failed
|
||||
ret = bridge.highlight_block('reST ``like`` text', 'python')
|
||||
logger.warning.assert_called_with('Could not lex literal_block as "%s". '
|
||||
'Highlighting skipped.', 'python3',
|
||||
'Highlighting skipped.', 'python',
|
||||
type='misc', subtype='highlighting_failure',
|
||||
location=None)
|
||||
|
@ -14,7 +14,7 @@ for stable releases
|
||||
* ``twine upload dist/Sphinx-* --sign --identity [your GPG key]``
|
||||
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
|
||||
* ``sh utils/bump_docker.sh X.Y.Z``
|
||||
* ``git tag vX.Y.Z``
|
||||
* ``git tag vX.Y.Z -m "Sphinx X.Y.Z"``
|
||||
* ``python utils/bump_version.py --in-develop X.Y.Zb0`` (ex. 1.5.3b0)
|
||||
* Check diff by ``git diff``
|
||||
* ``git commit -am 'Bump version'``
|
||||
@ -37,7 +37,7 @@ for first beta releases
|
||||
* ``python -m build .``
|
||||
* ``twine upload dist/Sphinx-* --sign --identity [your GPG key]``
|
||||
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
|
||||
* ``git tag vX.Y.0b1``
|
||||
* ``git tag vX.Y.0b1 -m "Sphinx X.Y.0b1"``
|
||||
* ``python utils/bump_version.py --in-develop X.Y.0b2`` (ex. 1.6.0b2)
|
||||
* Check diff by ``git diff``
|
||||
* ``git commit -am 'Bump version'``
|
||||
@ -65,7 +65,7 @@ for other beta releases
|
||||
* ``python -m build .``
|
||||
* ``twine upload dist/Sphinx-* --sign --identity [your GPG key]``
|
||||
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
|
||||
* ``git tag vX.Y.0bN``
|
||||
* ``git tag vX.Y.0bN -m "Sphinx X.Y.0bN"``
|
||||
* ``python utils/bump_version.py --in-develop X.Y.0bM`` (ex. 1.6.0b3)
|
||||
* Check diff by `git diff``
|
||||
* ``git commit -am 'Bump version'``
|
||||
@ -91,7 +91,7 @@ for major releases
|
||||
* ``twine upload dist/Sphinx-* --sign --identity [your GPG key]``
|
||||
* open https://pypi.org/project/Sphinx/ and check there are no obvious errors
|
||||
* ``sh utils/bump_docker.sh X.Y.Z``
|
||||
* ``git tag vX.Y.0``
|
||||
* ``git tag vX.Y.0 -m "Sphinx X.Y.0"``
|
||||
* ``python utils/bump_version.py --in-develop X.Y.1b0`` (ex. 1.6.1b0)
|
||||
* Check diff by ``git diff``
|
||||
* ``git commit -am 'Bump version'``
|
||||
@ -101,7 +101,7 @@ for major releases
|
||||
* ``git push origin master``
|
||||
* open https://github.com/sphinx-doc/sphinx/settings/branches and make ``A.B`` branch *not* protected
|
||||
* ``git checkout A.B`` (checkout old stable)
|
||||
* Run ``git tag A.B`` to paste a tag instead branch
|
||||
* Run ``git tag A.B -m "Sphinx A.B"`` to paste a tag instead branch
|
||||
* Run ``git push origin :A.B --tags`` to remove old stable branch
|
||||
* open https://readthedocs.org/dashboard/sphinx/versions/ and enable the released version
|
||||
* Add new version/milestone to tracker categories
|
||||
|
Loading…
Reference in New Issue
Block a user