Merge branch '2.0'

This commit is contained in:
Takeshi KOMIYA 2019-11-30 21:52:42 +09:00
commit 15c266c445
33 changed files with 1309 additions and 2108 deletions

15
CHANGES
View File

@ -50,12 +50,15 @@ Deprecated
* ``sphinx.builders.gettext.POHEADER``
* ``sphinx.io.SphinxStandaloneReader.app``
* ``sphinx.io.SphinxStandaloneReader.env``
* ``sphinx.util.texescape.tex_escape_map``
* ``sphinx.util.texescape.tex_hl_escape_map_new``
Features added
--------------
* #6707: C++, support bit-fields.
* #267: html: Eliminate prompt characters of doctest block from copyable text
* #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
@ -63,10 +66,14 @@ Features added
* #1331: Add new config variable: :confval:`user_agent`
* #6000: LaTeX: have backslash also be an inline literal word wrap break
character
* #4186: LaTeX: Support upLaTeX as a new :confval:`latex_engine` (experimental)
* #6812: Improve a warning message when extensions are not parallel safe
* #6818: Improve Intersphinx performance for multiple remote inventories.
* #2546: apidoc: .so file support
* #6798: autosummary: emit ``autodoc-skip-member`` event on generating stub file
* #6483: i18n: make explicit titles in toctree translatable
* #6816: linkcheck: Add :confval:`linkcheck_auth` option to provide
authentication information when doing ``linkcheck`` builds
Bugs fixed
----------
@ -80,6 +87,7 @@ Bugs fixed
supported LaTeX engines: ¶, §, €, ∞, ±, →, ‣, , superscript and subscript
digits go through "as is" (as default OpenType font supports them)
* #6704: linkcheck: Be defensive and handle newly defined HTTP error code
* #6806: linkcheck: Failure on parsing content
* #6655: image URLs containing ``data:`` causes gettext builder crashed
* #6584: i18n: Error when compiling message catalogs on Hindi
* #6718: i18n: KeyError is raised if section title and table title are same
@ -95,6 +103,13 @@ Bugs fixed
* #6809: LaTeX: code-block in a danger type admonition can easily spill over
bottom of page
* #6793: texinfo: Code examples broken following "sidebar"
* #6813: An orphan warning is emitted for included document on Windows. Thanks
to @drillan
* #6850: Fix smartypants module calls re.sub() with wrong options
* #6824: HTML search: If a search term is partially matched in the title and
fully matched in a text paragraph on the same page, the search does not
include this match.
* #6848: config.py shouldn't pop extensions from overrides
Testing
--------

View File

@ -41,6 +41,16 @@ The following is a list of deprecated interfaces.
- 4.0
- ``sphinx.io.SphinxStandaloneReader.setup()``
* - ``sphinx.util.texescape.tex_escape_map``
- 2.3
- 4.0
- ``sphinx.util.texescape.escape()``
* - ``sphinx.util.texescape.tex_hl_escape_map_new``
- 2.3
- 4.0
- ``sphinx.util.texescape.hlescape()``
* - ``sphinx.domains.math.MathDomain.add_equation()``
- 2.2
- 4.0

View File

@ -538,7 +538,7 @@ General configuration
directory pointed ``REQUESTS_CA_BUNDLE`` environment
variable if ``tls_cacerts`` not set.
.. _requests: http://docs.python-requests.org/en/master/
.. _requests: https://requests.readthedocs.io/en/master/
.. confval:: today
today_fmt
@ -662,12 +662,17 @@ documentation on :ref:`intl` for details.
Currently supported languages by Sphinx are:
* ``ar`` -- Arabic
* ``bn`` -- Bengali
* ``ca`` -- Catalan
* ``cak`` -- Kaqchikel
* ``cs`` -- Czech
* ``cy`` -- Welsh
* ``da`` -- Danish
* ``de`` -- German
* ``el`` -- Greek
* ``en`` -- English
* ``eo`` -- Esperanto
* ``es`` -- Spanish
* ``et`` -- Estonian
* ``eu`` -- Basque
@ -675,6 +680,7 @@ documentation on :ref:`intl` for details.
* ``fi`` -- Finnish
* ``fr`` -- French
* ``he`` -- Hebrew
* ``hi`` -- Hindi
* ``hr`` -- Croatian
* ``hu`` -- Hungarian
* ``id`` -- Indonesian
@ -688,15 +694,20 @@ documentation on :ref:`intl` for details.
* ``ne`` -- Nepali
* ``nl`` -- Dutch
* ``pl`` -- Polish
* ``pt`` -- Portuguese
* ``pt_BR`` -- Brazilian Portuguese
* ``pt_PT`` -- European Portuguese
* ``ro`` -- Romanian
* ``ru`` -- Russian
* ``si`` -- Sinhala
* ``sk`` -- Slovak
* ``sl`` -- Slovenian
* ``sr`` -- Serbian
* ``sv`` -- Swedish
* ``ta`` -- Tamil
* ``tr`` -- Turkish
* ``uk_UA`` -- Ukrainian
* ``ur`` -- Urdu
* ``vi`` -- Vietnamese
* ``zh_CN`` -- Simplified Chinese
* ``zh_TW`` -- Traditional Chinese
@ -1836,6 +1847,7 @@ These options influence LaTeX output.
* ``'xelatex'`` -- XeLaTeX
* ``'lualatex'`` -- LuaLaTeX
* ``'platex'`` -- pLaTeX (default if :confval:`language` is ``'ja'``)
* ``'uplatex'`` -- upLaTeX (experimental)
``'pdflatex'``\ 's support for Unicode characters is limited.
@ -1861,6 +1873,10 @@ These options influence LaTeX output.
Use ``xelatex`` by default for Greek documents.
.. versionchanged:: 2.3
Add ``uplatex`` support.
Contrarily to :ref:`MathJaX math rendering in HTML output <math-support>`,
LaTeX requires some extra configuration to support Unicode literals in
:rst:dir:`math`: the only comprehensive solution (as far as we know) is to
@ -2364,6 +2380,34 @@ Options for the linkcheck builder
.. versionadded:: 1.5
.. confval:: linkcheck_auth
Pass authentication information when doing a ``linkcheck`` build.
A list of ``(regex_pattern, auth_info)`` tuples where the items are:
*regex_pattern*
A regular expression that matches a URI.
*auth_info*
Authentication information to use for that URI. The value can be anything
that is understood by the ``requests`` library (see `requests
Authentication <requests-auth>`_ for details).
.. _requests-auth: https://requests.readthedocs.io/en/master/user/authentication/
The ``linkcheck`` builder will use the first matching ``auth_info`` value
it can find in the :confval:`linkcheck_auth` list, so values earlier in the
list have higher priority.
Example::
linkcheck_auth = [
('https://foo\.yourcompany\.com/.+', ('johndoe', 'secret')),
('https://.+\.yourcompany\.com/.+', HTTPDigestAuth(...)),
]
.. versionadded:: 2.3
Options for the XML builder
---------------------------

View File

@ -439,7 +439,7 @@ There are also config values that you can set:
* ``'signature'`` -- Show typehints as its signature (default)
* ``'none'`` -- Do not show typehints
.. versionadded: 2.1
.. versionadded:: 2.1
.. confval:: autodoc_warningiserror

View File

@ -143,6 +143,11 @@ also use these config values:
The new files will be placed in the directories specified in the
``:toctree:`` options of the directives.
.. versionchanged:: 2.3
Emits :event:`autodoc-skip-member` event as :mod:`~sphinx.ext.autodoc`
does.
.. confval:: autosummary_generate_overwrite
If true, autosummary already overwrites stub files by generated contents.

View File

@ -56,7 +56,7 @@ source code files.
.. _Google:
https://google.github.io/styleguide/pyguide.html#Comments
.. _NumPy:
https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard
.. _Khan Academy:
https://github.com/Khan/style-guides/blob/master/style/python.md#docstrings

View File

@ -427,8 +427,12 @@ def default_latex_engine(config: Config) -> str:
def default_latex_docclass(config: Config) -> Dict[str, str]:
""" Better default latex_docclass settings for specific languages. """
if config.language == 'ja':
return {'manual': 'jsbook',
'howto': 'jreport'}
if config.latex_engine == 'uplatex':
return {'manual': 'ujbook',
'howto': 'ujreport'}
else:
return {'manual': 'jsbook',
'howto': 'jreport'}
else:
return {}
@ -440,10 +444,12 @@ def default_latex_use_xindy(config: Config) -> bool:
def default_latex_documents(config: Config) -> List[Tuple[str, str, str, str, str]]:
""" Better default latex_documents settings. """
project = texescape.escape(config.project, config.latex_engine)
author = texescape.escape(config.author, config.latex_engine)
return [(config.master_doc,
make_filename_from_project(config.project) + '.tex',
texescape.escape_abbr(texescape.escape(config.project)),
texescape.escape_abbr(texescape.escape(config.author)),
texescape.escape_abbr(project),
texescape.escape_abbr(author),
'manual')]
@ -454,7 +460,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.connect('config-inited', validate_config_values)
app.add_config_value('latex_engine', default_latex_engine, None,
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex'))
ENUM('pdflatex', 'xelatex', 'lualatex', 'platex', 'uplatex'))
app.add_config_value('latex_documents', default_latex_documents, None)
app.add_config_value('latex_logo', None, None, [str])
app.add_config_value('latex_appendices', [], None)

View File

@ -59,6 +59,9 @@ def check_anchor(response: requests.requests.Response, anchor: str) -> bool:
# Read file in chunks. If we find a matching anchor, we break
# the loop early in hopes not to have to download the whole thing.
for chunk in response.iter_content(chunk_size=4096, decode_unicode=True):
if isinstance(chunk, bytes): # requests failed to decode
chunk = chunk.decode() # manually try to decode it
parser.feed(chunk)
if parser.found:
break
@ -78,6 +81,8 @@ class CheckExternalLinksBuilder(Builder):
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]]
@ -124,11 +129,18 @@ class CheckExternalLinksBuilder(Builder):
except UnicodeError:
req_url = encode_uri(req_url)
# Get auth info, if any
for pattern, auth_info in self.auth:
if pattern.match(uri):
break
else:
auth_info = None
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,
**kwargs)
auth=auth_info, **kwargs)
found = check_anchor(response, unquote(anchor))
if not found:
@ -137,13 +149,14 @@ 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, **kwargs)
response = requests.head(req_url, config=self.app.config,
auth=auth_info, **kwargs)
response.raise_for_status()
except HTTPError:
# 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,
**kwargs)
auth=auth_info, **kwargs)
response.raise_for_status()
except HTTPError as err:
if err.response.status_code == 401:
@ -302,6 +315,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_builder(CheckExternalLinksBuilder)
app.add_config_value('linkcheck_ignore', [], None)
app.add_config_value('linkcheck_auth', [], 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)

View File

@ -158,16 +158,16 @@ class Config:
def __init__(self, config={}, overrides={}):
# type: (Dict[str, Any], Dict[str, Any]) -> None
self.overrides = overrides
self.overrides = dict(overrides)
self.values = Config.config_values.copy()
self._raw_config = config
self.setup = config.get('setup', None) # type: Callable
if 'extensions' in overrides:
if isinstance(overrides['extensions'], str):
config['extensions'] = overrides.pop('extensions').split(',')
if 'extensions' in self.overrides:
if isinstance(self.overrides['extensions'], str):
config['extensions'] = self.overrides.pop('extensions').split(',')
else:
config['extensions'] = overrides.pop('extensions')
config['extensions'] = self.overrides.pop('extensions')
self.extensions = config.get('extensions', []) # type: List[str]
@classmethod

View File

@ -138,9 +138,20 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
if not template.exists(template_name):
template_name = 'autosummary/base.rst'
def skip_member(obj: Any, name: str, objtype: str) -> bool:
try:
return app.emit_firstresult('autodoc-skip-member', objtype, name,
obj, False, {})
except Exception as exc:
logger.warning(__('autosummary: failed to determine %r to be documented.'
'the following exception was raised:\n%s'),
name, exc, type='autosummary')
return False
def get_members(obj: Any, types: Set[str], include_public: List[str] = [],
imported: bool = True) -> Tuple[List[str], List[str]]:
items = [] # type: List[str]
public = [] # type: List[str]
for name in dir(obj):
try:
value = safe_getattr(obj, name)
@ -148,11 +159,20 @@ def generate_autosummary_content(name: str, obj: Any, parent: Any,
continue
documenter = get_documenter(app, value, obj)
if documenter.objtype in types:
# skip imported members if expected
if imported or getattr(value, '__module__', None) == obj.__name__:
# skip imported members if expected
items.append(name)
public = [x for x in items
if x in include_public or not x.startswith('_')]
skipped = skip_member(value, name, documenter.objtype)
if skipped is True:
pass
elif skipped is False:
# show the member forcedly
items.append(name)
public.append(name)
else:
items.append(name)
if name in include_public or not name.startswith('_'):
# considers member as public
public.append(name)
return public, items
ns = {} # type: Dict[str, Any]

View File

@ -27,10 +27,9 @@ from sphinx.domains import Domain
from sphinx.environment import BuildEnvironment
from sphinx.errors import NoUri
from sphinx.locale import _, __
from sphinx.util import logging
from sphinx.util import logging, texescape
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import make_refnode
from sphinx.util.texescape import get_escape_func
from sphinx.writers.html import HTMLTranslator
from sphinx.writers.latex import LaTeXTranslator
@ -299,11 +298,12 @@ def depart_todo_node(self: HTMLTranslator, node: todo_node) -> None:
def latex_visit_todo_node(self: LaTeXTranslator, node: todo_node) -> None:
if self.config.todo_include_todos:
escape = get_escape_func(self.config.latex_engine)
self.body.append('\n\\begin{sphinxadmonition}{note}{')
self.body.append(self.hypertarget_to(node))
title_node = cast(nodes.title, node[0])
self.body.append('%s:}' % escape(title_node.astext()))
title = texescape.escape(title_node.astext(), self.config.latex_engine)
self.body.append('%s:}' % title)
node.pop(0)
else:
raise nodes.SkipNode

View File

@ -23,8 +23,7 @@ from pygments.util import ClassNotFound
from sphinx.locale import __
from sphinx.pygments_styles import SphinxStyle, NoneStyle
from sphinx.util import logging
from sphinx.util.texescape import get_hlescape_func
from sphinx.util import logging, texescape
if False:
# For type annotation
@ -165,8 +164,7 @@ class PygmentsBridge:
if self.dest == 'html':
return hlsource
else:
escape = get_hlescape_func(self.latex_engine)
return escape(hlsource)
return texescape.hlescape(hlsource, self.latex_engine)
def get_stylesheet(self):
# type: () -> str

View File

@ -13,6 +13,7 @@ import os
from sphinx.locale import __
from sphinx.util import get_matching_files
from sphinx.util import logging
from sphinx.util import path_stabilize
from sphinx.util.matching import compile_matchers
from sphinx.util.osutil import SEP, relpath
@ -71,6 +72,7 @@ class Project:
filename = relpath(filename, self.srcdir)
for suffix in self.source_suffix:
if filename.endswith(suffix):
filename = path_stabilize(filename)
return filename[:-len(suffix)]
# the file does not have docname

View File

@ -36,7 +36,7 @@ XINDYOPTS += -M LatinRules.xdy
# format: pdf or dvi (used only by archive targets)
FMT = pdf
{% if latex_engine == 'platex' -%}
{% if latex_engine in ('platex', 'uplatex') -%}
# latexmkrc is read then overridden by latexmkjarc
LATEX = latexmk -r latexmkjarc -dvi
PDFLATEX = latexmk -r latexmkjarc -pdfdvi -dvi- -ps-

View File

@ -1,4 +1,4 @@
$latex = 'platex ' . $ENV{'LATEXOPTS'} . ' -kanji=utf8 %O %S';
$latex = '{{ latex_engine }} ' . $ENV{'LATEXOPTS'} . ' -kanji=utf8 %O %S';
$dvipdf = 'dvipdfmx %O -o %D %S';
$makeindex = 'internal mendex %S %B %D';
sub mendex {

View File

@ -6,5 +6,8 @@
<Url type="text/html" method="get"
template="{{ use_opensearch }}/{{ pathto('search') }}?q={searchTerms}"/>
<LongName>{{ docstitle|e }}</LongName>
{%- if favicon %}
<Image height="16" width="16" type="image/x-icon">{{ use_opensearch }}/{{ pathto('_static/' + favicon, 1) }}</Image>
{%- endif %}
{% block extra %} {# Put e.g. an <Image> element here. #} {% endblock %}
</OpenSearchDescription>

View File

@ -424,7 +424,7 @@ var Search = {
for (j = 0; j < _files.length; j++) {
file = _files[j];
if (!(file in scoreMap))
scoreMap[file] = {}
scoreMap[file] = {};
scoreMap[file][word] = o.score;
}
});
@ -432,7 +432,7 @@ var Search = {
// create the mapping
for (j = 0; j < files.length; j++) {
file = files[j];
if (file in fileMap)
if (file in fileMap && fileMap[file].indexOf(word) === -1)
fileMap[file].push(word);
else
fileMap[file] = [word];

View File

@ -155,7 +155,7 @@ def educateQuotes(text: str, language: str = 'en') -> str:
# Special case for decade abbreviations (the '80s):
if language.startswith('en'): # TODO similar cases in other languages?
text = re.sub(r"""'(?=\d{2}s)""", apostrophe, text, re.UNICODE)
text = re.sub(r"""'(?=\d{2}s)""", apostrophe, text, flags=re.UNICODE)
close_class = r"""[^\ \t\r\n\[\{\(\-]"""
dec_dashes = r"""&#8211;|&#8212;"""

View File

@ -9,6 +9,7 @@
"""
import os
from functools import partial
from typing import Dict, List, Union
from jinja2.loaders import BaseLoader
@ -69,8 +70,9 @@ class LaTeXRenderer(SphinxRenderer):
super().__init__(template_path)
# use texescape as escape filter
self.env.filters['e'] = texescape.get_escape_func(latex_engine)
self.env.filters['escape'] = texescape.get_escape_func(latex_engine)
escape = partial(texescape.escape, latex_engine=latex_engine)
self.env.filters['e'] = escape
self.env.filters['escape'] = escape
self.env.filters['eabbr'] = texescape.escape_abbr
# use JSP/eRuby like tagging instead because curly bracket; the default

View File

@ -9,7 +9,10 @@
"""
import re
from typing import Callable, Dict
from typing import Dict
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
tex_replacements = [
# map TeX special chars
@ -32,8 +35,6 @@ tex_replacements = [
('`', r'{}`'),
('<', r'\textless{}'),
('>', r'\textgreater{}'),
# map char for some unknown reason. TODO: remove this?
('|', r'\textbar{}'),
# map special Unicode characters to TeX commands
('', r'\(\checkmark\)'),
('', r'\(\pmb{\checkmark}\)'),
@ -84,47 +85,38 @@ unicode_tex_replacements = [
('', r'\(\sb{\text{9}}\)'),
]
tex_escape_map = {} # type: Dict[int, str]
tex_escape_map_without_unicode = {} # type: Dict[int, str]
tex_replace_map = {}
tex_hl_escape_map_new = {} # type: Dict[int, str]
tex_hl_escape_map_new_without_unicode = {} # type: Dict[int, str]
tex_replace_map = {} # type: Dict[int, str]
_tex_escape_map = {} # type: Dict[int, str]
_tex_escape_map_without_unicode = {} # type: Dict[int, str]
_tex_hlescape_map = {} # type: Dict[int, str]
_tex_hlescape_map_without_unicode = {} # type: Dict[int, str]
def get_escape_func(latex_engine: str) -> Callable[[str], str]:
"""Get escape() function for given latex_engine."""
if latex_engine in ('lualatex', 'xelatex'):
return escape_for_unicode_latex_engine
else:
return escape
deprecated_alias('sphinx.util.texescape',
{
'tex_escape_map': _tex_escape_map,
'tex_hl_escape_map_new': _tex_hlescape_map,
},
RemovedInSphinx40Warning)
def escape(s: str) -> str:
def escape(s: str, latex_engine: str = None) -> str:
"""Escape text for LaTeX output."""
return s.translate(tex_escape_map)
def escape_for_unicode_latex_engine(s: str) -> str:
"""Escape text for unicode supporting LaTeX engine."""
return s.translate(tex_escape_map_without_unicode)
def get_hlescape_func(latex_engine: str) -> Callable[[str], str]:
"""Get hlescape() function for given latex_engine."""
if latex_engine in ('lualatex', 'xelatex'):
return hlescape_for_unicode_latex_engine
# unicode based LaTeX engine
return s.translate(_tex_escape_map_without_unicode)
else:
return hlescape
return s.translate(_tex_escape_map)
def hlescape(s: str) -> str:
def hlescape(s: str, latex_engine: str = None) -> str:
"""Escape text for LaTeX highlighter."""
return s.translate(tex_hl_escape_map_new)
def hlescape_for_unicode_latex_engine(s: str) -> str:
"""Escape text for unicode supporting LaTeX engine."""
return s.translate(tex_hl_escape_map_new_without_unicode)
if latex_engine in ('lualatex', 'xelatex'):
# unicode based LaTeX engine
return s.translate(_tex_hlescape_map_without_unicode)
else:
return s.translate(_tex_hlescape_map)
def escape_abbr(text: str) -> str:
@ -134,19 +126,19 @@ def escape_abbr(text: str) -> str:
def init() -> None:
for a, b in tex_replacements:
tex_escape_map[ord(a)] = b
tex_escape_map_without_unicode[ord(a)] = b
_tex_escape_map[ord(a)] = b
_tex_escape_map_without_unicode[ord(a)] = b
tex_replace_map[ord(a)] = '_'
for a, b in unicode_tex_replacements:
tex_escape_map[ord(a)] = b
_tex_escape_map[ord(a)] = b
tex_replace_map[ord(a)] = '_'
for a, b in tex_replacements:
if a in '[]{}\\':
continue
tex_hl_escape_map_new[ord(a)] = b
tex_hl_escape_map_new_without_unicode[ord(a)] = b
_tex_hlescape_map[ord(a)] = b
_tex_hlescape_map_without_unicode[ord(a)] = b
for a, b in unicode_tex_replacements:
tex_hl_escape_map_new[ord(a)] = b
_tex_hlescape_map[ord(a)] = b

View File

@ -12,9 +12,11 @@ import copy
import os
import posixpath
import warnings
from typing import Iterable, cast
from typing import cast
from typing import Iterable
from docutils import nodes
from docutils.nodes import Element, Node, Text
from docutils.writers.html4css1 import Writer, HTMLTranslator as BaseTranslator
from sphinx import addnodes
@ -27,8 +29,7 @@ from sphinx.util.images import get_image_size
if False:
# For type annotation
from typing import Any # NOQA
from sphinx.builders.html import StandaloneHTMLBuilder # NOQA
from sphinx.builders.html import StandaloneHTMLBuilder
logger = logging.getLogger(__name__)
@ -45,13 +46,11 @@ class HTMLWriter(Writer):
if '--embed-stylesheet' in _setting[1]:
_setting[2]['default'] = 0
def __init__(self, builder):
# type: (StandaloneHTMLBuilder) -> None
def __init__(self, builder: "StandaloneHTMLBuilder") -> None:
super().__init__()
self.builder = builder
def translate(self):
# type: () -> None
def translate(self) -> None:
# sadly, this is mostly copied from parent class
visitor = self.builder.create_translator(self.document, self.builder)
self.visitor = cast(HTMLTranslator, visitor)
@ -73,8 +72,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
builder = None # type: StandaloneHTMLBuilder
def __init__(self, *args):
# type: (Any) -> None
def __init__(self, *args) -> None:
if isinstance(args[0], nodes.document) and isinstance(args[1], Builder):
document, builder = args
else:
@ -100,26 +98,21 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self._fieldlist_row_index = 0
self.required_params_left = 0
def visit_start_of_file(self, node):
# type: (nodes.Element) -> None
def visit_start_of_file(self, node: Element) -> None:
# only occurs in the single-file builder
self.docnames.append(node['docname'])
self.body.append('<span id="document-%s"></span>' % node['docname'])
def depart_start_of_file(self, node):
# type: (nodes.Element) -> None
def depart_start_of_file(self, node: Element) -> None:
self.docnames.pop()
def visit_desc(self, node):
# type: (nodes.Element) -> None
def visit_desc(self, node: Element) -> None:
self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
def depart_desc(self, node):
# type: (nodes.Element) -> None
def depart_desc(self, node: Element) -> None:
self.body.append('</dl>\n\n')
def visit_desc_signature(self, node):
# type: (nodes.Element) -> None
def visit_desc_signature(self, node: Element) -> None:
# the id is set automatically
self.body.append(self.starttag(node, 'dt'))
# anchor for per-desc interactive data
@ -127,57 +120,45 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
and node['ids'] and node['first']:
self.body.append('<!--[%s]-->' % node['ids'][0])
def depart_desc_signature(self, node):
# type: (nodes.Element) -> None
def depart_desc_signature(self, node: Element) -> None:
if not node.get('is_multiline'):
self.add_permalink_ref(node, _('Permalink to this definition'))
self.body.append('</dt>\n')
def visit_desc_signature_line(self, node):
# type: (nodes.Element) -> None
def visit_desc_signature_line(self, node: Element) -> None:
pass
def depart_desc_signature_line(self, node):
# type: (nodes.Element) -> None
def depart_desc_signature_line(self, node: Element) -> None:
if node.get('add_permalink'):
# the permalink info is on the parent desc_signature node
self.add_permalink_ref(node.parent, _('Permalink to this definition'))
self.body.append('<br />')
def visit_desc_addname(self, node):
# type: (nodes.Element) -> None
def visit_desc_addname(self, node: Element) -> None:
self.body.append(self.starttag(node, 'code', '', CLASS='descclassname'))
def depart_desc_addname(self, node):
# type: (nodes.Element) -> None
def depart_desc_addname(self, node: Element) -> None:
self.body.append('</code>')
def visit_desc_type(self, node):
# type: (nodes.Element) -> None
def visit_desc_type(self, node: Element) -> None:
pass
def depart_desc_type(self, node):
# type: (nodes.Element) -> None
def depart_desc_type(self, node: Element) -> None:
pass
def visit_desc_returns(self, node):
# type: (nodes.Element) -> None
def visit_desc_returns(self, node: Element) -> None:
self.body.append(' &#x2192; ')
def depart_desc_returns(self, node):
# type: (nodes.Element) -> None
def depart_desc_returns(self, node: Element) -> None:
pass
def visit_desc_name(self, node):
# type: (nodes.Element) -> None
def visit_desc_name(self, node: Element) -> None:
self.body.append(self.starttag(node, 'code', '', CLASS='descname'))
def depart_desc_name(self, node):
# type: (nodes.Element) -> None
def depart_desc_name(self, node: Element) -> None:
self.body.append('</code>')
def visit_desc_parameterlist(self, node):
# type: (nodes.Element) -> None
def visit_desc_parameterlist(self, node: Element) -> None:
self.body.append('<span class="sig-paren">(</span>')
self.first_param = 1
self.optional_param_level = 0
@ -186,8 +167,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
for c in node.children])
self.param_separator = node.child_text_separator
def depart_desc_parameterlist(self, node):
# type: (nodes.Element) -> None
def depart_desc_parameterlist(self, node: Element) -> None:
self.body.append('<span class="sig-paren">)</span>')
# If required parameters are still to come, then put the comma after
@ -196,8 +176,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
#
# foo([a, ]b, c[, d])
#
def visit_desc_parameter(self, node):
# type: (nodes.Element) -> None
def visit_desc_parameter(self, node: Element) -> None:
if self.first_param:
self.first_param = 0
elif not self.required_params_left:
@ -207,50 +186,40 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
if not node.hasattr('noemph'):
self.body.append('<em>')
def depart_desc_parameter(self, node):
# type: (nodes.Element) -> None
def depart_desc_parameter(self, node: Element) -> None:
if not node.hasattr('noemph'):
self.body.append('</em>')
if self.required_params_left:
self.body.append(self.param_separator)
def visit_desc_optional(self, node):
# type: (nodes.Element) -> None
def visit_desc_optional(self, node: Element) -> None:
self.optional_param_level += 1
self.body.append('<span class="optional">[</span>')
def depart_desc_optional(self, node):
# type: (nodes.Element) -> None
def depart_desc_optional(self, node: Element) -> None:
self.optional_param_level -= 1
self.body.append('<span class="optional">]</span>')
def visit_desc_annotation(self, node):
# type: (nodes.Element) -> None
def visit_desc_annotation(self, node: Element) -> None:
self.body.append(self.starttag(node, 'em', '', CLASS='property'))
def depart_desc_annotation(self, node):
# type: (nodes.Element) -> None
def depart_desc_annotation(self, node: Element) -> None:
self.body.append('</em>')
def visit_desc_content(self, node):
# type: (nodes.Element) -> None
def visit_desc_content(self, node: Element) -> None:
self.body.append(self.starttag(node, 'dd', ''))
def depart_desc_content(self, node):
# type: (nodes.Element) -> None
def depart_desc_content(self, node: Element) -> None:
self.body.append('</dd>')
def visit_versionmodified(self, node):
# type: (nodes.Element) -> None
def visit_versionmodified(self, node: Element) -> None:
self.body.append(self.starttag(node, 'div', CLASS=node['type']))
def depart_versionmodified(self, node):
# type: (nodes.Element) -> None
def depart_versionmodified(self, node: Element) -> None:
self.body.append('</div>\n')
# overwritten
def visit_reference(self, node):
# type: (nodes.Element) -> None
def visit_reference(self, node: Element) -> None:
atts = {'class': 'reference'}
if node.get('internal') or 'refuri' not in node:
atts['class'] += ' internal'
@ -278,38 +247,31 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.body.append(('%s' + self.secnumber_suffix) %
'.'.join(map(str, node['secnumber'])))
def visit_number_reference(self, node):
# type: (nodes.Element) -> None
def visit_number_reference(self, node: Element) -> None:
self.visit_reference(node)
def depart_number_reference(self, node):
# type: (nodes.Element) -> None
def depart_number_reference(self, node: Element) -> None:
self.depart_reference(node)
# overwritten -- we don't want source comments to show up in the HTML
def visit_comment(self, node): # type: ignore
# type: (nodes.Element) -> None
def visit_comment(self, node: Element) -> None: # type: ignore
raise nodes.SkipNode
# overwritten
def visit_admonition(self, node, name=''):
# type: (nodes.Element, str) -> None
def visit_admonition(self, node: Element, name: str = '') -> None:
self.body.append(self.starttag(
node, 'div', CLASS=('admonition ' + name)))
if name:
node.insert(0, nodes.title(name, admonitionlabels[name]))
self.set_first_last(node)
def visit_seealso(self, node):
# type: (nodes.Element) -> None
def visit_seealso(self, node: Element) -> None:
self.visit_admonition(node, 'seealso')
def depart_seealso(self, node):
# type: (nodes.Element) -> None
def depart_seealso(self, node: Element) -> None:
self.depart_admonition(node)
def add_secnumber(self, node):
# type: (nodes.Element) -> None
def add_secnumber(self, node: Element) -> None:
if node.get('secnumber'):
self.body.append('.'.join(map(str, node['secnumber'])) +
self.secnumber_suffix)
@ -328,10 +290,8 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.body.append('.'.join(map(str, numbers)) +
self.secnumber_suffix)
def add_fignumber(self, node):
# type: (nodes.Element) -> None
def append_fignumber(figtype, figure_id):
# type: (str, str) -> None
def add_fignumber(self, node: Element) -> None:
def append_fignumber(figtype: str, figure_id: str) -> None:
if self.builder.name == 'singlehtml':
key = "%s/%s" % (self.docnames[-1], figtype)
else:
@ -356,14 +316,12 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
else:
append_fignumber(figtype, node['ids'][0])
def add_permalink_ref(self, node, title):
# type: (nodes.Element, str) -> None
def add_permalink_ref(self, node: Element, title: str) -> None:
if node['ids'] and self.permalink_text and self.builder.add_permalinks:
format = '<a class="headerlink" href="#%s" title="%s">%s</a>'
self.body.append(format % (node['ids'][0], title, self.permalink_text))
def generate_targets_for_listing(self, node):
# type: (nodes.Element) -> None
def generate_targets_for_listing(self, node: Element) -> None:
"""Generate hyperlink targets for listings.
Original visit_bullet_list(), visit_definition_list() and visit_enumerated_list()
@ -378,8 +336,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
node['ids'].remove(id)
# overwritten
def visit_bullet_list(self, node):
# type: (nodes.Element) -> None
def visit_bullet_list(self, node: Element) -> None:
if len(node) == 1 and isinstance(node[0], addnodes.toctree):
# avoid emitting empty <ul></ul>
raise nodes.SkipNode
@ -387,46 +344,39 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
super().visit_bullet_list(node)
# overwritten
def visit_enumerated_list(self, node):
# type: (nodes.Element) -> None
def visit_enumerated_list(self, node: Element) -> None:
self.generate_targets_for_listing(node)
super().visit_enumerated_list(node)
# overwritten
def visit_definition(self, node):
# type: (nodes.Element) -> None
def visit_definition(self, node: Element) -> None:
# don't insert </dt> here.
self.body.append(self.starttag(node, 'dd', ''))
# overwritten
def depart_definition(self, node):
# type: (nodes.Element) -> None
def depart_definition(self, node: Element) -> None:
self.body.append('</dd>\n')
# overwritten
def visit_classifier(self, node):
# type: (nodes.Element) -> None
def visit_classifier(self, node: Element) -> None:
self.body.append(self.starttag(node, 'span', '', CLASS='classifier'))
# overwritten
def depart_classifier(self, node):
# type: (nodes.Element) -> None
def depart_classifier(self, node: Element) -> None:
self.body.append('</span>')
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
next_node = node.next_node(descend=False, siblings=True) # type: Node
if not isinstance(next_node, nodes.classifier):
# close `<dt>` tag at the tail of classifiers
self.body.append('</dt>')
# overwritten
def visit_term(self, node):
# type: (nodes.Element) -> None
def visit_term(self, node: Element) -> None:
self.body.append(self.starttag(node, 'dt', ''))
# overwritten
def depart_term(self, node):
# type: (nodes.Element) -> None
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
def depart_term(self, node: Element) -> None:
next_node = node.next_node(descend=False, siblings=True) # type: Node
if isinstance(next_node, nodes.classifier):
# Leave the end tag to `self.depart_classifier()`, in case
# there's a classifier.
@ -435,16 +385,14 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.body.append('</dt>')
# overwritten
def visit_title(self, node):
# type: (nodes.Element) -> None
def visit_title(self, node: Element) -> None:
super().visit_title(node)
self.add_secnumber(node)
self.add_fignumber(node.parent)
if isinstance(node.parent, nodes.table):
self.body.append('<span class="caption-text">')
def depart_title(self, node):
# type: (nodes.Element) -> None
def depart_title(self, node: Element) -> None:
close_tag = self.context[-1]
if (self.permalink_text and self.builder.add_permalinks and
node.parent.hasattr('ids') and node.parent['ids']):
@ -466,8 +414,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
super().depart_title(node)
# overwritten
def visit_literal_block(self, node):
# type: (nodes.Element) -> None
def visit_literal_block(self, node: Element) -> None:
if node.rawsource != node.astext():
# most probably a parsed-literal block -- don't highlight
return super().visit_literal_block(node)
@ -491,8 +438,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.body.append(starttag + highlighted + '</div>\n')
raise nodes.SkipNode
def visit_caption(self, node):
# type: (nodes.Element) -> None
def visit_caption(self, node: Element) -> None:
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
self.body.append('<div class="code-block-caption">')
else:
@ -500,8 +446,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.add_fignumber(node.parent)
self.body.append(self.starttag(node, 'span', '', CLASS='caption-text'))
def depart_caption(self, node):
# type: (nodes.Element) -> None
def depart_caption(self, node: Element) -> None:
self.body.append('</span>')
# append permalink if available
@ -517,22 +462,18 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
else:
super().depart_caption(node)
def visit_doctest_block(self, node):
# type: (nodes.Element) -> None
def visit_doctest_block(self, node: Element) -> None:
self.visit_literal_block(node)
# overwritten to add the <div> (for XHTML compliance)
def visit_block_quote(self, node):
# type: (nodes.Element) -> None
def visit_block_quote(self, node: Element) -> None:
self.body.append(self.starttag(node, 'blockquote') + '<div>')
def depart_block_quote(self, node):
# type: (nodes.Element) -> None
def depart_block_quote(self, node: Element) -> None:
self.body.append('</div></blockquote>\n')
# overwritten
def visit_literal(self, node):
# type: (nodes.Element) -> None
def visit_literal(self, node: Element) -> None:
if 'kbd' in node['classes']:
self.body.append(self.starttag(node, 'kbd', '',
CLASS='docutils literal notranslate'))
@ -541,16 +482,14 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
CLASS='docutils literal notranslate'))
self.protect_literal_text += 1
def depart_literal(self, node):
# type: (nodes.Element) -> None
def depart_literal(self, node: Element) -> None:
if 'kbd' in node['classes']:
self.body.append('</kbd>')
else:
self.protect_literal_text -= 1
self.body.append('</code>')
def visit_productionlist(self, node):
# type: (nodes.Element) -> None
def visit_productionlist(self, node: Element) -> None:
self.body.append(self.starttag(node, 'pre'))
names = []
productionlist = cast(Iterable[addnodes.production], node)
@ -570,30 +509,24 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.body.append('</pre>\n')
raise nodes.SkipNode
def depart_productionlist(self, node):
# type: (nodes.Element) -> None
def depart_productionlist(self, node: Element) -> None:
pass
def visit_production(self, node):
# type: (nodes.Element) -> None
def visit_production(self, node: Element) -> None:
pass
def depart_production(self, node):
# type: (nodes.Element) -> None
def depart_production(self, node: Element) -> None:
pass
def visit_centered(self, node):
# type: (nodes.Element) -> None
def visit_centered(self, node: Element) -> None:
self.body.append(self.starttag(node, 'p', CLASS="centered") +
'<strong>')
def depart_centered(self, node):
# type: (nodes.Element) -> None
def depart_centered(self, node: Element) -> None:
self.body.append('</strong></p>')
# overwritten
def should_be_compact_paragraph(self, node):
# type: (nodes.Node) -> bool
def should_be_compact_paragraph(self, node: Node) -> bool:
"""Determine if the <p> tags around paragraph can be omitted."""
if isinstance(node.parent, addnodes.desc_content):
# Never compact desc_content items.
@ -603,16 +536,13 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
return False
return super().should_be_compact_paragraph(node)
def visit_compact_paragraph(self, node):
# type: (nodes.Element) -> None
def visit_compact_paragraph(self, node: Element) -> None:
pass
def depart_compact_paragraph(self, node):
# type: (nodes.Element) -> None
def depart_compact_paragraph(self, node: Element) -> None:
pass
def visit_download_reference(self, node):
# type: (nodes.Element) -> None
def visit_download_reference(self, node: Element) -> None:
atts = {'class': 'reference download',
'download': ''}
@ -631,13 +561,11 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
else:
self.context.append('')
def depart_download_reference(self, node):
# type: (nodes.Element) -> None
def depart_download_reference(self, node: Element) -> None:
self.body.append(self.context.pop())
# overwritten
def visit_image(self, node):
# type: (nodes.Element) -> None
def visit_image(self, node: Element) -> None:
olduri = node['uri']
# rewrite the URI if the environment knows about it
if olduri in self.builder.images:
@ -678,67 +606,53 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
super().visit_image(node)
# overwritten
def depart_image(self, node):
# type: (nodes.Element) -> None
def depart_image(self, node: Element) -> None:
if node['uri'].lower().endswith(('svg', 'svgz')):
self.body.append(self.context.pop())
else:
super().depart_image(node)
def visit_toctree(self, node):
# type: (nodes.Element) -> None
def visit_toctree(self, node: Element) -> None:
# this only happens when formatting a toc from env.tocs -- in this
# case we don't want to include the subtree
raise nodes.SkipNode
def visit_index(self, node):
# type: (nodes.Element) -> None
def visit_index(self, node: Element) -> None:
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
# type: (nodes.Element) -> None
def visit_tabular_col_spec(self, node: Element) -> None:
raise nodes.SkipNode
def visit_glossary(self, node):
# type: (nodes.Element) -> None
def visit_glossary(self, node: Element) -> None:
pass
def depart_glossary(self, node):
# type: (nodes.Element) -> None
def depart_glossary(self, node: Element) -> None:
pass
def visit_acks(self, node):
# type: (nodes.Element) -> None
def visit_acks(self, node: Element) -> None:
pass
def depart_acks(self, node):
# type: (nodes.Element) -> None
def depart_acks(self, node: Element) -> None:
pass
def visit_hlist(self, node):
# type: (nodes.Element) -> None
def visit_hlist(self, node: Element) -> None:
self.body.append('<table class="hlist"><tr>')
def depart_hlist(self, node):
# type: (nodes.Element) -> None
def depart_hlist(self, node: Element) -> None:
self.body.append('</tr></table>\n')
def visit_hlistcol(self, node):
# type: (nodes.Element) -> None
def visit_hlistcol(self, node: Element) -> None:
self.body.append('<td>')
def depart_hlistcol(self, node):
# type: (nodes.Element) -> None
def depart_hlistcol(self, node: Element) -> None:
self.body.append('</td>')
def visit_option_group(self, node):
# type: (nodes.Element) -> None
def visit_option_group(self, node: Element) -> None:
super().visit_option_group(node)
self.context[-2] = self.context[-2].replace('&nbsp;', '&#160;')
# overwritten
def visit_Text(self, node):
# type: (nodes.Text) -> None
def visit_Text(self, node: Text) -> None:
text = node.astext()
encoded = self.encode(text)
if self.protect_literal_text:
@ -759,127 +673,99 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
encoded = self.cloak_email(encoded)
self.body.append(encoded)
def visit_note(self, node):
# type: (nodes.Element) -> None
def visit_note(self, node: Element) -> None:
self.visit_admonition(node, 'note')
def depart_note(self, node):
# type: (nodes.Element) -> None
def depart_note(self, node: Element) -> None:
self.depart_admonition(node)
def visit_warning(self, node):
# type: (nodes.Element) -> None
def visit_warning(self, node: Element) -> None:
self.visit_admonition(node, 'warning')
def depart_warning(self, node):
# type: (nodes.Element) -> None
def depart_warning(self, node: Element) -> None:
self.depart_admonition(node)
def visit_attention(self, node):
# type: (nodes.Element) -> None
def visit_attention(self, node: Element) -> None:
self.visit_admonition(node, 'attention')
def depart_attention(self, node):
# type: (nodes.Element) -> None
def depart_attention(self, node: Element) -> None:
self.depart_admonition(node)
def visit_caution(self, node):
# type: (nodes.Element) -> None
def visit_caution(self, node: Element) -> None:
self.visit_admonition(node, 'caution')
def depart_caution(self, node):
# type: (nodes.Element) -> None
def depart_caution(self, node: Element) -> None:
self.depart_admonition(node)
def visit_danger(self, node):
# type: (nodes.Element) -> None
def visit_danger(self, node: Element) -> None:
self.visit_admonition(node, 'danger')
def depart_danger(self, node):
# type: (nodes.Element) -> None
def depart_danger(self, node: Element) -> None:
self.depart_admonition(node)
def visit_error(self, node):
# type: (nodes.Element) -> None
def visit_error(self, node: Element) -> None:
self.visit_admonition(node, 'error')
def depart_error(self, node):
# type: (nodes.Element) -> None
def depart_error(self, node: Element) -> None:
self.depart_admonition(node)
def visit_hint(self, node):
# type: (nodes.Element) -> None
def visit_hint(self, node: Element) -> None:
self.visit_admonition(node, 'hint')
def depart_hint(self, node):
# type: (nodes.Element) -> None
def depart_hint(self, node: Element) -> None:
self.depart_admonition(node)
def visit_important(self, node):
# type: (nodes.Element) -> None
def visit_important(self, node: Element) -> None:
self.visit_admonition(node, 'important')
def depart_important(self, node):
# type: (nodes.Element) -> None
def depart_important(self, node: Element) -> None:
self.depart_admonition(node)
def visit_tip(self, node):
# type: (nodes.Element) -> None
def visit_tip(self, node: Element) -> None:
self.visit_admonition(node, 'tip')
def depart_tip(self, node):
# type: (nodes.Element) -> None
def depart_tip(self, node: Element) -> None:
self.depart_admonition(node)
def visit_literal_emphasis(self, node):
# type: (nodes.Element) -> None
def visit_literal_emphasis(self, node: Element) -> None:
return self.visit_emphasis(node)
def depart_literal_emphasis(self, node):
# type: (nodes.Element) -> None
def depart_literal_emphasis(self, node: Element) -> None:
return self.depart_emphasis(node)
def visit_literal_strong(self, node):
# type: (nodes.Element) -> None
def visit_literal_strong(self, node: Element) -> None:
return self.visit_strong(node)
def depart_literal_strong(self, node):
# type: (nodes.Element) -> None
def depart_literal_strong(self, node: Element) -> None:
return self.depart_strong(node)
def visit_abbreviation(self, node):
# type: (nodes.Element) -> None
def visit_abbreviation(self, node: Element) -> None:
attrs = {}
if node.hasattr('explanation'):
attrs['title'] = node['explanation']
self.body.append(self.starttag(node, 'abbr', '', **attrs))
def depart_abbreviation(self, node):
# type: (nodes.Element) -> None
def depart_abbreviation(self, node: Element) -> None:
self.body.append('</abbr>')
def visit_manpage(self, node):
# type: (nodes.Element) -> None
def visit_manpage(self, node: Element) -> None:
self.visit_literal_emphasis(node)
if self.manpages_url:
node['refuri'] = self.manpages_url.format(**node.attributes)
self.visit_reference(node)
def depart_manpage(self, node):
# type: (nodes.Element) -> None
def depart_manpage(self, node: Element) -> None:
if self.manpages_url:
self.depart_reference(node)
self.depart_literal_emphasis(node)
# overwritten to add even/odd classes
def visit_table(self, node):
# type: (nodes.Element) -> None
def visit_table(self, node: Element) -> None:
self._table_row_index = 0
return super().visit_table(node)
def visit_row(self, node):
# type: (nodes.Element) -> None
def visit_row(self, node: Element) -> None:
self._table_row_index += 1
if self._table_row_index % 2 == 0:
node['classes'].append('row-even')
@ -888,19 +774,16 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
self.body.append(self.starttag(node, 'tr', ''))
node.column = 0 # type: ignore
def visit_entry(self, node):
# type: (nodes.Element) -> None
def visit_entry(self, node: Element) -> None:
super().visit_entry(node)
if self.body[-1] == '&nbsp;':
self.body[-1] = '&#160;'
def visit_field_list(self, node):
# type: (nodes.Element) -> None
def visit_field_list(self, node: Element) -> None:
self._fieldlist_row_index = 0
return super().visit_field_list(node)
def visit_field(self, node):
# type: (nodes.Element) -> None
def visit_field(self, node: Element) -> None:
self._fieldlist_row_index += 1
if self._fieldlist_row_index % 2 == 0:
node['classes'].append('field-even')
@ -908,39 +791,33 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
node['classes'].append('field-odd')
self.body.append(self.starttag(node, 'tr', '', CLASS='field'))
def visit_field_name(self, node):
# type: (nodes.Element) -> None
def visit_field_name(self, node: Element) -> None:
context_count = len(self.context)
super().visit_field_name(node)
if context_count != len(self.context):
self.context[-1] = self.context[-1].replace('&nbsp;', '&#160;')
def visit_math(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def visit_math(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
visit, _ = self.builder.app.registry.html_inline_math_renderers[name]
visit(self, node)
def depart_math(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def depart_math(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
_, depart = self.builder.app.registry.html_inline_math_renderers[name]
if depart:
depart(self, node)
def visit_math_block(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def visit_math_block(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
visit, _ = self.builder.app.registry.html_block_math_renderers[name]
visit(self, node)
def depart_math_block(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def depart_math_block(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
_, depart = self.builder.app.registry.html_block_math_renderers[name]
if depart:
depart(self, node)
def unknown_visit(self, node):
# type: (nodes.Node) -> None
def unknown_visit(self, node: Node) -> None:
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)

View File

@ -11,9 +11,11 @@
import os
import posixpath
import warnings
from typing import Iterable, cast
from typing import cast
from typing import Iterable
from docutils import nodes
from docutils.nodes import Element, Node, Text
from docutils.writers.html5_polyglot import HTMLTranslator as BaseTranslator
from sphinx import addnodes
@ -26,8 +28,7 @@ from sphinx.util.images import get_image_size
if False:
# For type annotation
from typing import Any # NOQA
from sphinx.builders.html import StandaloneHTMLBuilder # NOQA
from sphinx.builders.html import StandaloneHTMLBuilder
logger = logging.getLogger(__name__)
@ -43,8 +44,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
builder = None # type: StandaloneHTMLBuilder
def __init__(self, *args):
# type: (Any) -> None
def __init__(self, *args) -> None:
if isinstance(args[0], nodes.document) and isinstance(args[1], Builder):
document, builder = args
else:
@ -70,26 +70,21 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self._fieldlist_row_index = 0
self.required_params_left = 0
def visit_start_of_file(self, node):
# type: (nodes.Element) -> None
def visit_start_of_file(self, node: Element) -> None:
# only occurs in the single-file builder
self.docnames.append(node['docname'])
self.body.append('<span id="document-%s"></span>' % node['docname'])
def depart_start_of_file(self, node):
# type: (nodes.Element) -> None
def depart_start_of_file(self, node: Element) -> None:
self.docnames.pop()
def visit_desc(self, node):
# type: (nodes.Element) -> None
def visit_desc(self, node: Element) -> None:
self.body.append(self.starttag(node, 'dl', CLASS=node['objtype']))
def depart_desc(self, node):
# type: (nodes.Element) -> None
def depart_desc(self, node: Element) -> None:
self.body.append('</dl>\n\n')
def visit_desc_signature(self, node):
# type: (nodes.Element) -> None
def visit_desc_signature(self, node: Element) -> None:
# the id is set automatically
self.body.append(self.starttag(node, 'dt'))
# anchor for per-desc interactive data
@ -97,57 +92,45 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
and node['ids'] and node['first']:
self.body.append('<!--[%s]-->' % node['ids'][0])
def depart_desc_signature(self, node):
# type: (nodes.Element) -> None
def depart_desc_signature(self, node: Element) -> None:
if not node.get('is_multiline'):
self.add_permalink_ref(node, _('Permalink to this definition'))
self.body.append('</dt>\n')
def visit_desc_signature_line(self, node):
# type: (nodes.Element) -> None
def visit_desc_signature_line(self, node: Element) -> None:
pass
def depart_desc_signature_line(self, node):
# type: (nodes.Element) -> None
def depart_desc_signature_line(self, node: Element) -> None:
if node.get('add_permalink'):
# the permalink info is on the parent desc_signature node
self.add_permalink_ref(node.parent, _('Permalink to this definition'))
self.body.append('<br />')
def visit_desc_addname(self, node):
# type: (nodes.Element) -> None
def visit_desc_addname(self, node: Element) -> None:
self.body.append(self.starttag(node, 'code', '', CLASS='sig-prename descclassname'))
def depart_desc_addname(self, node):
# type: (nodes.Element) -> None
def depart_desc_addname(self, node: Element) -> None:
self.body.append('</code>')
def visit_desc_type(self, node):
# type: (nodes.Element) -> None
def visit_desc_type(self, node: Element) -> None:
pass
def depart_desc_type(self, node):
# type: (nodes.Element) -> None
def depart_desc_type(self, node: Element) -> None:
pass
def visit_desc_returns(self, node):
# type: (nodes.Element) -> None
def visit_desc_returns(self, node: Element) -> None:
self.body.append(' &#x2192; ')
def depart_desc_returns(self, node):
# type: (nodes.Element) -> None
def depart_desc_returns(self, node: Element) -> None:
pass
def visit_desc_name(self, node):
# type: (nodes.Element) -> None
def visit_desc_name(self, node: Element) -> None:
self.body.append(self.starttag(node, 'code', '', CLASS='sig-name descname'))
def depart_desc_name(self, node):
# type: (nodes.Element) -> None
def depart_desc_name(self, node: Element) -> None:
self.body.append('</code>')
def visit_desc_parameterlist(self, node):
# type: (nodes.Element) -> None
def visit_desc_parameterlist(self, node: Element) -> None:
self.body.append('<span class="sig-paren">(</span>')
self.first_param = 1
self.optional_param_level = 0
@ -156,8 +139,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
for c in node.children])
self.param_separator = node.child_text_separator
def depart_desc_parameterlist(self, node):
# type: (nodes.Element) -> None
def depart_desc_parameterlist(self, node: Element) -> None:
self.body.append('<span class="sig-paren">)</span>')
# If required parameters are still to come, then put the comma after
@ -166,8 +148,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
#
# foo([a, ]b, c[, d])
#
def visit_desc_parameter(self, node):
# type: (nodes.Element) -> None
def visit_desc_parameter(self, node: Element) -> None:
if self.first_param:
self.first_param = 0
elif not self.required_params_left:
@ -177,50 +158,40 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
if not node.hasattr('noemph'):
self.body.append('<em class="sig-param">')
def depart_desc_parameter(self, node):
# type: (nodes.Element) -> None
def depart_desc_parameter(self, node: Element) -> None:
if not node.hasattr('noemph'):
self.body.append('</em>')
if self.required_params_left:
self.body.append(self.param_separator)
def visit_desc_optional(self, node):
# type: (nodes.Element) -> None
def visit_desc_optional(self, node: Element) -> None:
self.optional_param_level += 1
self.body.append('<span class="optional">[</span>')
def depart_desc_optional(self, node):
# type: (nodes.Element) -> None
def depart_desc_optional(self, node: Element) -> None:
self.optional_param_level -= 1
self.body.append('<span class="optional">]</span>')
def visit_desc_annotation(self, node):
# type: (nodes.Element) -> None
def visit_desc_annotation(self, node: Element) -> None:
self.body.append(self.starttag(node, 'em', '', CLASS='property'))
def depart_desc_annotation(self, node):
# type: (nodes.Element) -> None
def depart_desc_annotation(self, node: Element) -> None:
self.body.append('</em>')
def visit_desc_content(self, node):
# type: (nodes.Element) -> None
def visit_desc_content(self, node: Element) -> None:
self.body.append(self.starttag(node, 'dd', ''))
def depart_desc_content(self, node):
# type: (nodes.Element) -> None
def depart_desc_content(self, node: Element) -> None:
self.body.append('</dd>')
def visit_versionmodified(self, node):
# type: (nodes.Element) -> None
def visit_versionmodified(self, node: Element) -> None:
self.body.append(self.starttag(node, 'div', CLASS=node['type']))
def depart_versionmodified(self, node):
# type: (nodes.Element) -> None
def depart_versionmodified(self, node: Element) -> None:
self.body.append('</div>\n')
# overwritten
def visit_reference(self, node):
# type: (nodes.Element) -> None
def visit_reference(self, node: Element) -> None:
atts = {'class': 'reference'}
if node.get('internal') or 'refuri' not in node:
atts['class'] += ' internal'
@ -248,37 +219,30 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append(('%s' + self.secnumber_suffix) %
'.'.join(map(str, node['secnumber'])))
def visit_number_reference(self, node):
# type: (nodes.Element) -> None
def visit_number_reference(self, node: Element) -> None:
self.visit_reference(node)
def depart_number_reference(self, node):
# type: (nodes.Element) -> None
def depart_number_reference(self, node: Element) -> None:
self.depart_reference(node)
# overwritten -- we don't want source comments to show up in the HTML
def visit_comment(self, node): # type: ignore
# type: (nodes.Element) -> None
def visit_comment(self, node: Element) -> None: # type: ignore
raise nodes.SkipNode
# overwritten
def visit_admonition(self, node, name=''):
# type: (nodes.Element, str) -> None
def visit_admonition(self, node: Element, name: str = '') -> None:
self.body.append(self.starttag(
node, 'div', CLASS=('admonition ' + name)))
if name:
node.insert(0, nodes.title(name, admonitionlabels[name]))
def visit_seealso(self, node):
# type: (nodes.Element) -> None
def visit_seealso(self, node: Element) -> None:
self.visit_admonition(node, 'seealso')
def depart_seealso(self, node):
# type: (nodes.Element) -> None
def depart_seealso(self, node: Element) -> None:
self.depart_admonition(node)
def add_secnumber(self, node):
# type: (nodes.Element) -> None
def add_secnumber(self, node: Element) -> None:
if node.get('secnumber'):
self.body.append('.'.join(map(str, node['secnumber'])) +
self.secnumber_suffix)
@ -297,10 +261,8 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append('.'.join(map(str, numbers)) +
self.secnumber_suffix)
def add_fignumber(self, node):
# type: (nodes.Element) -> None
def append_fignumber(figtype, figure_id):
# type: (str, str) -> None
def add_fignumber(self, node: Element) -> None:
def append_fignumber(figtype: str, figure_id: str) -> None:
if self.builder.name == 'singlehtml':
key = "%s/%s" % (self.docnames[-1], figtype)
else:
@ -325,55 +287,47 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
else:
append_fignumber(figtype, node['ids'][0])
def add_permalink_ref(self, node, title):
# type: (nodes.Element, str) -> None
def add_permalink_ref(self, node: Element, title: str) -> None:
if node['ids'] and self.permalink_text and self.builder.add_permalinks:
format = '<a class="headerlink" href="#%s" title="%s">%s</a>'
self.body.append(format % (node['ids'][0], title, self.permalink_text))
# overwritten
def visit_bullet_list(self, node):
# type: (nodes.Element) -> None
def visit_bullet_list(self, node: Element) -> None:
if len(node) == 1 and isinstance(node[0], addnodes.toctree):
# avoid emitting empty <ul></ul>
raise nodes.SkipNode
super().visit_bullet_list(node)
# overwritten
def visit_definition(self, node):
# type: (nodes.Element) -> None
def visit_definition(self, node: Element) -> None:
# don't insert </dt> here.
self.body.append(self.starttag(node, 'dd', ''))
# overwritten
def depart_definition(self, node):
# type: (nodes.Element) -> None
def depart_definition(self, node: Element) -> None:
self.body.append('</dd>\n')
# overwritten
def visit_classifier(self, node):
# type: (nodes.Element) -> None
def visit_classifier(self, node: Element) -> None:
self.body.append(self.starttag(node, 'span', '', CLASS='classifier'))
# overwritten
def depart_classifier(self, node):
# type: (nodes.Element) -> None
def depart_classifier(self, node: Element) -> None:
self.body.append('</span>')
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
next_node = node.next_node(descend=False, siblings=True) # type: Node
if not isinstance(next_node, nodes.classifier):
# close `<dt>` tag at the tail of classifiers
self.body.append('</dt>')
# overwritten
def visit_term(self, node):
# type: (nodes.Element) -> None
def visit_term(self, node: Element) -> None:
self.body.append(self.starttag(node, 'dt', ''))
# overwritten
def depart_term(self, node):
# type: (nodes.Element) -> None
next_node = node.next_node(descend=False, siblings=True) # type: nodes.Node
def depart_term(self, node: Element) -> None:
next_node = node.next_node(descend=False, siblings=True) # type: Node
if isinstance(next_node, nodes.classifier):
# Leave the end tag to `self.depart_classifier()`, in case
# there's a classifier.
@ -382,16 +336,14 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append('</dt>')
# overwritten
def visit_title(self, node):
# type: (nodes.Element) -> None
def visit_title(self, node: Element) -> None:
super().visit_title(node)
self.add_secnumber(node)
self.add_fignumber(node.parent)
if isinstance(node.parent, nodes.table):
self.body.append('<span class="caption-text">')
def depart_title(self, node):
# type: (nodes.Element) -> None
def depart_title(self, node: Element) -> None:
close_tag = self.context[-1]
if (self.permalink_text and self.builder.add_permalinks and
node.parent.hasattr('ids') and node.parent['ids']):
@ -413,8 +365,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
super().depart_title(node)
# overwritten
def visit_literal_block(self, node):
# type: (nodes.Element) -> None
def visit_literal_block(self, node: Element) -> None:
if node.rawsource != node.astext():
# most probably a parsed-literal block -- don't highlight
return super().visit_literal_block(node)
@ -438,8 +389,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append(starttag + highlighted + '</div>\n')
raise nodes.SkipNode
def visit_caption(self, node):
# type: (nodes.Element) -> None
def visit_caption(self, node: Element) -> None:
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
self.body.append('<div class="code-block-caption">')
else:
@ -447,8 +397,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.add_fignumber(node.parent)
self.body.append(self.starttag(node, 'span', '', CLASS='caption-text'))
def depart_caption(self, node):
# type: (nodes.Element) -> None
def depart_caption(self, node: Element) -> None:
self.body.append('</span>')
# append permalink if available
@ -464,22 +413,18 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
else:
super().depart_caption(node)
def visit_doctest_block(self, node):
# type: (nodes.Element) -> None
def visit_doctest_block(self, node: Element) -> None:
self.visit_literal_block(node)
# overwritten to add the <div> (for XHTML compliance)
def visit_block_quote(self, node):
# type: (nodes.Element) -> None
def visit_block_quote(self, node: Element) -> None:
self.body.append(self.starttag(node, 'blockquote') + '<div>')
def depart_block_quote(self, node):
# type: (nodes.Element) -> None
def depart_block_quote(self, node: Element) -> None:
self.body.append('</div></blockquote>\n')
# overwritten
def visit_literal(self, node):
# type: (nodes.Element) -> None
def visit_literal(self, node: Element) -> None:
if 'kbd' in node['classes']:
self.body.append(self.starttag(node, 'kbd', '',
CLASS='docutils literal notranslate'))
@ -488,16 +433,14 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
CLASS='docutils literal notranslate'))
self.protect_literal_text += 1
def depart_literal(self, node):
# type: (nodes.Element) -> None
def depart_literal(self, node: Element) -> None:
if 'kbd' in node['classes']:
self.body.append('</kbd>')
else:
self.protect_literal_text -= 1
self.body.append('</code>')
def visit_productionlist(self, node):
# type: (nodes.Element) -> None
def visit_productionlist(self, node: Element) -> None:
self.body.append(self.starttag(node, 'pre'))
names = []
productionlist = cast(Iterable[addnodes.production], node)
@ -517,37 +460,29 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append('</pre>\n')
raise nodes.SkipNode
def depart_productionlist(self, node):
# type: (nodes.Element) -> None
def depart_productionlist(self, node: Element) -> None:
pass
def visit_production(self, node):
# type: (nodes.Element) -> None
def visit_production(self, node: Element) -> None:
pass
def depart_production(self, node):
# type: (nodes.Element) -> None
def depart_production(self, node: Element) -> None:
pass
def visit_centered(self, node):
# type: (nodes.Element) -> None
def visit_centered(self, node: Element) -> None:
self.body.append(self.starttag(node, 'p', CLASS="centered") +
'<strong>')
def depart_centered(self, node):
# type: (nodes.Element) -> None
def depart_centered(self, node: Element) -> None:
self.body.append('</strong></p>')
def visit_compact_paragraph(self, node):
# type: (nodes.Element) -> None
def visit_compact_paragraph(self, node: Element) -> None:
pass
def depart_compact_paragraph(self, node):
# type: (nodes.Element) -> None
def depart_compact_paragraph(self, node: Element) -> None:
pass
def visit_download_reference(self, node):
# type: (nodes.Element) -> None
def visit_download_reference(self, node: Element) -> None:
atts = {'class': 'reference download',
'download': ''}
@ -566,13 +501,11 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
else:
self.context.append('')
def depart_download_reference(self, node):
# type: (nodes.Element) -> None
def depart_download_reference(self, node: Element) -> None:
self.body.append(self.context.pop())
# overwritten
def visit_image(self, node):
# type: (nodes.Element) -> None
def visit_image(self, node: Element) -> None:
olduri = node['uri']
# rewrite the URI if the environment knows about it
if olduri in self.builder.images:
@ -613,62 +546,49 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
super().visit_image(node)
# overwritten
def depart_image(self, node):
# type: (nodes.Element) -> None
def depart_image(self, node: Element) -> None:
if node['uri'].lower().endswith(('svg', 'svgz')):
self.body.append(self.context.pop())
else:
super().depart_image(node)
def visit_toctree(self, node):
# type: (nodes.Element) -> None
def visit_toctree(self, node: Element) -> None:
# this only happens when formatting a toc from env.tocs -- in this
# case we don't want to include the subtree
raise nodes.SkipNode
def visit_index(self, node):
# type: (nodes.Element) -> None
def visit_index(self, node: Element) -> None:
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
# type: (nodes.Element) -> None
def visit_tabular_col_spec(self, node: Element) -> None:
raise nodes.SkipNode
def visit_glossary(self, node):
# type: (nodes.Element) -> None
def visit_glossary(self, node: Element) -> None:
pass
def depart_glossary(self, node):
# type: (nodes.Element) -> None
def depart_glossary(self, node: Element) -> None:
pass
def visit_acks(self, node):
# type: (nodes.Element) -> None
def visit_acks(self, node: Element) -> None:
pass
def depart_acks(self, node):
# type: (nodes.Element) -> None
def depart_acks(self, node: Element) -> None:
pass
def visit_hlist(self, node):
# type: (nodes.Element) -> None
def visit_hlist(self, node: Element) -> None:
self.body.append('<table class="hlist"><tr>')
def depart_hlist(self, node):
# type: (nodes.Element) -> None
def depart_hlist(self, node: Element) -> None:
self.body.append('</tr></table>\n')
def visit_hlistcol(self, node):
# type: (nodes.Element) -> None
def visit_hlistcol(self, node: Element) -> None:
self.body.append('<td>')
def depart_hlistcol(self, node):
# type: (nodes.Element) -> None
def depart_hlistcol(self, node: Element) -> None:
self.body.append('</td>')
# overwritten
def visit_Text(self, node):
# type: (nodes.Text) -> None
def visit_Text(self, node: Text) -> None:
text = node.astext()
encoded = self.encode(text)
if self.protect_literal_text:
@ -689,122 +609,95 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
encoded = self.cloak_email(encoded)
self.body.append(encoded)
def visit_note(self, node):
# type: (nodes.Element) -> None
def visit_note(self, node: Element) -> None:
self.visit_admonition(node, 'note')
def depart_note(self, node):
# type: (nodes.Element) -> None
def depart_note(self, node: Element) -> None:
self.depart_admonition(node)
def visit_warning(self, node):
# type: (nodes.Element) -> None
def visit_warning(self, node: Element) -> None:
self.visit_admonition(node, 'warning')
def depart_warning(self, node):
# type: (nodes.Element) -> None
def depart_warning(self, node: Element) -> None:
self.depart_admonition(node)
def visit_attention(self, node):
# type: (nodes.Element) -> None
def visit_attention(self, node: Element) -> None:
self.visit_admonition(node, 'attention')
def depart_attention(self, node):
# type: (nodes.Element) -> None
def depart_attention(self, node: Element) -> None:
self.depart_admonition(node)
def visit_caution(self, node):
# type: (nodes.Element) -> None
def visit_caution(self, node: Element) -> None:
self.visit_admonition(node, 'caution')
def depart_caution(self, node):
# type: (nodes.Element) -> None
def depart_caution(self, node: Element) -> None:
self.depart_admonition(node)
def visit_danger(self, node):
# type: (nodes.Element) -> None
def visit_danger(self, node: Element) -> None:
self.visit_admonition(node, 'danger')
def depart_danger(self, node):
# type: (nodes.Element) -> None
def depart_danger(self, node: Element) -> None:
self.depart_admonition(node)
def visit_error(self, node):
# type: (nodes.Element) -> None
def visit_error(self, node: Element) -> None:
self.visit_admonition(node, 'error')
def depart_error(self, node):
# type: (nodes.Element) -> None
def depart_error(self, node: Element) -> None:
self.depart_admonition(node)
def visit_hint(self, node):
# type: (nodes.Element) -> None
def visit_hint(self, node: Element) -> None:
self.visit_admonition(node, 'hint')
def depart_hint(self, node):
# type: (nodes.Element) -> None
def depart_hint(self, node: Element) -> None:
self.depart_admonition(node)
def visit_important(self, node):
# type: (nodes.Element) -> None
def visit_important(self, node: Element) -> None:
self.visit_admonition(node, 'important')
def depart_important(self, node):
# type: (nodes.Element) -> None
def depart_important(self, node: Element) -> None:
self.depart_admonition(node)
def visit_tip(self, node):
# type: (nodes.Element) -> None
def visit_tip(self, node: Element) -> None:
self.visit_admonition(node, 'tip')
def depart_tip(self, node):
# type: (nodes.Element) -> None
def depart_tip(self, node: Element) -> None:
self.depart_admonition(node)
def visit_literal_emphasis(self, node):
# type: (nodes.Element) -> None
def visit_literal_emphasis(self, node: Element) -> None:
return self.visit_emphasis(node)
def depart_literal_emphasis(self, node):
# type: (nodes.Element) -> None
def depart_literal_emphasis(self, node: Element) -> None:
return self.depart_emphasis(node)
def visit_literal_strong(self, node):
# type: (nodes.Element) -> None
def visit_literal_strong(self, node: Element) -> None:
return self.visit_strong(node)
def depart_literal_strong(self, node):
# type: (nodes.Element) -> None
def depart_literal_strong(self, node: Element) -> None:
return self.depart_strong(node)
def visit_abbreviation(self, node):
# type: (nodes.Element) -> None
def visit_abbreviation(self, node: Element) -> None:
attrs = {}
if node.hasattr('explanation'):
attrs['title'] = node['explanation']
self.body.append(self.starttag(node, 'abbr', '', **attrs))
def depart_abbreviation(self, node):
# type: (nodes.Element) -> None
def depart_abbreviation(self, node: Element) -> None:
self.body.append('</abbr>')
def visit_manpage(self, node):
# type: (nodes.Element) -> None
def visit_manpage(self, node: Element) -> None:
self.visit_literal_emphasis(node)
if self.manpages_url:
node['refuri'] = self.manpages_url.format(**node.attributes)
self.visit_reference(node)
def depart_manpage(self, node):
# type: (nodes.Element) -> None
def depart_manpage(self, node: Element) -> None:
if self.manpages_url:
self.depart_reference(node)
self.depart_literal_emphasis(node)
# overwritten to add even/odd classes
def generate_targets_for_table(self, node):
# type: (nodes.Element) -> None
def generate_targets_for_table(self, node: Element) -> None:
"""Generate hyperlink targets for tables.
Original visit_table() generates hyperlink targets inside table tags
@ -817,8 +710,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append('<span id="%s"></span>' % id)
node['ids'].remove(id)
def visit_table(self, node):
# type: (nodes.Element) -> None
def visit_table(self, node: Element) -> None:
self.generate_targets_for_table(node)
self._table_row_index = 0
@ -830,8 +722,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
tag = self.starttag(node, 'table', CLASS=' '.join(classes))
self.body.append(tag)
def visit_row(self, node):
# type: (nodes.Element) -> None
def visit_row(self, node: Element) -> None:
self._table_row_index += 1
if self._table_row_index % 2 == 0:
node['classes'].append('row-even')
@ -840,45 +731,38 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
self.body.append(self.starttag(node, 'tr', ''))
node.column = 0 # type: ignore
def visit_field_list(self, node):
# type: (nodes.Element) -> None
def visit_field_list(self, node: Element) -> None:
self._fieldlist_row_index = 0
return super().visit_field_list(node)
def visit_field(self, node):
# type: (nodes.Element) -> None
def visit_field(self, node: Element) -> None:
self._fieldlist_row_index += 1
if self._fieldlist_row_index % 2 == 0:
node['classes'].append('field-even')
else:
node['classes'].append('field-odd')
def visit_math(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def visit_math(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
visit, _ = self.builder.app.registry.html_inline_math_renderers[name]
visit(self, node)
def depart_math(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def depart_math(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
_, depart = self.builder.app.registry.html_inline_math_renderers[name]
if depart:
depart(self, node)
def visit_math_block(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def visit_math_block(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
visit, _ = self.builder.app.registry.html_block_math_renderers[name]
visit(self, node)
def depart_math_block(self, node, math_env=''):
# type: (nodes.Element, str) -> None
def depart_math_block(self, node: Element, math_env: str = '') -> None:
name = self.builder.math_renderer_name
_, depart = self.builder.app.registry.html_block_math_renderers[name]
if depart:
depart(self, node)
def unknown_visit(self, node):
# type: (nodes.Node) -> None
def unknown_visit(self, node: Node) -> None:
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)

File diff suppressed because it is too large Load Diff

View File

@ -9,9 +9,11 @@
"""
import warnings
from typing import Iterable, cast
from typing import Any, Dict, Iterable
from typing import cast
from docutils import nodes
from docutils.nodes import Element, Node, TextElement
from docutils.writers.manpage import (
Writer,
Translator as BaseTranslator
@ -26,21 +28,16 @@ from sphinx.util.docutils import SphinxTranslator
from sphinx.util.i18n import format_date
from sphinx.util.nodes import NodeMatcher
if False:
# For type annotation
from typing import Any, Dict # NOQA
logger = logging.getLogger(__name__)
class ManualPageWriter(Writer):
def __init__(self, builder):
# type: (Builder) -> None
def __init__(self, builder: Builder) -> None:
super().__init__()
self.builder = builder
def translate(self):
# type: () -> None
def translate(self) -> None:
transform = NestedInlineTransform(self.document)
transform.apply()
visitor = self.builder.create_translator(self.document, self.builder)
@ -60,14 +57,12 @@ class NestedInlineTransform:
<strong>foo=</strong><emphasis>var</emphasis>
<strong>&bar=</strong><emphasis>2</emphasis>
"""
def __init__(self, document):
# type: (nodes.document) -> None
def __init__(self, document: nodes.document) -> None:
self.document = document
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
matcher = NodeMatcher(nodes.literal, nodes.emphasis, nodes.strong)
for node in self.document.traverse(matcher): # type: nodes.TextElement
for node in self.document.traverse(matcher): # type: TextElement
if any(matcher(subnode) for subnode in node):
pos = node.parent.index(node)
for subnode in reversed(node[1:]):
@ -86,8 +81,7 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
_docinfo = {} # type: Dict[str, Any]
def __init__(self, *args):
# type: (Any) -> None
def __init__(self, *args) -> None:
if isinstance(args[0], nodes.document) and isinstance(args[1], Builder):
document, builder = args
else:
@ -126,153 +120,120 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
self.language.labels[label] = self.deunicode(translation) # type: ignore
# overwritten -- added quotes around all .TH arguments
def header(self):
# type: () -> str
def header(self) -> str:
tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\""
" \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
".SH NAME\n"
"%(title)s \\- %(subtitle)s\n")
return tmpl % self._docinfo
def visit_start_of_file(self, node):
# type: (nodes.Element) -> None
def visit_start_of_file(self, node: Element) -> None:
pass
def depart_start_of_file(self, node):
# type: (nodes.Element) -> None
def depart_start_of_file(self, node: Element) -> None:
pass
def visit_desc(self, node):
# type: (nodes.Element) -> None
def visit_desc(self, node: Element) -> None:
self.visit_definition_list(node)
def depart_desc(self, node):
# type: (nodes.Element) -> None
def depart_desc(self, node: Element) -> None:
self.depart_definition_list(node)
def visit_desc_signature(self, node):
# type: (nodes.Element) -> None
def visit_desc_signature(self, node: Element) -> None:
self.visit_definition_list_item(node)
self.visit_term(node)
def depart_desc_signature(self, node):
# type: (nodes.Element) -> None
def depart_desc_signature(self, node: Element) -> None:
self.depart_term(node)
def visit_desc_signature_line(self, node):
# type: (nodes.Element) -> None
def visit_desc_signature_line(self, node: Element) -> None:
pass
def depart_desc_signature_line(self, node):
# type: (nodes.Element) -> None
def depart_desc_signature_line(self, node: Element) -> None:
self.body.append(' ')
def visit_desc_addname(self, node):
# type: (nodes.Element) -> None
def visit_desc_addname(self, node: Element) -> None:
pass
def depart_desc_addname(self, node):
# type: (nodes.Element) -> None
def depart_desc_addname(self, node: Element) -> None:
pass
def visit_desc_type(self, node):
# type: (nodes.Element) -> None
def visit_desc_type(self, node: Element) -> None:
pass
def depart_desc_type(self, node):
# type: (nodes.Element) -> None
def depart_desc_type(self, node: Element) -> None:
pass
def visit_desc_returns(self, node):
# type: (nodes.Element) -> None
def visit_desc_returns(self, node: Element) -> None:
self.body.append(' -> ')
def depart_desc_returns(self, node):
# type: (nodes.Element) -> None
def depart_desc_returns(self, node: Element) -> None:
pass
def visit_desc_name(self, node):
# type: (nodes.Element) -> None
def visit_desc_name(self, node: Element) -> None:
pass
def depart_desc_name(self, node):
# type: (nodes.Element) -> None
def depart_desc_name(self, node: Element) -> None:
pass
def visit_desc_parameterlist(self, node):
# type: (nodes.Element) -> None
def visit_desc_parameterlist(self, node: Element) -> None:
self.body.append('(')
self.first_param = 1
def depart_desc_parameterlist(self, node):
# type: (nodes.Element) -> None
def depart_desc_parameterlist(self, node: Element) -> None:
self.body.append(')')
def visit_desc_parameter(self, node):
# type: (nodes.Element) -> None
def visit_desc_parameter(self, node: Element) -> None:
if not self.first_param:
self.body.append(', ')
else:
self.first_param = 0
def depart_desc_parameter(self, node):
# type: (nodes.Element) -> None
def depart_desc_parameter(self, node: Element) -> None:
pass
def visit_desc_optional(self, node):
# type: (nodes.Element) -> None
def visit_desc_optional(self, node: Element) -> None:
self.body.append('[')
def depart_desc_optional(self, node):
# type: (nodes.Element) -> None
def depart_desc_optional(self, node: Element) -> None:
self.body.append(']')
def visit_desc_annotation(self, node):
# type: (nodes.Element) -> None
def visit_desc_annotation(self, node: Element) -> None:
pass
def depart_desc_annotation(self, node):
# type: (nodes.Element) -> None
def depart_desc_annotation(self, node: Element) -> None:
pass
def visit_desc_content(self, node):
# type: (nodes.Element) -> None
def visit_desc_content(self, node: Element) -> None:
self.visit_definition(node)
def depart_desc_content(self, node):
# type: (nodes.Element) -> None
def depart_desc_content(self, node: Element) -> None:
self.depart_definition(node)
def visit_versionmodified(self, node):
# type: (nodes.Element) -> None
def visit_versionmodified(self, node: Element) -> None:
self.visit_paragraph(node)
def depart_versionmodified(self, node):
# type: (nodes.Element) -> None
def depart_versionmodified(self, node: Element) -> None:
self.depart_paragraph(node)
# overwritten -- don't make whole of term bold if it includes strong node
def visit_term(self, node):
# type: (nodes.Element) -> None
def visit_term(self, node: Element) -> None:
if node.traverse(nodes.strong):
self.body.append('\n')
else:
super().visit_term(node)
# overwritten -- we don't want source comments to show up
def visit_comment(self, node): # type: ignore
# type: (nodes.Element) -> None
def visit_comment(self, node: Element) -> None: # type: ignore
raise nodes.SkipNode
# overwritten -- added ensure_eol()
def visit_footnote(self, node):
# type: (nodes.Element) -> None
def visit_footnote(self, node: Element) -> None:
self.ensure_eol()
super().visit_footnote(node)
# overwritten -- handle footnotes rubric
def visit_rubric(self, node):
# type: (nodes.Element) -> None
def visit_rubric(self, node: Element) -> None:
self.ensure_eol()
if len(node) == 1 and node.astext() in ('Footnotes', _('Footnotes')):
self.body.append('.SH ' + self.deunicode(node.astext()).upper() + '\n')
@ -280,20 +241,16 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
else:
self.body.append('.sp\n')
def depart_rubric(self, node):
# type: (nodes.Element) -> None
def depart_rubric(self, node: Element) -> None:
self.body.append('\n')
def visit_seealso(self, node):
# type: (nodes.Element) -> None
def visit_seealso(self, node: Element) -> None:
self.visit_admonition(node, 'seealso')
def depart_seealso(self, node):
# type: (nodes.Element) -> None
def depart_seealso(self, node: Element) -> None:
self.depart_admonition(node)
def visit_productionlist(self, node):
# type: (nodes.Element) -> None
def visit_productionlist(self, node: Element) -> None:
self.ensure_eol()
names = []
self.in_productionlist += 1
@ -318,25 +275,21 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
self.in_productionlist -= 1
raise nodes.SkipNode
def visit_production(self, node):
# type: (nodes.Element) -> None
def visit_production(self, node: Element) -> None:
pass
def depart_production(self, node):
# type: (nodes.Element) -> None
def depart_production(self, node: Element) -> None:
pass
# overwritten -- don't emit a warning for images
def visit_image(self, node):
# type: (nodes.Element) -> None
def visit_image(self, node: Element) -> None:
if 'alt' in node.attributes:
self.body.append(_('[image: %s]') % node['alt'] + '\n')
self.body.append(_('[image]') + '\n')
raise nodes.SkipNode
# overwritten -- don't visit inner marked up nodes
def visit_reference(self, node):
# type: (nodes.Element) -> None
def visit_reference(self, node: Element) -> None:
self.body.append(self.defs['reference'][0])
# avoid repeating escaping code... fine since
# visit_Text calls astext() and only works on that afterwards
@ -357,59 +310,46 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
'>'])
raise nodes.SkipNode
def visit_number_reference(self, node):
# type: (nodes.Element) -> None
def visit_number_reference(self, node: Element) -> None:
text = nodes.Text(node.get('title', '#'))
self.visit_Text(text)
raise nodes.SkipNode
def visit_centered(self, node):
# type: (nodes.Element) -> None
def visit_centered(self, node: Element) -> None:
self.ensure_eol()
self.body.append('.sp\n.ce\n')
def depart_centered(self, node):
# type: (nodes.Element) -> None
def depart_centered(self, node: Element) -> None:
self.body.append('\n.ce 0\n')
def visit_compact_paragraph(self, node):
# type: (nodes.Element) -> None
def visit_compact_paragraph(self, node: Element) -> None:
pass
def depart_compact_paragraph(self, node):
# type: (nodes.Element) -> None
def depart_compact_paragraph(self, node: Element) -> None:
pass
def visit_download_reference(self, node):
# type: (nodes.Element) -> None
def visit_download_reference(self, node: Element) -> None:
pass
def depart_download_reference(self, node):
# type: (nodes.Element) -> None
def depart_download_reference(self, node: Element) -> None:
pass
def visit_toctree(self, node):
# type: (nodes.Element) -> None
def visit_toctree(self, node: Element) -> None:
raise nodes.SkipNode
def visit_index(self, node):
# type: (nodes.Element) -> None
def visit_index(self, node: Element) -> None:
raise nodes.SkipNode
def visit_tabular_col_spec(self, node):
# type: (nodes.Element) -> None
def visit_tabular_col_spec(self, node: Element) -> None:
raise nodes.SkipNode
def visit_glossary(self, node):
# type: (nodes.Element) -> None
def visit_glossary(self, node: Element) -> None:
pass
def depart_glossary(self, node):
# type: (nodes.Element) -> None
def depart_glossary(self, node: Element) -> None:
pass
def visit_acks(self, node):
# type: (nodes.Element) -> None
def visit_acks(self, node: Element) -> None:
bullet_list = cast(nodes.bullet_list, node[0])
list_items = cast(Iterable[nodes.list_item], bullet_list)
self.ensure_eol()
@ -419,72 +359,57 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
self.body.append('\n')
raise nodes.SkipNode
def visit_hlist(self, node):
# type: (nodes.Element) -> None
def visit_hlist(self, node: Element) -> None:
self.visit_bullet_list(node)
def depart_hlist(self, node):
# type: (nodes.Element) -> None
def depart_hlist(self, node: Element) -> None:
self.depart_bullet_list(node)
def visit_hlistcol(self, node):
# type: (nodes.Element) -> None
def visit_hlistcol(self, node: Element) -> None:
pass
def depart_hlistcol(self, node):
# type: (nodes.Element) -> None
def depart_hlistcol(self, node: Element) -> None:
pass
def visit_literal_emphasis(self, node):
# type: (nodes.Element) -> None
def visit_literal_emphasis(self, node: Element) -> None:
return self.visit_emphasis(node)
def depart_literal_emphasis(self, node):
# type: (nodes.Element) -> None
def depart_literal_emphasis(self, node: Element) -> None:
return self.depart_emphasis(node)
def visit_literal_strong(self, node):
# type: (nodes.Element) -> None
def visit_literal_strong(self, node: Element) -> None:
return self.visit_strong(node)
def depart_literal_strong(self, node):
# type: (nodes.Element) -> None
def depart_literal_strong(self, node: Element) -> None:
return self.depart_strong(node)
def visit_abbreviation(self, node):
# type: (nodes.Element) -> None
def visit_abbreviation(self, node: Element) -> None:
pass
def depart_abbreviation(self, node):
# type: (nodes.Element) -> None
def depart_abbreviation(self, node: Element) -> None:
pass
def visit_manpage(self, node):
# type: (nodes.Element) -> None
def visit_manpage(self, node: Element) -> None:
return self.visit_strong(node)
def depart_manpage(self, node):
# type: (nodes.Element) -> None
def depart_manpage(self, node: Element) -> None:
return self.depart_strong(node)
# overwritten: handle section titles better than in 0.6 release
def visit_caption(self, node):
# type: (nodes.Element) -> None
def visit_caption(self, node: Element) -> None:
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
self.body.append('.sp\n')
else:
super().visit_caption(node)
def depart_caption(self, node):
# type: (nodes.Element) -> None
def depart_caption(self, node: Element) -> None:
if isinstance(node.parent, nodes.container) and node.parent.get('literal_block'):
self.body.append('\n')
else:
super().depart_caption(node)
# overwritten: handle section titles better than in 0.6 release
def visit_title(self, node):
# type: (nodes.Element) -> None
def visit_title(self, node: Element) -> None:
if isinstance(node.parent, addnodes.seealso):
self.body.append('.IP "')
return
@ -498,47 +423,37 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
raise nodes.SkipNode
return super().visit_title(node)
def depart_title(self, node):
# type: (nodes.Element) -> None
def depart_title(self, node: Element) -> None:
if isinstance(node.parent, addnodes.seealso):
self.body.append('"\n')
return
return super().depart_title(node)
def visit_raw(self, node):
# type: (nodes.Element) -> None
def visit_raw(self, node: Element) -> None:
if 'manpage' in node.get('format', '').split():
self.body.append(node.astext())
raise nodes.SkipNode
def visit_meta(self, node):
# type: (nodes.Element) -> None
def visit_meta(self, node: Element) -> None:
raise nodes.SkipNode
def visit_inline(self, node):
# type: (nodes.Element) -> None
def visit_inline(self, node: Element) -> None:
pass
def depart_inline(self, node):
# type: (nodes.Element) -> None
def depart_inline(self, node: Element) -> None:
pass
def visit_math(self, node):
# type: (nodes.Element) -> None
def visit_math(self, node: Element) -> None:
pass
def depart_math(self, node):
# type: (nodes.Element) -> None
def depart_math(self, node: Element) -> None:
pass
def visit_math_block(self, node):
# type: (nodes.Element) -> None
def visit_math_block(self, node: Element) -> None:
self.visit_centered(node)
def depart_math_block(self, node):
# type: (nodes.Element) -> None
def depart_math_block(self, node: Element) -> None:
self.depart_centered(node)
def unknown_visit(self, node):
# type: (nodes.Node) -> None
def unknown_visit(self, node: Node) -> None:
raise NotImplementedError('Unknown node: ' + node.__class__.__name__)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,22 +10,16 @@
from docutils.writers.docutils_xml import Writer as BaseXMLWriter
if False:
# For type annotation
from typing import Any # NOQA
from sphinx.builders import Builder # NOQA
from sphinx.builders import Builder
class XMLWriter(BaseXMLWriter):
def __init__(self, builder):
# type: (Builder) -> None
def __init__(self, builder: Builder) -> None:
super().__init__()
self.builder = builder
self.translator_class = self.builder.get_translator_class()
def translate(self, *args, **kwargs):
# type: (Any, Any) -> None
def translate(self, *args, **kwargs) -> None:
self.document.settings.newlines = \
self.document.settings.indents = \
self.builder.env.config.xml_pretty
@ -45,16 +39,13 @@ class PseudoXMLWriter(BaseXMLWriter):
output = None
"""Final translated form of `document`."""
def __init__(self, builder):
# type: (Builder) -> None
def __init__(self, builder: Builder) -> None:
super().__init__()
self.builder = builder
def translate(self):
# type: () -> None
def translate(self) -> None:
self.output = self.document.pformat()
def supports(self, format):
# type: (str) -> bool
def supports(self, format: str) -> bool:
"""This writer supports all format-specific elements."""
return True

View File

@ -0,0 +1,20 @@
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
extensions = ['sphinx.ext.autosummary']
autosummary_generate = True
autodoc_default_options = {'members': True}
def skip_member(app, what, name, obj, skip, options):
if name == 'skipmeth':
return True
elif name == '_privatemeth':
return False
def setup(app):
app.connect('autodoc-skip-member', skip_member)

View File

@ -0,0 +1,4 @@
.. autosummary::
:toctree: generate
target.Foo

View File

@ -0,0 +1,14 @@
class Foo:
"""docstring of Foo."""
def meth(self):
"""docstring of meth."""
pass
def skipmeth(self):
"""docstring of skipmeth."""
pass
def _privatemeth(self):
"""docstring of _privatemeth."""
pass

View File

@ -315,7 +315,7 @@ def test_numref_with_prefix2(app, status, warning):
assert ('\\hyperref[\\detokenize{baz:table22}]'
'{Table:\\ref{\\detokenize{baz:table22}}}') in result
assert ('\\hyperref[\\detokenize{index:code-1}]{Code-\\ref{\\detokenize{index:code-1}} '
'\\textbar{} }') in result
'| }') in result
assert ('\\hyperref[\\detokenize{baz:code22}]'
'{Code-\\ref{\\detokenize{baz:code22}}}') in result
assert ('\\hyperref[\\detokenize{foo:foo}]'
@ -1414,6 +1414,7 @@ def test_default_latex_documents():
'project': 'STASI™ Documentation',
'author': "Wolfgang Schäuble & G'Beckstein."})
config.init_values()
config.add('latex_engine', None, True, None)
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
r"Wolfgang Schäuble \& G'Beckstein.\@{}", 'manual')]
assert default_latex_documents(config) == expected

View File

@ -8,6 +8,7 @@
:license: BSD, see LICENSE for details.
"""
from unittest import mock
import pytest
@ -47,3 +48,25 @@ def test_anchors_ignored(app, status, warning):
# expect all ok when excluding #top
assert not content
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck', freshenv=True,
confoverrides={'linkcheck_auth': [
(r'.+google\.com/image.+', 'authinfo1'),
(r'.+google\.com.+', 'authinfo2'),
]
})
def test_auth(app, status, warning):
mock_req = mock.MagicMock()
mock_req.return_value = 'fake-response'
with mock.patch.multiple('requests', get=mock_req, head=mock_req):
app.builder.build_all()
for c_args, c_kwargs in mock_req.call_args_list:
if 'google.com/image' in c_args[0]:
assert c_kwargs['auth'] == 'authinfo1'
elif 'google.com' in c_args[0]:
assert c_kwargs['auth'] == 'authinfo2'
else:
assert not c_kwargs['auth']

View File

@ -37,6 +37,11 @@ default_kw = {
}
@pytest.fixture(scope='function', autouse=True)
def unload_target_module():
sys.modules.pop('target', None)
def test_mangle_signature():
TEST = """
() :: ()
@ -335,6 +340,15 @@ def test_generate_autosummary_docs_property(app):
".. autoproperty:: Base.prop")
@pytest.mark.sphinx(testroot='ext-autosummary-skip-member')
def test_autosummary_skip_member(app):
app.build()
content = (app.srcdir / 'generate' / 'target.Foo.rst').text()
assert 'Foo.skipmeth' not in content
assert 'Foo._privatemeth' in content
@pytest.mark.sphinx('dummy', testroot='ext-autosummary',
confoverrides={'autosummary_generate': []})
def test_empty_autosummary_generate(app, status, warning):