mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '3.x'
This commit is contained in:
8
CHANGES
8
CHANGES
@@ -52,6 +52,10 @@ Incompatible changes
|
||||
node_id for cross reference
|
||||
* #7229: rst domain: Non intended behavior is removed such as ``numref_`` links
|
||||
to ``.. rst:role:: numref``
|
||||
* #6903: py domain: Internal data structure has changed. Both objects and
|
||||
modules have node_id for cross reference
|
||||
* #6903: py domain: Non intended behavior is removed such as ``say_hello_``
|
||||
links to ``.. py:function:: say_hello()``
|
||||
|
||||
Deprecated
|
||||
----------
|
||||
@@ -63,6 +67,7 @@ Deprecated
|
||||
* ``sphinx.testing.path.Path.text()``
|
||||
* ``sphinx.testing.path.Path.bytes()``
|
||||
* ``sphinx.util.inspect.getargspec()``
|
||||
* ``sphinx.writers.latex.LaTeXWriter.format_docclass()``
|
||||
|
||||
Features added
|
||||
--------------
|
||||
@@ -78,6 +83,7 @@ Features added
|
||||
* #3106: domain: Register hyperlink target for index page automatically
|
||||
* #6558: std domain: emit a warning for duplicated generic objects
|
||||
* #6830: py domain: Add new event: :event:`object-description-transform`
|
||||
* #6895: py domain: Do not emit nitpicky warnings for built-in types
|
||||
* py domain: Support lambda functions in function signature
|
||||
* Support priority of event handlers. For more detail, see
|
||||
:py:meth:`.Sphinx.connect()`
|
||||
@@ -89,6 +95,8 @@ Features added
|
||||
``no-scaled-link`` class
|
||||
* #7144: Add CSS class indicating its domain for each desc node
|
||||
* #7211: latex: Use babel for Chinese document when using XeLaTeX
|
||||
* #6672: LaTeX: Support LaTeX Theming (experimental)
|
||||
* #7005: LaTeX: Add LaTeX styling macro for :rst:role:`kbd` role
|
||||
* #7220: genindex: Show "main" index entries at first
|
||||
* #7103: linkcheck: writes all links to ``output.json``
|
||||
* #7025: html search: full text search can be disabled for individual document
|
||||
|
||||
@@ -45,7 +45,6 @@ package.
|
||||
|
||||
.. automethod:: Sphinx.add_enumerable_node(node, figtype, title_getter=None, \*\*kwds)
|
||||
|
||||
.. method:: Sphinx.add_directive(name, func, content, arguments, \*\*options)
|
||||
.. automethod:: Sphinx.add_directive(name, directiveclass)
|
||||
|
||||
.. automethod:: Sphinx.add_role(name, role)
|
||||
@@ -54,7 +53,6 @@ package.
|
||||
|
||||
.. automethod:: Sphinx.add_domain(domain)
|
||||
|
||||
.. method:: Sphinx.add_directive_to_domain(domain, name, func, content, arguments, \*\*options)
|
||||
.. automethod:: Sphinx.add_directive_to_domain(domain, name, directiveclass)
|
||||
|
||||
.. automethod:: Sphinx.add_role_to_domain(domain, name, role)
|
||||
@@ -107,6 +105,7 @@ Emitting events
|
||||
---------------
|
||||
|
||||
.. class:: Sphinx
|
||||
:noindex:
|
||||
|
||||
.. automethod:: emit(event, \*arguments)
|
||||
|
||||
@@ -268,11 +267,6 @@ connect handlers to the events. Example:
|
||||
environment from the main process. *docnames* is a set of document names
|
||||
that have been read in the subprocess.
|
||||
|
||||
For a sample of how to deal with this event, look at the standard
|
||||
``sphinx.ext.todo`` extension. The implementation is often similar to that
|
||||
of :event:`env-purge-doc`, only that information is not removed, but added to
|
||||
the main environment from the other environment.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
.. event:: env-updated (app, env)
|
||||
|
||||
@@ -61,6 +61,11 @@ The following is a list of deprecated interfaces.
|
||||
- 5.0
|
||||
- ``inspect.getargspec()``
|
||||
|
||||
* - ``sphinx.writers.latex.LaTeXWriter.format_docclass()``
|
||||
- 3.0
|
||||
- 5.0
|
||||
- LaTeX Themes
|
||||
|
||||
* - ``decode`` argument of ``sphinx.pycode.ModuleAnalyzer()``
|
||||
- 2.4
|
||||
- 4.0
|
||||
|
||||
@@ -817,6 +817,8 @@ Macros
|
||||
multiple paragraphs in header cells of tables.
|
||||
.. versionadded:: 1.6.3
|
||||
``\sphinxstylecodecontinued`` and ``\sphinxstylecodecontinues``.
|
||||
.. versionadded:: 3.0
|
||||
``\sphinxkeyboard``
|
||||
- ``\sphinxtableofcontents``: it is a
|
||||
wrapper (defined differently in :file:`sphinxhowto.cls` and in
|
||||
:file:`sphinxmanual.cls`) of standard ``\tableofcontents``. The macro
|
||||
|
||||
@@ -227,6 +227,7 @@ them to generate links or output multiply used elements.
|
||||
documents.
|
||||
|
||||
.. function:: pathto(file, 1)
|
||||
:noindex:
|
||||
|
||||
Return the path to a *file* which is a filename relative to the root of the
|
||||
generated output. Use this to refer to static files.
|
||||
@@ -413,10 +414,6 @@ are in HTML form), these variables are also available:
|
||||
nonempty if the :confval:`html_copy_source` value is ``True``.
|
||||
This has empty value on creating automatically-generated files.
|
||||
|
||||
.. data:: title
|
||||
|
||||
The page title.
|
||||
|
||||
.. data:: toc
|
||||
|
||||
The local table of contents for the current page, rendered as HTML bullet
|
||||
|
||||
@@ -1904,7 +1904,7 @@ These options influence LaTeX output.
|
||||
|
||||
This value determines how to group the document tree into LaTeX source files.
|
||||
It must be a list of tuples ``(startdocname, targetname, title, author,
|
||||
documentclass, toctree_only)``, where the items are:
|
||||
theme, toctree_only)``, where the items are:
|
||||
|
||||
*startdocname*
|
||||
String that specifies the :term:`document name` of the LaTeX file's master
|
||||
@@ -1926,13 +1926,8 @@ These options influence LaTeX output.
|
||||
applies. Use ``\\and`` to separate multiple authors, as in:
|
||||
``'John \\and Sarah'`` (backslashes must be Python-escaped to reach LaTeX).
|
||||
|
||||
*documentclass*
|
||||
Normally, one of ``'manual'`` or ``'howto'`` (provided by Sphinx and based
|
||||
on ``'report'``, resp. ``'article'``; Japanese documents use ``'jsbook'``,
|
||||
resp. ``'jreport'``.) "howto" (non-Japanese) documents will not get
|
||||
appendices. Also they have a simpler title page. Other document classes
|
||||
can be given. Independently of the document class, the "sphinx" package is
|
||||
always loaded in order to define Sphinx's custom LaTeX commands.
|
||||
*theme*
|
||||
LaTeX theme. See :confval:`latex_theme`.
|
||||
|
||||
*toctree_only*
|
||||
Must be ``True`` or ``False``. If true, the *startdoc* document itself is
|
||||
@@ -2087,6 +2082,33 @@ These options influence LaTeX output.
|
||||
This overrides the files which is provided from Sphinx such as
|
||||
``sphinx.sty``.
|
||||
|
||||
.. confval:: latex_theme
|
||||
|
||||
The "theme" that the LaTeX output should use. It is a collection of settings
|
||||
for LaTeX output (ex. document class, top level sectioning unit and so on).
|
||||
|
||||
As a built-in LaTeX themes, ``manual`` and ``howto`` are bundled.
|
||||
|
||||
``manual``
|
||||
A LaTeX theme for writing a manual. It imports the ``report`` document
|
||||
class (Japanese documents use ``jsbook``).
|
||||
|
||||
``howto``
|
||||
A LaTeX theme for writing an article. It imports the ``article`` document
|
||||
class (Japanese documents use ``jreport`` rather). :confval:`latex_appendices`
|
||||
is available only for this theme.
|
||||
|
||||
It defaults to ``'manual'``.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
.. confval:: latex_theme_path
|
||||
|
||||
A list of paths that contain custom LaTeX themes as subdirectories. Relative
|
||||
paths are taken as relative to the configuration directory.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
|
||||
.. _text-options:
|
||||
|
||||
|
||||
@@ -273,6 +273,7 @@ Additionally, the following filters are available
|
||||
replaces the builtin Jinja `escape filter`_ that does html-escaping.
|
||||
|
||||
.. function:: underline(s, line='=')
|
||||
:noindex:
|
||||
|
||||
Add a title underline to a piece of text.
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ import sphinx.builders.latex.nodes # NOQA # Workaround: import this before wri
|
||||
from sphinx import package_dir, addnodes, highlighting
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.builders import Builder
|
||||
from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS
|
||||
from sphinx.builders.latex.constants import ADDITIONAL_SETTINGS, DEFAULT_SETTINGS, SHORTHANDOFF
|
||||
from sphinx.builders.latex.theming import Theme, ThemeFactory
|
||||
from sphinx.builders.latex.util import ExtBabel
|
||||
from sphinx.config import Config, ENUM
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning
|
||||
@@ -126,11 +127,13 @@ class LaTeXBuilder(Builder):
|
||||
self.context = {} # type: Dict[str, Any]
|
||||
self.docnames = [] # type: Iterable[str]
|
||||
self.document_data = [] # type: List[Tuple[str, str, str, str, str, bool]]
|
||||
self.themes = ThemeFactory(self.app)
|
||||
self.usepackages = self.app.registry.latex_packages
|
||||
texescape.init()
|
||||
|
||||
self.init_context()
|
||||
self.init_babel()
|
||||
self.init_multilingual()
|
||||
|
||||
def get_outdated_docs(self) -> Union[str, List[str]]:
|
||||
return 'all documents' # for now
|
||||
@@ -206,6 +209,41 @@ class LaTeXBuilder(Builder):
|
||||
logger.warning(__('no Babel option known for language %r'),
|
||||
self.config.language)
|
||||
|
||||
def init_multilingual(self) -> None:
|
||||
if self.context['latex_engine'] == 'pdflatex':
|
||||
if not self.babel.uses_cyrillic():
|
||||
if 'X2' in self.context['fontenc']:
|
||||
self.context['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
self.context['textcyrillic'] = '\\usepackage[Xtwo]{sphinxcyrillic}'
|
||||
elif 'T2A' in self.context['fontenc']:
|
||||
self.context['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
self.context['textcyrillic'] = '\\usepackage[TtwoA]{sphinxcyrillic}'
|
||||
if 'LGR' in self.context['fontenc']:
|
||||
self.context['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
else:
|
||||
self.context['textgreek'] = ''
|
||||
|
||||
# 'babel' key is public and user setting must be obeyed
|
||||
if self.context['babel']:
|
||||
self.context['classoptions'] += ',' + self.babel.get_language()
|
||||
# this branch is not taken for xelatex/lualatex if default settings
|
||||
self.context['multilingual'] = self.context['babel']
|
||||
if self.config.language:
|
||||
self.context['shorthandoff'] = SHORTHANDOFF
|
||||
|
||||
# Times fonts don't work with Cyrillic languages
|
||||
if self.babel.uses_cyrillic() and 'fontpkg' not in self.config.latex_elements:
|
||||
self.context['fontpkg'] = ''
|
||||
elif self.context['polyglossia']:
|
||||
self.context['classoptions'] += ',' + self.babel.get_language()
|
||||
options = self.babel.get_mainlanguage_options()
|
||||
if options:
|
||||
language = r'\setmainlanguage[%s]{%s}' % (options, self.babel.get_language())
|
||||
else:
|
||||
language = r'\setmainlanguage{%s}' % self.babel.get_language()
|
||||
|
||||
self.context['multilingual'] = '%s\n%s' % (self.context['polyglossia'], language)
|
||||
|
||||
def write_stylesheet(self) -> None:
|
||||
highlighter = highlighting.PygmentsBridge('latex', self.config.pygments_style)
|
||||
stylesheet = path.join(self.outdir, 'sphinxhighlight.sty')
|
||||
@@ -227,7 +265,8 @@ class LaTeXBuilder(Builder):
|
||||
self.write_stylesheet()
|
||||
|
||||
for entry in self.document_data:
|
||||
docname, targetname, title, author, docclass = entry[:5]
|
||||
docname, targetname, title, author, themename = entry[:5]
|
||||
theme = self.themes.get(themename)
|
||||
toctree_only = False
|
||||
if len(entry) > 5:
|
||||
toctree_only = entry[5]
|
||||
@@ -243,21 +282,22 @@ class LaTeXBuilder(Builder):
|
||||
|
||||
doctree = self.assemble_doctree(
|
||||
docname, toctree_only,
|
||||
appendices=(self.config.latex_appendices if docclass != 'howto' else []))
|
||||
doctree['docclass'] = docclass
|
||||
appendices=(self.config.latex_appendices if theme.name != 'howto' else []))
|
||||
doctree['docclass'] = theme.docclass
|
||||
doctree['contentsname'] = self.get_contentsname(docname)
|
||||
doctree['tocdepth'] = tocdepth
|
||||
self.post_process_images(doctree)
|
||||
self.update_doc_context(title, author)
|
||||
self.update_doc_context(title, author, theme)
|
||||
|
||||
with progress_message(__("writing")):
|
||||
docsettings._author = author
|
||||
docsettings._title = title
|
||||
docsettings._contentsname = doctree['contentsname']
|
||||
docsettings._docname = docname
|
||||
docsettings._docclass = docclass
|
||||
docsettings._docclass = theme.name
|
||||
|
||||
doctree.settings = docsettings
|
||||
docwriter.theme = theme
|
||||
docwriter.write(doctree, destination)
|
||||
|
||||
def get_contentsname(self, indexfile: str) -> str:
|
||||
@@ -270,9 +310,11 @@ class LaTeXBuilder(Builder):
|
||||
|
||||
return contentsname
|
||||
|
||||
def update_doc_context(self, title: str, author: str) -> None:
|
||||
def update_doc_context(self, title: str, author: str, theme: Theme) -> None:
|
||||
self.context['title'] = title
|
||||
self.context['author'] = author
|
||||
self.context['docclass'] = theme.docclass
|
||||
self.context['wrapperclass'] = theme.wrapperclass
|
||||
|
||||
def assemble_doctree(self, indexfile: str, toctree_only: bool, appendices: List[str]) -> nodes.document: # NOQA
|
||||
self.docnames = set([indexfile] + appendices)
|
||||
@@ -487,7 +529,7 @@ def default_latex_documents(config: Config) -> List[Tuple[str, str, str, str, st
|
||||
make_filename_from_project(config.project) + '.tex',
|
||||
texescape.escape_abbr(project),
|
||||
texescape.escape_abbr(author),
|
||||
'manual')]
|
||||
config.latex_theme)]
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
@@ -510,6 +552,8 @@ def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.add_config_value('latex_show_pagerefs', False, None)
|
||||
app.add_config_value('latex_elements', {}, None)
|
||||
app.add_config_value('latex_additional_files', [], None)
|
||||
app.add_config_value('latex_theme', 'manual', None, [str])
|
||||
app.add_config_value('latex_theme_path', [], None, [list])
|
||||
|
||||
app.add_config_value('latex_docclass', default_latex_docclass, None)
|
||||
|
||||
|
||||
@@ -192,3 +192,11 @@ ADDITIONAL_SETTINGS = {
|
||||
'fontpkg': XELATEX_GREEK_DEFAULT_FONTPKG,
|
||||
},
|
||||
} # type: Dict[Any, Dict[str, Any]]
|
||||
|
||||
|
||||
SHORTHANDOFF = r'''
|
||||
\ifdefined\shorthandoff
|
||||
\ifnum\catcode`\=\string=\active\shorthandoff{=}\fi
|
||||
\ifnum\catcode`\"=\active\shorthandoff{"}\fi
|
||||
\fi
|
||||
'''
|
||||
|
||||
118
sphinx/builders/latex/theming.py
Normal file
118
sphinx/builders/latex/theming.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
sphinx.builders.latex.theming
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Theming support for LaTeX builder.
|
||||
|
||||
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import configparser
|
||||
from os import path
|
||||
from typing import Dict
|
||||
|
||||
from sphinx.application import Sphinx
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import ThemeError
|
||||
from sphinx.locale import __
|
||||
from sphinx.util import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Theme:
|
||||
"""A set of LaTeX configurations."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name = name
|
||||
self.docclass = name
|
||||
self.wrapperclass = name
|
||||
self.toplevel_sectioning = 'chapter'
|
||||
|
||||
|
||||
class BuiltInTheme(Theme):
|
||||
"""A built-in LaTeX theme."""
|
||||
|
||||
def __init__(self, name: str, config: Config) -> None:
|
||||
# Note: Don't call supermethod here.
|
||||
self.name = name
|
||||
self.latex_docclass = config.latex_docclass # type: Dict[str, str]
|
||||
|
||||
@property
|
||||
def docclass(self) -> str: # type: ignore
|
||||
if self.name == 'howto':
|
||||
return self.latex_docclass.get('howto', 'article')
|
||||
else:
|
||||
return self.latex_docclass.get('manual', 'report')
|
||||
|
||||
@property
|
||||
def wrapperclass(self) -> str: # type: ignore
|
||||
if self.name in ('manual', 'howto'):
|
||||
return 'sphinx' + self.name
|
||||
else:
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def toplevel_sectioning(self) -> str: # type: ignore
|
||||
# we assume LaTeX class provides \chapter command except in case
|
||||
# of non-Japanese 'howto' case
|
||||
if self.name == 'howto' and not self.docclass.startswith('j'):
|
||||
return 'section'
|
||||
else:
|
||||
return 'chapter'
|
||||
|
||||
|
||||
class UserTheme(Theme):
|
||||
"""A user defined LaTeX theme."""
|
||||
|
||||
def __init__(self, name: str, filename: str) -> None:
|
||||
self.name = name
|
||||
self.config = configparser.RawConfigParser()
|
||||
self.config.read(path.join(filename))
|
||||
|
||||
try:
|
||||
self.docclass = self.config.get('theme', 'docclass')
|
||||
self.wrapperclass = self.config.get('theme', 'wrapperclass')
|
||||
self.toplevel_sectioning = self.config.get('theme', 'toplevel_sectioning')
|
||||
except configparser.NoSectionError:
|
||||
raise ThemeError(__('%r doesn\'t have "theme" setting') % filename)
|
||||
except configparser.NoOptionError as exc:
|
||||
raise ThemeError(__('%r doesn\'t have "%s" setting') % (filename, exc.args[0]))
|
||||
|
||||
|
||||
class ThemeFactory:
|
||||
"""A factory class for LaTeX Themes."""
|
||||
|
||||
def __init__(self, app: Sphinx) -> None:
|
||||
self.themes = {} # type: Dict[str, Theme]
|
||||
self.theme_paths = [path.join(app.srcdir, p) for p in app.config.latex_theme_path]
|
||||
self.load_builtin_themes(app.config)
|
||||
|
||||
def load_builtin_themes(self, config: Config) -> None:
|
||||
"""Load built-in themes."""
|
||||
self.themes['manual'] = BuiltInTheme('manual', config)
|
||||
self.themes['howto'] = BuiltInTheme('howto', config)
|
||||
|
||||
def get(self, name: str) -> Theme:
|
||||
"""Get a theme for given *name*."""
|
||||
if name in self.themes:
|
||||
return self.themes[name]
|
||||
else:
|
||||
theme = self.find_user_theme(name)
|
||||
if theme:
|
||||
return theme
|
||||
else:
|
||||
return Theme(name)
|
||||
|
||||
def find_user_theme(self, name: str) -> Theme:
|
||||
"""Find a theme named as *name* from latex_theme_path."""
|
||||
for theme_path in self.theme_paths:
|
||||
config_path = path.join(theme_path, name, 'theme.conf')
|
||||
if path.isfile(config_path):
|
||||
try:
|
||||
return UserTheme(name, config_path)
|
||||
except ThemeError as exc:
|
||||
logger.warning(exc)
|
||||
|
||||
return None
|
||||
@@ -11,11 +11,14 @@
|
||||
import re
|
||||
import warnings
|
||||
from copy import deepcopy
|
||||
from typing import Any, Callable, Dict, Iterator, List, Match, Pattern, Tuple, Type, Union
|
||||
from typing import (
|
||||
Any, Callable, Dict, Iterator, List, Match, Pattern, Tuple, Type, TypeVar, Union
|
||||
)
|
||||
|
||||
from docutils import nodes, utils
|
||||
from docutils.nodes import Element, Node, TextElement
|
||||
from docutils.nodes import Element, Node, TextElement, system_message
|
||||
from docutils.parsers.rst import directives
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx.addnodes import desc_signature, pending_xref
|
||||
@@ -39,6 +42,7 @@ from sphinx.util.nodes import make_refnode
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
StringifyTransform = Callable[[Any], str]
|
||||
T = TypeVar('T')
|
||||
|
||||
"""
|
||||
Important note on ids
|
||||
@@ -652,7 +656,7 @@ class ASTCPPAttribute(ASTBase):
|
||||
def __init__(self, arg: str) -> None:
|
||||
self.arg = arg
|
||||
|
||||
def _stringify(self, transform):
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
return "[[" + self.arg + "]]"
|
||||
|
||||
def describe_signature(self, signode: desc_signature) -> None:
|
||||
@@ -733,12 +737,13 @@ class ASTPointerLiteral(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'LDnE'
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('nullptr'))
|
||||
|
||||
|
||||
class ASTBooleanLiteral(ASTBase):
|
||||
def __init__(self, value):
|
||||
def __init__(self, value: bool) -> None:
|
||||
self.value = value
|
||||
|
||||
def _stringify(self, transform: StringifyTransform) -> str:
|
||||
@@ -753,7 +758,8 @@ class ASTBooleanLiteral(ASTBase):
|
||||
else:
|
||||
return 'L0E'
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text(str(self)))
|
||||
|
||||
|
||||
@@ -767,7 +773,8 @@ class ASTNumberLiteral(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return "L%sE" % self.data
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
txt = str(self)
|
||||
signode.append(nodes.Text(txt, txt))
|
||||
|
||||
@@ -802,7 +809,8 @@ class ASTCharLiteral(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return self.type + str(self.value)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
txt = str(self)
|
||||
signode.append(nodes.Text(txt, txt))
|
||||
|
||||
@@ -818,7 +826,8 @@ class ASTStringLiteral(ASTBase):
|
||||
# note: the length is not really correct with escaping
|
||||
return "LA%d_KcE" % (len(self.data) - 2)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
txt = str(self)
|
||||
signode.append(nodes.Text(txt, txt))
|
||||
|
||||
@@ -830,7 +839,8 @@ class ASTThisLiteral(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return "fpT"
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text("this"))
|
||||
|
||||
|
||||
@@ -844,7 +854,8 @@ class ASTParenExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('(', '('))
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')', ')'))
|
||||
@@ -894,7 +905,8 @@ class ASTFoldExpr(ASTBase):
|
||||
res.append(self.rightExpr.get_id(version))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('('))
|
||||
if self.leftExpr:
|
||||
self.leftExpr.describe_signature(signode, mode, env, symbol)
|
||||
@@ -936,7 +948,8 @@ class ASTBinOpExpr(ASTBase):
|
||||
res.append(self.exprs[-1].get_id(version))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
self.exprs[0].describe_signature(signode, mode, env, symbol)
|
||||
for i in range(1, len(self.exprs)):
|
||||
signode.append(nodes.Text(' '))
|
||||
@@ -970,7 +983,8 @@ class ASTAssignmentExpr(ASTBase):
|
||||
res.append(self.exprs[-1].get_id(version))
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
self.exprs[0].describe_signature(signode, mode, env, symbol)
|
||||
for i in range(1, len(self.exprs)):
|
||||
signode.append(nodes.Text(' '))
|
||||
@@ -994,7 +1008,8 @@ class ASTCastExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'cv' + self.typ.get_id(version) + self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('('))
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')'))
|
||||
@@ -1012,7 +1027,8 @@ class ASTUnaryOpExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return _id_operator_unary_v2[self.op] + self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text(self.op))
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
@@ -1027,7 +1043,8 @@ class ASTSizeofParamPack(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'sZ' + self.identifier.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('sizeof...('))
|
||||
self.identifier.describe_signature(signode, mode, env,
|
||||
symbol=symbol, prefix="", templateArgs="")
|
||||
@@ -1044,7 +1061,8 @@ class ASTSizeofType(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'st' + self.typ.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('sizeof('))
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')'))
|
||||
@@ -1060,7 +1078,8 @@ class ASTSizeofExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'sz' + self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('sizeof '))
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
@@ -1075,7 +1094,8 @@ class ASTAlignofExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'at' + self.typ.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('alignof('))
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')'))
|
||||
@@ -1091,7 +1111,8 @@ class ASTNoexceptExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return 'nx' + self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('noexcept('))
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(')'))
|
||||
@@ -1130,7 +1151,8 @@ class ASTNewExpr(ASTBase):
|
||||
res.append('E')
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
if self.rooted:
|
||||
signode.append(nodes.Text('::'))
|
||||
signode.append(nodes.Text('new '))
|
||||
@@ -1166,7 +1188,8 @@ class ASTDeleteExpr(ASTBase):
|
||||
id = "dl"
|
||||
return id + self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
if self.rooted:
|
||||
signode.append(nodes.Text('::'))
|
||||
signode.append(nodes.Text('delete '))
|
||||
@@ -1196,7 +1219,8 @@ class ASTExplicitCast(ASTBase):
|
||||
self.typ.get_id(version) +
|
||||
self.expr.get_id(version))
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text(self.cast))
|
||||
signode.append(nodes.Text('<'))
|
||||
self.typ.describe_signature(signode, mode, env, symbol)
|
||||
@@ -1218,7 +1242,8 @@ class ASTTypeId(ASTBase):
|
||||
prefix = 'ti' if self.isType else 'te'
|
||||
return prefix + self.typeOrExpr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('typeid'))
|
||||
signode.append(nodes.Text('('))
|
||||
self.typeOrExpr.describe_signature(signode, mode, env, symbol)
|
||||
@@ -1239,7 +1264,8 @@ class ASTPostfixCallExpr(ASTBase):
|
||||
res.append('E')
|
||||
return ''.join(res)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
self.lst.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
|
||||
@@ -1253,7 +1279,8 @@ class ASTPostfixArray(ASTBase):
|
||||
def get_id(self, idPrefix: str, version: int) -> str:
|
||||
return 'ix' + idPrefix + self.expr.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('['))
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode.append(nodes.Text(']'))
|
||||
@@ -1266,7 +1293,8 @@ class ASTPostfixInc(ASTBase):
|
||||
def get_id(self, idPrefix: str, version: int) -> str:
|
||||
return 'pp' + idPrefix
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('++'))
|
||||
|
||||
|
||||
@@ -1277,7 +1305,8 @@ class ASTPostfixDec(ASTBase):
|
||||
def get_id(self, idPrefix: str, version: int) -> str:
|
||||
return 'mm' + idPrefix
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('--'))
|
||||
|
||||
|
||||
@@ -1291,7 +1320,8 @@ class ASTPostfixMember(ASTBase):
|
||||
def get_id(self, idPrefix: str, version: int) -> str:
|
||||
return 'dt' + idPrefix + self.name.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('.'))
|
||||
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
||||
|
||||
@@ -1306,7 +1336,8 @@ class ASTPostfixMemberOfPointer(ASTBase):
|
||||
def get_id(self, idPrefix: str, version: int) -> str:
|
||||
return 'pt' + idPrefix + self.name.get_id(version)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode.append(nodes.Text('->'))
|
||||
self.name.describe_signature(signode, 'noneIsName', env, symbol)
|
||||
|
||||
@@ -1329,7 +1360,8 @@ class ASTPostfixExpr(ASTBase):
|
||||
id = p.get_id(id, version)
|
||||
return id
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
self.prefix.describe_signature(signode, mode, env, symbol)
|
||||
for p in self.postFixes:
|
||||
p.describe_signature(signode, mode, env, symbol)
|
||||
@@ -1346,7 +1378,8 @@ class ASTPackExpansionExpr(ASTBase):
|
||||
id = self.expr.get_id(version)
|
||||
return 'sp' + id
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
self.expr.describe_signature(signode, mode, env, symbol)
|
||||
signode += nodes.Text('...')
|
||||
|
||||
@@ -1361,7 +1394,8 @@ class ASTFallbackExpr(ASTBase):
|
||||
def get_id(self, version: int) -> str:
|
||||
return str(self.expr)
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
signode += nodes.Text(self.expr)
|
||||
|
||||
|
||||
@@ -1667,13 +1701,13 @@ class ASTTemplateParams(ASTBase):
|
||||
env: "BuildEnvironment", symbol: "Symbol", lineSpec: bool = None
|
||||
) -> None:
|
||||
# 'lineSpec' is defaulted becuase of template template parameters
|
||||
def makeLine(parentNode=parentNode):
|
||||
def makeLine(parentNode: desc_signature = parentNode) -> addnodes.desc_signature_line:
|
||||
signode = addnodes.desc_signature_line()
|
||||
parentNode += signode
|
||||
signode.sphinx_cpp_tagname = 'templateParams'
|
||||
return signode
|
||||
if self.isNested:
|
||||
lineNode = parentNode
|
||||
lineNode = parentNode # type: Element
|
||||
else:
|
||||
lineNode = makeLine()
|
||||
lineNode += nodes.Text("template<")
|
||||
@@ -1822,7 +1856,7 @@ class ASTTemplateDeclarationPrefix(ASTBase):
|
||||
|
||||
|
||||
class ASTOperator(ASTBase):
|
||||
def is_anon(self):
|
||||
def is_anon(self) -> bool:
|
||||
return False
|
||||
|
||||
def is_operator(self) -> bool:
|
||||
@@ -2300,11 +2334,11 @@ class ASTParametersQualifiers(ASTBase):
|
||||
paramlist += param
|
||||
signode += paramlist
|
||||
|
||||
def _add_anno(signode, text):
|
||||
def _add_anno(signode: desc_signature, text: str) -> None:
|
||||
signode += nodes.Text(' ')
|
||||
signode += addnodes.desc_annotation(text, text)
|
||||
|
||||
def _add_text(signode, text):
|
||||
def _add_text(signode: desc_signature, text: str) -> None:
|
||||
signode += nodes.Text(' ' + text)
|
||||
|
||||
if self.volatile:
|
||||
@@ -2376,7 +2410,7 @@ class ASTDeclSpecsSimple(ASTBase):
|
||||
return ' '.join(res)
|
||||
|
||||
def describe_signature(self, modifiers: List[Node]) -> None:
|
||||
def _add(modifiers, text):
|
||||
def _add(modifiers: List[Node], text: str) -> None:
|
||||
if len(modifiers) > 0:
|
||||
modifiers.append(nodes.Text(' '))
|
||||
modifiers.append(addnodes.desc_annotation(text, text))
|
||||
@@ -2456,9 +2490,9 @@ class ASTDeclSpecs(ASTBase):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
_verify_description_mode(mode)
|
||||
modifiers = [] # type: List[nodes.Node]
|
||||
modifiers = [] # type: List[Node]
|
||||
|
||||
def _add(modifiers, text):
|
||||
def _add(modifiers: List[Node], text: str) -> None:
|
||||
if len(modifiers) > 0:
|
||||
modifiers.append(nodes.Text(' '))
|
||||
modifiers.append(addnodes.desc_annotation(text, text))
|
||||
@@ -2503,7 +2537,8 @@ class ASTArray(ASTBase):
|
||||
else:
|
||||
return 'A_'
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
def describe_signature(self, signode: desc_signature, mode: str,
|
||||
env: "BuildEnvironment", symbol: "Symbol") -> None:
|
||||
_verify_description_mode(mode)
|
||||
signode.append(nodes.Text("["))
|
||||
if self.size:
|
||||
@@ -2595,7 +2630,7 @@ class ASTDeclaratorPtr(ASTBase):
|
||||
if len(self.attrs) > 0 and (self.volatile or self.const):
|
||||
signode += nodes.Text(' ')
|
||||
|
||||
def _add_anno(signode, text):
|
||||
def _add_anno(signode: desc_signature, text: str) -> None:
|
||||
signode += addnodes.desc_annotation(text, text)
|
||||
if self.volatile:
|
||||
_add_anno(signode, 'volatile')
|
||||
@@ -2795,7 +2830,7 @@ class ASTDeclaratorMemPtr(ASTBase):
|
||||
self.className.describe_signature(signode, mode, env, symbol)
|
||||
signode += nodes.Text('::*')
|
||||
|
||||
def _add_anno(signode, text):
|
||||
def _add_anno(signode: desc_signature, text: str) -> None:
|
||||
signode += addnodes.desc_annotation(text, text)
|
||||
if self.volatile:
|
||||
_add_anno(signode, 'volatile')
|
||||
@@ -3565,7 +3600,7 @@ class Symbol:
|
||||
debug_show_tree = False
|
||||
|
||||
@staticmethod
|
||||
def debug_print(*args):
|
||||
def debug_print(*args: Any) -> None:
|
||||
print(Symbol.debug_indent_string * Symbol.debug_indent, end="")
|
||||
print(*args)
|
||||
|
||||
@@ -3627,7 +3662,7 @@ class Symbol:
|
||||
# and symbol addition should be done as well
|
||||
self._add_template_and_function_params()
|
||||
|
||||
def _add_template_and_function_params(self):
|
||||
def _add_template_and_function_params(self) -> None:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent += 1
|
||||
Symbol.debug_print("_add_template_and_function_params:")
|
||||
@@ -3663,7 +3698,7 @@ class Symbol:
|
||||
if Symbol.debug_lookup:
|
||||
Symbol.debug_indent -= 1
|
||||
|
||||
def remove(self):
|
||||
def remove(self) -> None:
|
||||
if self.parent is None:
|
||||
return
|
||||
assert self in self.parent._children
|
||||
@@ -3771,7 +3806,7 @@ class Symbol:
|
||||
Symbol.debug_print("correctPrimaryTemplateAargs:", correctPrimaryTemplateArgs)
|
||||
Symbol.debug_print("searchInSiblings: ", searchInSiblings)
|
||||
|
||||
def isSpecialization():
|
||||
def isSpecialization() -> bool:
|
||||
# the names of the template parameters must be given exactly as args
|
||||
# and params that are packs must in the args be the name expanded
|
||||
if len(templateParams.params) != len(templateArgs.args):
|
||||
@@ -6509,7 +6544,7 @@ class CPPObject(ObjectDescription):
|
||||
def describe_signature(self, signode: desc_signature, ast: Any, options: Dict) -> None:
|
||||
ast.describe_signature(signode, 'lastIsName', self.env, options)
|
||||
|
||||
def run(self):
|
||||
def run(self) -> List[Node]:
|
||||
env = self.state.document.settings.env # from ObjectDescription.run
|
||||
if 'cpp:parent_symbol' not in env.temp_data:
|
||||
root = env.domaindata['cpp']['root_symbol']
|
||||
@@ -6617,7 +6652,7 @@ class CPPClassObject(CPPObject):
|
||||
object_type = 'class'
|
||||
|
||||
@property
|
||||
def display_object_type(self):
|
||||
def display_object_type(self) -> str:
|
||||
# the distinction between class and struct is only cosmetic
|
||||
assert self.objtype in ('class', 'struct')
|
||||
return self.objtype
|
||||
@@ -6733,7 +6768,8 @@ class CPPNamespacePopObject(SphinxDirective):
|
||||
|
||||
|
||||
class AliasNode(nodes.Element):
|
||||
def __init__(self, sig, env=None, parentKey=None):
|
||||
def __init__(self, sig: str, env: "BuildEnvironment" = None,
|
||||
parentKey: LookupKey = None) -> None:
|
||||
super().__init__()
|
||||
self.sig = sig
|
||||
if env is not None:
|
||||
@@ -6745,8 +6781,8 @@ class AliasNode(nodes.Element):
|
||||
assert parentKey is not None
|
||||
self.parentKey = parentKey
|
||||
|
||||
def copy(self):
|
||||
return self.__class__(self.sig, env=None, parentKey=self.parentKey)
|
||||
def copy(self: T) -> T:
|
||||
return self.__class__(self.sig, env=None, parentKey=self.parentKey) # type: ignore
|
||||
|
||||
|
||||
class AliasTransform(SphinxTransform):
|
||||
@@ -6755,7 +6791,7 @@ class AliasTransform(SphinxTransform):
|
||||
def apply(self, **kwargs: Any) -> None:
|
||||
for node in self.document.traverse(AliasNode):
|
||||
class Warner:
|
||||
def warn(self, msg):
|
||||
def warn(self, msg: Any) -> None:
|
||||
logger.warning(msg, location=node)
|
||||
warner = Warner()
|
||||
sig = node.sig
|
||||
@@ -6898,7 +6934,7 @@ class CPPXRefRole(XRefRole):
|
||||
|
||||
|
||||
class CPPExprRole:
|
||||
def __init__(self, asCode):
|
||||
def __init__(self, asCode: bool) -> None:
|
||||
if asCode:
|
||||
# render the expression as inline code
|
||||
self.class_type = 'cpp-expr'
|
||||
@@ -6908,9 +6944,11 @@ class CPPExprRole:
|
||||
self.class_type = 'cpp-texpr'
|
||||
self.node_type = nodes.inline
|
||||
|
||||
def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
def __call__(self, typ: str, rawtext: str, text: str, lineno: int,
|
||||
inliner: Inliner, options: Dict = {}, content: List[str] = []
|
||||
) -> Tuple[List[Node], List[system_message]]:
|
||||
class Warner:
|
||||
def warn(self, msg):
|
||||
def warn(self, msg: str) -> None:
|
||||
inliner.reporter.warning(msg, line=lineno)
|
||||
text = utils.unescape(text).replace('\n', ' ')
|
||||
env = inliner.document.settings.env
|
||||
@@ -7056,7 +7094,7 @@ class CPPDomain(Domain):
|
||||
typ: str, target: str, node: pending_xref, contnode: Element,
|
||||
emitWarnings: bool = True) -> Tuple[Element, str]:
|
||||
class Warner:
|
||||
def warn(self, msg):
|
||||
def warn(self, msg: str) -> None:
|
||||
if emitWarnings:
|
||||
logger.warning(msg, location=node)
|
||||
warner = Warner()
|
||||
@@ -7067,7 +7105,8 @@ class CPPDomain(Domain):
|
||||
try:
|
||||
ast, isShorthand = parser.parse_xref_object()
|
||||
except DefinitionError as e:
|
||||
def findWarning(e): # as arg to stop flake8 from complaining
|
||||
# as arg to stop flake8 from complaining
|
||||
def findWarning(e: Exception) -> Tuple[str, Exception]:
|
||||
if typ != 'any' and typ != 'func':
|
||||
return target, e
|
||||
# hax on top of the paren hax to try to get correct errors
|
||||
@@ -7138,7 +7177,7 @@ class CPPDomain(Domain):
|
||||
typ = 'class'
|
||||
declTyp = s.declaration.objectType
|
||||
|
||||
def checkType():
|
||||
def checkType() -> bool:
|
||||
if typ == 'any' or typ == 'identifier':
|
||||
return True
|
||||
if declTyp == 'templateParam':
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import builtins
|
||||
import inspect
|
||||
import re
|
||||
import typing
|
||||
import warnings
|
||||
from inspect import Parameter
|
||||
from typing import Any, Dict, Iterable, Iterator, List, Tuple
|
||||
@@ -32,7 +35,7 @@ from sphinx.util import logging
|
||||
from sphinx.util.docfields import Field, GroupedField, TypedField
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
from sphinx.util.inspect import signature_from_str
|
||||
from sphinx.util.nodes import make_refnode
|
||||
from sphinx.util.nodes import make_id, make_refnode
|
||||
from sphinx.util.typing import TextlikeNode
|
||||
|
||||
if False:
|
||||
@@ -358,19 +361,22 @@ class PyObject(ObjectDescription):
|
||||
signode: desc_signature) -> None:
|
||||
modname = self.options.get('module', self.env.ref_context.get('py:module'))
|
||||
fullname = (modname + '.' if modname else '') + name_cls[0]
|
||||
# note target
|
||||
if fullname not in self.state.document.ids:
|
||||
signode['names'].append(fullname)
|
||||
signode['ids'].append(fullname)
|
||||
self.state.document.note_explicit_target(signode)
|
||||
node_id = make_id(self.env, self.state.document, modname or '', name_cls[0])
|
||||
signode['ids'].append(node_id)
|
||||
|
||||
domain = cast(PythonDomain, self.env.get_domain('py'))
|
||||
domain.note_object(fullname, self.objtype, location=signode)
|
||||
# Assign old styled node_id(fullname) not to break old hyperlinks (if possible)
|
||||
# Note: Will removed in Sphinx-5.0 (RemovedInSphinx50Warning)
|
||||
if node_id != fullname and fullname not in self.state.document.ids:
|
||||
signode['ids'].append(fullname)
|
||||
|
||||
self.state.document.note_explicit_target(signode)
|
||||
|
||||
domain = cast(PythonDomain, self.env.get_domain('py'))
|
||||
domain.note_object(fullname, self.objtype, node_id, location=signode)
|
||||
|
||||
indextext = self.get_index_text(modname, name_cls)
|
||||
if indextext:
|
||||
self.indexnode['entries'].append(('single', indextext,
|
||||
fullname, '', None))
|
||||
self.indexnode['entries'].append(('single', indextext, node_id, '', None))
|
||||
|
||||
def before_content(self) -> None:
|
||||
"""Handle object nesting before content
|
||||
@@ -788,24 +794,43 @@ class PyModule(SphinxDirective):
|
||||
ret = [] # type: List[Node]
|
||||
if not noindex:
|
||||
# note module to the domain
|
||||
node_id = make_id(self.env, self.state.document, 'module', modname)
|
||||
target = nodes.target('', '', ids=[node_id], ismod=True)
|
||||
self.set_source_info(target)
|
||||
|
||||
# Assign old styled node_id not to break old hyperlinks (if possible)
|
||||
# Note: Will removed in Sphinx-5.0 (RemovedInSphinx50Warning)
|
||||
old_node_id = self.make_old_id(modname)
|
||||
if node_id != old_node_id and old_node_id not in self.state.document.ids:
|
||||
target['ids'].append(old_node_id)
|
||||
|
||||
self.state.document.note_explicit_target(target)
|
||||
|
||||
domain.note_module(modname,
|
||||
node_id,
|
||||
self.options.get('synopsis', ''),
|
||||
self.options.get('platform', ''),
|
||||
'deprecated' in self.options)
|
||||
domain.note_object(modname, 'module', location=(self.env.docname, self.lineno))
|
||||
domain.note_object(modname, 'module', node_id, location=target)
|
||||
|
||||
targetnode = nodes.target('', '', ids=['module-' + modname],
|
||||
ismod=True)
|
||||
self.state.document.note_explicit_target(targetnode)
|
||||
# the platform and synopsis aren't printed; in fact, they are only
|
||||
# used in the modindex currently
|
||||
ret.append(targetnode)
|
||||
ret.append(target)
|
||||
indextext = _('%s (module)') % modname
|
||||
inode = addnodes.index(entries=[('single', indextext,
|
||||
'module-' + modname, '', None)])
|
||||
inode = addnodes.index(entries=[('single', indextext, node_id, '', None)])
|
||||
ret.append(inode)
|
||||
return ret
|
||||
|
||||
def make_old_id(self, name: str) -> str:
|
||||
"""Generate old styled node_id.
|
||||
|
||||
Old styled node_id is incompatible with docutils' node_id.
|
||||
It can contain dots and hyphens.
|
||||
|
||||
.. note:: Old styled node_id was mainly used until Sphinx-3.0.
|
||||
"""
|
||||
return 'module-%s' % name
|
||||
|
||||
|
||||
class PyCurrentModule(SphinxDirective):
|
||||
"""
|
||||
@@ -888,7 +913,7 @@ class PythonModuleIndex(Index):
|
||||
# sort out collapsable modules
|
||||
prev_modname = ''
|
||||
num_toplevels = 0
|
||||
for modname, (docname, synopsis, platforms, deprecated) in modules:
|
||||
for modname, (docname, node_id, synopsis, platforms, deprecated) in modules:
|
||||
if docnames and docname not in docnames:
|
||||
continue
|
||||
|
||||
@@ -925,8 +950,7 @@ class PythonModuleIndex(Index):
|
||||
|
||||
qualifier = _('Deprecated') if deprecated else ''
|
||||
entries.append(IndexEntry(stripped + modname, subtype, docname,
|
||||
'module-' + stripped + modname, platforms,
|
||||
qualifier, synopsis))
|
||||
node_id, platforms, qualifier, synopsis))
|
||||
prev_modname = modname
|
||||
|
||||
# apply heuristics when to collapse modindex at page load:
|
||||
@@ -990,10 +1014,10 @@ class PythonDomain(Domain):
|
||||
]
|
||||
|
||||
@property
|
||||
def objects(self) -> Dict[str, Tuple[str, str]]:
|
||||
return self.data.setdefault('objects', {}) # fullname -> docname, objtype
|
||||
def objects(self) -> Dict[str, Tuple[str, str, str]]:
|
||||
return self.data.setdefault('objects', {}) # fullname -> docname, node_id, objtype
|
||||
|
||||
def note_object(self, name: str, objtype: str, location: Any = None) -> None:
|
||||
def note_object(self, name: str, objtype: str, node_id: str, location: Any = None) -> None:
|
||||
"""Note a python object for cross reference.
|
||||
|
||||
.. versionadded:: 2.1
|
||||
@@ -1003,39 +1027,40 @@ class PythonDomain(Domain):
|
||||
logger.warning(__('duplicate object description of %s, '
|
||||
'other instance in %s, use :noindex: for one of them'),
|
||||
name, docname, location=location)
|
||||
self.objects[name] = (self.env.docname, objtype)
|
||||
self.objects[name] = (self.env.docname, node_id, objtype)
|
||||
|
||||
@property
|
||||
def modules(self) -> Dict[str, Tuple[str, str, str, bool]]:
|
||||
return self.data.setdefault('modules', {}) # modname -> docname, synopsis, platform, deprecated # NOQA
|
||||
def modules(self) -> Dict[str, Tuple[str, str, str, str, bool]]:
|
||||
return self.data.setdefault('modules', {}) # modname -> docname, node_id, synopsis, platform, deprecated # NOQA
|
||||
|
||||
def note_module(self, name: str, synopsis: str, platform: str, deprecated: bool) -> None:
|
||||
def note_module(self, name: str, node_id: str, synopsis: str,
|
||||
platform: str, deprecated: bool) -> None:
|
||||
"""Note a python module for cross reference.
|
||||
|
||||
.. versionadded:: 2.1
|
||||
"""
|
||||
self.modules[name] = (self.env.docname, synopsis, platform, deprecated)
|
||||
self.modules[name] = (self.env.docname, node_id, synopsis, platform, deprecated)
|
||||
|
||||
def clear_doc(self, docname: str) -> None:
|
||||
for fullname, (fn, _l) in list(self.objects.items()):
|
||||
for fullname, (fn, _x, _x) in list(self.objects.items()):
|
||||
if fn == docname:
|
||||
del self.objects[fullname]
|
||||
for modname, (fn, _x, _x, _y) in list(self.modules.items()):
|
||||
for modname, (fn, _x, _x, _x, _y) in list(self.modules.items()):
|
||||
if fn == docname:
|
||||
del self.modules[modname]
|
||||
|
||||
def merge_domaindata(self, docnames: List[str], otherdata: Dict) -> None:
|
||||
# XXX check duplicates?
|
||||
for fullname, (fn, objtype) in otherdata['objects'].items():
|
||||
for fullname, (fn, node_id, objtype) in otherdata['objects'].items():
|
||||
if fn in docnames:
|
||||
self.objects[fullname] = (fn, objtype)
|
||||
self.objects[fullname] = (fn, node_id, objtype)
|
||||
for modname, data in otherdata['modules'].items():
|
||||
if data[0] in docnames:
|
||||
self.modules[modname] = data
|
||||
|
||||
def find_obj(self, env: BuildEnvironment, modname: str, classname: str,
|
||||
name: str, type: str, searchmode: int = 0
|
||||
) -> List[Tuple[str, Tuple[str, str]]]:
|
||||
) -> List[Tuple[str, Tuple[str, str, str]]]:
|
||||
"""Find a Python object for "name", perhaps using the given module
|
||||
and/or classname. Returns a list of (name, object entry) tuples.
|
||||
"""
|
||||
@@ -1046,7 +1071,7 @@ class PythonDomain(Domain):
|
||||
if not name:
|
||||
return []
|
||||
|
||||
matches = [] # type: List[Tuple[str, Tuple[str, str]]]
|
||||
matches = [] # type: List[Tuple[str, Tuple[str, str, str]]]
|
||||
|
||||
newname = None
|
||||
if searchmode == 1:
|
||||
@@ -1057,20 +1082,20 @@ class PythonDomain(Domain):
|
||||
if objtypes is not None:
|
||||
if modname and classname:
|
||||
fullname = modname + '.' + classname + '.' + name
|
||||
if fullname in self.objects and self.objects[fullname][1] in objtypes:
|
||||
if fullname in self.objects and self.objects[fullname][2] in objtypes:
|
||||
newname = fullname
|
||||
if not newname:
|
||||
if modname and modname + '.' + name in self.objects and \
|
||||
self.objects[modname + '.' + name][1] in objtypes:
|
||||
self.objects[modname + '.' + name][2] in objtypes:
|
||||
newname = modname + '.' + name
|
||||
elif name in self.objects and self.objects[name][1] in objtypes:
|
||||
elif name in self.objects and self.objects[name][2] in objtypes:
|
||||
newname = name
|
||||
else:
|
||||
# "fuzzy" searching mode
|
||||
searchname = '.' + name
|
||||
matches = [(oname, self.objects[oname]) for oname in self.objects
|
||||
if oname.endswith(searchname) and
|
||||
self.objects[oname][1] in objtypes]
|
||||
self.objects[oname][2] in objtypes]
|
||||
else:
|
||||
# NOTE: searching for exact match, object type is not considered
|
||||
if name in self.objects:
|
||||
@@ -1118,10 +1143,10 @@ class PythonDomain(Domain):
|
||||
type='ref', subtype='python', location=node)
|
||||
name, obj = matches[0]
|
||||
|
||||
if obj[1] == 'module':
|
||||
if obj[2] == 'module':
|
||||
return self._make_module_refnode(builder, fromdocname, name, contnode)
|
||||
else:
|
||||
return make_refnode(builder, fromdocname, obj[0], name, contnode, name)
|
||||
return make_refnode(builder, fromdocname, obj[0], obj[1], contnode, name)
|
||||
|
||||
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
|
||||
target: str, node: pending_xref, contnode: Element
|
||||
@@ -1133,20 +1158,20 @@ class PythonDomain(Domain):
|
||||
# always search in "refspecific" mode with the :any: role
|
||||
matches = self.find_obj(env, modname, clsname, target, None, 1)
|
||||
for name, obj in matches:
|
||||
if obj[1] == 'module':
|
||||
if obj[2] == 'module':
|
||||
results.append(('py:mod',
|
||||
self._make_module_refnode(builder, fromdocname,
|
||||
name, contnode)))
|
||||
else:
|
||||
results.append(('py:' + self.role_for_objtype(obj[1]),
|
||||
make_refnode(builder, fromdocname, obj[0], name,
|
||||
results.append(('py:' + self.role_for_objtype(obj[2]),
|
||||
make_refnode(builder, fromdocname, obj[0], obj[1],
|
||||
contnode, name)))
|
||||
return results
|
||||
|
||||
def _make_module_refnode(self, builder: Builder, fromdocname: str, name: str,
|
||||
contnode: Node) -> Element:
|
||||
# get additional info for modules
|
||||
docname, synopsis, platform, deprecated = self.modules[name]
|
||||
docname, node_id, synopsis, platform, deprecated = self.modules[name]
|
||||
title = name
|
||||
if synopsis:
|
||||
title += ': ' + synopsis
|
||||
@@ -1154,15 +1179,14 @@ class PythonDomain(Domain):
|
||||
title += _(' (deprecated)')
|
||||
if platform:
|
||||
title += ' (' + platform + ')'
|
||||
return make_refnode(builder, fromdocname, docname,
|
||||
'module-' + name, contnode, title)
|
||||
return make_refnode(builder, fromdocname, docname, node_id, contnode, title)
|
||||
|
||||
def get_objects(self) -> Iterator[Tuple[str, str, str, str, str, int]]:
|
||||
for modname, info in self.modules.items():
|
||||
yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
|
||||
for refname, (docname, type) in self.objects.items():
|
||||
yield (modname, modname, 'module', info[0], info[1], 0)
|
||||
for refname, (docname, node_id, type) in self.objects.items():
|
||||
if type != 'module': # modules are already handled
|
||||
yield (refname, refname, type, docname, refname, 1)
|
||||
yield (refname, refname, type, docname, node_id, 1)
|
||||
|
||||
def get_full_qualified_name(self, node: Element) -> str:
|
||||
modname = node.get('py:module')
|
||||
@@ -1174,15 +1198,41 @@ class PythonDomain(Domain):
|
||||
return '.'.join(filter(None, [modname, clsname, target]))
|
||||
|
||||
|
||||
def builtin_resolver(app: Sphinx, env: BuildEnvironment,
|
||||
node: pending_xref, contnode: Element) -> Element:
|
||||
"""Do not emit nitpicky warnings for built-in types."""
|
||||
def istyping(s: str) -> bool:
|
||||
if s.startswith('typing.'):
|
||||
s = s.split('.', 1)[1]
|
||||
|
||||
return s in typing.__all__ # type: ignore
|
||||
|
||||
if node.get('refdomain') != 'py':
|
||||
return None
|
||||
elif node.get('reftype') == 'obj' and node.get('reftarget') == 'None':
|
||||
return contnode
|
||||
elif node.get('reftype') in ('class', 'exc'):
|
||||
reftarget = node.get('reftarget')
|
||||
if inspect.isclass(getattr(builtins, reftarget, None)):
|
||||
# built-in class
|
||||
return contnode
|
||||
elif istyping(reftarget):
|
||||
# typing class
|
||||
return contnode
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||
app.setup_extension('sphinx.directives')
|
||||
|
||||
app.add_domain(PythonDomain)
|
||||
app.connect('object-description-transform', filter_meta_fields)
|
||||
app.connect('missing-reference', builtin_resolver, priority=900)
|
||||
|
||||
return {
|
||||
'version': 'builtin',
|
||||
'env_version': 1,
|
||||
'env_version': 2,
|
||||
'parallel_read_safe': True,
|
||||
'parallel_write_safe': True,
|
||||
}
|
||||
|
||||
@@ -214,16 +214,18 @@ class Cmdoption(ObjectDescription):
|
||||
def add_target_and_index(self, firstname: str, sig: str, signode: desc_signature) -> None:
|
||||
currprogram = self.env.ref_context.get('std:program')
|
||||
for optname in signode.get('allnames', []):
|
||||
targetname = optname.replace('/', '-')
|
||||
if not targetname.startswith('-'):
|
||||
targetname = '-arg-' + targetname
|
||||
prefixes = ['cmdoption']
|
||||
if currprogram:
|
||||
targetname = '-' + currprogram + targetname
|
||||
targetname = 'cmdoption' + targetname
|
||||
signode['names'].append(targetname)
|
||||
prefixes.append(currprogram)
|
||||
if not optname.startswith(('-', '/')):
|
||||
prefixes.append('arg')
|
||||
prefix = '-'.join(prefixes)
|
||||
node_id = make_id(self.env, self.state.document, prefix, optname)
|
||||
signode['ids'].append(node_id)
|
||||
|
||||
self.state.document.note_explicit_target(signode)
|
||||
|
||||
domain = cast(StandardDomain, self.env.get_domain('std'))
|
||||
self.state.document.note_explicit_target(signode)
|
||||
for optname in signode.get('allnames', []):
|
||||
domain.add_program_option(currprogram, optname,
|
||||
self.env.docname, signode['ids'][0])
|
||||
@@ -487,28 +489,36 @@ class ProductionList(SphinxDirective):
|
||||
subnode = addnodes.production(rule)
|
||||
subnode['tokenname'] = name.strip()
|
||||
if subnode['tokenname']:
|
||||
# nodes.make_id converts '_' to '-',
|
||||
# so we can use '_' to delimit group from name,
|
||||
# and make sure we don't clash with other IDs.
|
||||
idname = 'grammar-token-%s_%s' \
|
||||
% (nodes.make_id(productionGroup), nodes.make_id(name))
|
||||
if idname not in self.state.document.ids:
|
||||
subnode['ids'].append(idname)
|
||||
prefix = 'grammar-token-%s' % productionGroup
|
||||
node_id = make_id(self.env, self.state.document, prefix, name)
|
||||
subnode['ids'].append(node_id)
|
||||
|
||||
# Assign old styled node_id not to break old hyperlinks (if possible)
|
||||
# Note: Will be removed in Sphinx-5.0 (RemovedInSphinx50Warning)
|
||||
old_node_id = self.make_old_id(name)
|
||||
if (old_node_id not in self.state.document.ids and
|
||||
old_node_id not in subnode['ids']):
|
||||
subnode['ids'].append(old_node_id)
|
||||
|
||||
idnameOld = nodes.make_id('grammar-token-' + name)
|
||||
if idnameOld not in self.state.document.ids:
|
||||
subnode['ids'].append(idnameOld)
|
||||
self.state.document.note_implicit_target(subnode, subnode)
|
||||
|
||||
if len(productionGroup) != 0:
|
||||
objName = "%s:%s" % (productionGroup, name)
|
||||
else:
|
||||
objName = name
|
||||
domain.note_object(objtype='token', name=objName, labelid=idname,
|
||||
location=node)
|
||||
domain.note_object('token', objName, node_id, location=node)
|
||||
subnode.extend(token_xrefs(tokens, productionGroup))
|
||||
node.append(subnode)
|
||||
return [node]
|
||||
|
||||
def make_old_id(self, token: str) -> str:
|
||||
"""Generate old styled node_id for tokens.
|
||||
|
||||
.. note:: Old Styled node_id was used until Sphinx-3.0.
|
||||
This will be removed in Sphinx-5.0.
|
||||
"""
|
||||
return nodes.make_id('grammar-token-' + token)
|
||||
|
||||
|
||||
class TokenXRefRole(XRefRole):
|
||||
def process_link(self, env: "BuildEnvironment", refnode: Element, has_explicit_title: bool,
|
||||
|
||||
@@ -1837,6 +1837,7 @@
|
||||
\protected\def\sphinxtitleref#1{\emph{#1}}
|
||||
\protected\def\sphinxmenuselection#1{\emph{#1}}
|
||||
\protected\def\sphinxguilabel#1{\emph{#1}}
|
||||
\protected\def\sphinxkeyboard#1{\sphinxcode{#1}}
|
||||
\protected\def\sphinxaccelerator#1{\underline{#1}}
|
||||
\protected\def\sphinxcrossref#1{\emph{#1}}
|
||||
\protected\def\sphinxtermref#1{\emph{#1}}
|
||||
|
||||
@@ -23,7 +23,9 @@ from docutils.nodes import Element, Node, Text
|
||||
|
||||
from sphinx import addnodes
|
||||
from sphinx import highlighting
|
||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||
from sphinx.deprecation import (
|
||||
RemovedInSphinx40Warning, RemovedInSphinx50Warning, deprecated_alias
|
||||
)
|
||||
from sphinx.domains import IndexEntry
|
||||
from sphinx.domains.std import StandardDomain
|
||||
from sphinx.errors import SphinxError
|
||||
@@ -43,17 +45,11 @@ except ImportError:
|
||||
if False:
|
||||
# For type annotation
|
||||
from sphinx.builders.latex import LaTeXBuilder
|
||||
from sphinx.builders.latex.theming import Theme
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SHORTHANDOFF = r'''
|
||||
\ifdefined\shorthandoff
|
||||
\ifnum\catcode`\=\string=\active\shorthandoff{=}\fi
|
||||
\ifnum\catcode`\"=\active\shorthandoff{"}\fi
|
||||
\fi
|
||||
'''
|
||||
|
||||
MAX_CITATION_LABEL_LENGTH = 8
|
||||
LATEXSECTIONNAMES = ["part", "chapter", "section", "subsection",
|
||||
"subsubsection", "paragraph", "subparagraph"]
|
||||
@@ -93,9 +89,16 @@ class LaTeXWriter(writers.Writer):
|
||||
def __init__(self, builder: "LaTeXBuilder") -> None:
|
||||
super().__init__()
|
||||
self.builder = builder
|
||||
self.theme = None # type: Theme
|
||||
|
||||
def translate(self) -> None:
|
||||
visitor = self.builder.create_translator(self.document, self.builder)
|
||||
try:
|
||||
visitor = self.builder.create_translator(self.document, self.builder, self.theme)
|
||||
except TypeError:
|
||||
warnings.warn('LaTeXTranslator now takes 3rd argument; "theme".',
|
||||
RemovedInSphinx50Warning)
|
||||
visitor = self.builder.create_translator(self.document, self.builder)
|
||||
|
||||
self.document.walkabout(visitor)
|
||||
self.output = cast(LaTeXTranslator, visitor).astext()
|
||||
|
||||
@@ -281,9 +284,15 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
# sphinx specific document classes
|
||||
docclasses = ('howto', 'manual')
|
||||
|
||||
def __init__(self, document: nodes.document, builder: "LaTeXBuilder") -> None:
|
||||
def __init__(self, document: nodes.document, builder: "LaTeXBuilder",
|
||||
theme: "Theme" = None) -> None:
|
||||
super().__init__(document, builder)
|
||||
self.body = [] # type: List[str]
|
||||
self.theme = theme
|
||||
|
||||
if theme is None:
|
||||
warnings.warn('LaTeXTranslator now takes 3rd argument; "theme".',
|
||||
RemovedInSphinx50Warning)
|
||||
|
||||
# flags
|
||||
self.in_title = 0
|
||||
@@ -306,21 +315,32 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
# sort out some elements
|
||||
self.elements = self.builder.context.copy()
|
||||
|
||||
# but some have other interface in config file
|
||||
self.elements['wrapperclass'] = self.format_docclass(document.get('docclass'))
|
||||
|
||||
# we assume LaTeX class provides \chapter command except in case
|
||||
# of non-Japanese 'howto' case
|
||||
# initial section names
|
||||
self.sectionnames = LATEXSECTIONNAMES[:]
|
||||
if document.get('docclass') == 'howto':
|
||||
docclass = self.config.latex_docclass.get('howto', 'article')
|
||||
if docclass[0] == 'j': # Japanese class...
|
||||
pass
|
||||
else:
|
||||
|
||||
if self.theme:
|
||||
# new style: control sectioning via theme's setting
|
||||
#
|
||||
# .. note:: template variables(elements) are already assigned in builder
|
||||
docclass = self.theme.docclass
|
||||
if self.theme.toplevel_sectioning == 'section':
|
||||
self.sectionnames.remove('chapter')
|
||||
else:
|
||||
docclass = self.config.latex_docclass.get('manual', 'report')
|
||||
self.elements['docclass'] = docclass
|
||||
# old style: sectioning control is hard-coded
|
||||
# but some have other interface in config file
|
||||
self.elements['wrapperclass'] = self.format_docclass(self.settings.docclass)
|
||||
|
||||
# we assume LaTeX class provides \chapter command except in case
|
||||
# of non-Japanese 'howto' case
|
||||
if document.get('docclass') == 'howto':
|
||||
docclass = self.config.latex_docclass.get('howto', 'article')
|
||||
if docclass[0] == 'j': # Japanese class...
|
||||
pass
|
||||
else:
|
||||
self.sectionnames.remove('chapter')
|
||||
else:
|
||||
docclass = self.config.latex_docclass.get('manual', 'report')
|
||||
self.elements['docclass'] = docclass
|
||||
|
||||
# determine top section level
|
||||
self.top_sectionlevel = 1
|
||||
@@ -368,44 +388,6 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
logger.warning(__('no Babel option known for language %r'),
|
||||
self.config.language)
|
||||
|
||||
# set up multilingual module...
|
||||
if self.elements['latex_engine'] == 'pdflatex':
|
||||
if not self.babel.uses_cyrillic():
|
||||
if 'X2' in self.elements['fontenc']:
|
||||
self.elements['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
self.elements['textcyrillic'] = ('\\usepackage[Xtwo]'
|
||||
'{sphinxcyrillic}')
|
||||
elif 'T2A' in self.elements['fontenc']:
|
||||
self.elements['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
self.elements['textcyrillic'] = ('\\usepackage[TtwoA]'
|
||||
'{sphinxcyrillic}')
|
||||
if 'LGR' in self.elements['fontenc']:
|
||||
self.elements['substitutefont'] = '\\usepackage{substitutefont}'
|
||||
else:
|
||||
self.elements['textgreek'] = ''
|
||||
# 'babel' key is public and user setting must be obeyed
|
||||
if self.elements['babel']:
|
||||
self.elements['classoptions'] += ',' + self.babel.get_language()
|
||||
# this branch is not taken for xelatex/lualatex if default settings
|
||||
self.elements['multilingual'] = self.elements['babel']
|
||||
if self.config.language:
|
||||
self.elements['shorthandoff'] = SHORTHANDOFF
|
||||
|
||||
# Times fonts don't work with Cyrillic languages
|
||||
if self.babel.uses_cyrillic() and 'fontpkg' not in self.config.latex_elements:
|
||||
self.elements['fontpkg'] = ''
|
||||
elif self.elements['polyglossia']:
|
||||
self.elements['classoptions'] += ',' + self.babel.get_language()
|
||||
options = self.babel.get_mainlanguage_options()
|
||||
if options:
|
||||
mainlanguage = r'\setmainlanguage[%s]{%s}' % (options,
|
||||
self.babel.get_language())
|
||||
else:
|
||||
mainlanguage = r'\setmainlanguage{%s}' % self.babel.get_language()
|
||||
|
||||
self.elements['multilingual'] = '%s\n%s' % (self.elements['polyglossia'],
|
||||
mainlanguage)
|
||||
|
||||
minsecnumdepth = self.secnumdepth # 2 from legacy sphinx manual/howto
|
||||
if self.document.get('tocdepth'):
|
||||
# reduce tocdepth if `part` or `chapter` is used for top_sectionlevel
|
||||
@@ -472,6 +454,8 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
def format_docclass(self, docclass: str) -> str:
|
||||
""" prepends prefix to sphinx document classes
|
||||
"""
|
||||
warnings.warn('LaTeXWriter.format_docclass() is deprecated.',
|
||||
RemovedInSphinx50Warning, stacklevel=2)
|
||||
if docclass in self.docclasses:
|
||||
docclass = 'sphinx' + docclass
|
||||
return docclass
|
||||
@@ -1720,6 +1704,8 @@ class LaTeXTranslator(SphinxTranslator):
|
||||
def visit_literal(self, node: Element) -> None:
|
||||
if self.in_title:
|
||||
self.body.append(r'\sphinxstyleliteralintitle{\sphinxupquote{')
|
||||
elif 'kbd' in node['classes']:
|
||||
self.body.append(r'\sphinxkeyboard{\sphinxupquote{')
|
||||
else:
|
||||
self.body.append(r'\sphinxcode{\sphinxupquote{')
|
||||
|
||||
@@ -2146,6 +2132,7 @@ deprecated_alias('sphinx.writers.latex',
|
||||
'DEFAULT_SETTINGS': constants.DEFAULT_SETTINGS,
|
||||
'LUALATEX_DEFAULT_FONTPKG': constants.LUALATEX_DEFAULT_FONTPKG,
|
||||
'PDFLATEX_DEFAULT_FONTPKG': constants.PDFLATEX_DEFAULT_FONTPKG,
|
||||
'SHORTHANDOFF': constants.SHORTHANDOFF,
|
||||
'XELATEX_DEFAULT_FONTPKG': constants.XELATEX_DEFAULT_FONTPKG,
|
||||
'XELATEX_GREEK_DEFAULT_FONTPKG': constants.XELATEX_GREEK_DEFAULT_FONTPKG,
|
||||
'ExtBabel': ExtBabel,
|
||||
|
||||
2
tests/roots/test-latex-theme/conf.py
Normal file
2
tests/roots/test-latex-theme/conf.py
Normal file
@@ -0,0 +1,2 @@
|
||||
latex_theme = 'custom'
|
||||
latex_theme_path = ['theme']
|
||||
2
tests/roots/test-latex-theme/index.rst
Normal file
2
tests/roots/test-latex-theme/index.rst
Normal file
@@ -0,0 +1,2 @@
|
||||
latex_theme
|
||||
===========
|
||||
4
tests/roots/test-latex-theme/theme/custom/theme.conf
Normal file
4
tests/roots/test-latex-theme/theme/custom/theme.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
[theme]
|
||||
docclass = book
|
||||
wrapperclass = sphinxbook
|
||||
toplevel_sectioning = chapter
|
||||
@@ -176,8 +176,8 @@ def test_html4_output(app, status, warning):
|
||||
r'-| |-'),
|
||||
],
|
||||
'autodoc.html': [
|
||||
(".//dl[@class='py class']/dt[@id='autodoc_target.Class']", ''),
|
||||
(".//dl[@class='py function']/dt[@id='autodoc_target.function']/em", r'\*\*kwds'),
|
||||
(".//dl[@class='py class']/dt[@id='autodoc-target-class']", ''),
|
||||
(".//dl[@class='py function']/dt[@id='autodoc-target-function']/em", r'\*\*kwds'),
|
||||
(".//dd/p", r'Return spam\.'),
|
||||
],
|
||||
'extapi.html': [
|
||||
@@ -222,7 +222,7 @@ def test_html4_output(app, status, warning):
|
||||
"[@class='reference internal']/code/span[@class='pre']", 'HOME'),
|
||||
(".//a[@href='#with']"
|
||||
"[@class='reference internal']/code/span[@class='pre']", '^with$'),
|
||||
(".//a[@href='#grammar-token-_try-stmt']"
|
||||
(".//a[@href='#grammar-token-try-stmt']"
|
||||
"[@class='reference internal']/code/span", '^statement$'),
|
||||
(".//a[@href='#some-label'][@class='reference internal']/span", '^here$'),
|
||||
(".//a[@href='#some-label'][@class='reference internal']/span", '^there$'),
|
||||
@@ -254,7 +254,7 @@ def test_html4_output(app, status, warning):
|
||||
(".//dl/dt[@id='term-boson']", 'boson'),
|
||||
# a production list
|
||||
(".//pre/strong", 'try_stmt'),
|
||||
(".//pre/a[@href='#grammar-token-_try1-stmt']/code/span", 'try1_stmt'),
|
||||
(".//pre/a[@href='#grammar-token-try1-stmt']/code/span", 'try1_stmt'),
|
||||
# tests for ``only`` directive
|
||||
(".//p", 'A global substitution.'),
|
||||
(".//p", 'In HTML.'),
|
||||
@@ -262,7 +262,7 @@ def test_html4_output(app, status, warning):
|
||||
(".//p", 'Always present'),
|
||||
# tests for ``any`` role
|
||||
(".//a[@href='#with']/span", 'headings'),
|
||||
(".//a[@href='objects.html#func_without_body']/code/span", 'objects'),
|
||||
(".//a[@href='objects.html#func-without-body']/code/span", 'objects'),
|
||||
# tests for numeric labels
|
||||
(".//a[@href='#id1'][@class='reference internal']/span", 'Testing various markup'),
|
||||
# tests for smartypants
|
||||
@@ -274,18 +274,18 @@ def test_html4_output(app, status, warning):
|
||||
(".//p", 'Il dit : « C’est “super” ! »'),
|
||||
],
|
||||
'objects.html': [
|
||||
(".//dt[@id='mod.Cls.meth1']", ''),
|
||||
(".//dt[@id='errmod.Error']", ''),
|
||||
(".//dt[@id='mod-cls-meth1']", ''),
|
||||
(".//dt[@id='errmod-error']", ''),
|
||||
(".//dt/code", r'long\(parameter,\s* list\)'),
|
||||
(".//dt/code", 'another one'),
|
||||
(".//a[@href='#mod.Cls'][@class='reference internal']", ''),
|
||||
(".//a[@href='#mod-cls'][@class='reference internal']", ''),
|
||||
(".//dl[@class='std userdesc']", ''),
|
||||
(".//dt[@id='userdesc-myobj']", ''),
|
||||
(".//a[@href='#userdesc-myobj'][@class='reference internal']", ''),
|
||||
# docfields
|
||||
(".//a[@class='reference internal'][@href='#TimeInt']/em", 'TimeInt'),
|
||||
(".//a[@class='reference internal'][@href='#Time']", 'Time'),
|
||||
(".//a[@class='reference internal'][@href='#errmod.Error']/strong", 'Error'),
|
||||
(".//a[@class='reference internal'][@href='#timeint']/em", 'TimeInt'),
|
||||
(".//a[@class='reference internal'][@href='#time']", 'Time'),
|
||||
(".//a[@class='reference internal'][@href='#errmod-error']/strong", 'Error'),
|
||||
# C references
|
||||
(".//span[@class='pre']", 'CFunction()'),
|
||||
(".//a[@href='#c.Sphinx_DoSomething']", ''),
|
||||
|
||||
@@ -20,7 +20,7 @@ from test_build_html import ENV_WARNINGS
|
||||
|
||||
from sphinx.builders.latex import default_latex_documents
|
||||
from sphinx.config import Config
|
||||
from sphinx.errors import SphinxError
|
||||
from sphinx.errors import SphinxError, ThemeError
|
||||
from sphinx.testing.util import strip_escseq
|
||||
from sphinx.util import docutils
|
||||
from sphinx.util.osutil import cd, ensuredir
|
||||
@@ -99,7 +99,7 @@ def skip_if_stylefiles_notfound(testfunc):
|
||||
def test_build_latex_doc(app, status, warning, engine, docclass):
|
||||
app.config.latex_engine = engine
|
||||
app.config.latex_documents = [app.config.latex_documents[0][:4] + (docclass,)]
|
||||
app.builder.init_context()
|
||||
app.builder.init()
|
||||
|
||||
LaTeXTranslator.ignore_missing_images = True
|
||||
app.builder.build_all()
|
||||
@@ -165,6 +165,65 @@ def test_latex_basic(app, status, warning):
|
||||
assert r'\renewcommand{\releasename}{}' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='basic',
|
||||
confoverrides={
|
||||
'latex_documents': [('index', 'test.tex', 'title', 'author', 'manual')]
|
||||
})
|
||||
def test_latex_basic_manual(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'test.tex').read_text(encoding='utf8')
|
||||
print(result)
|
||||
assert r'\def\sphinxdocclass{report}' in result
|
||||
assert r'\documentclass[letterpaper,10pt,english]{sphinxmanual}' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='basic',
|
||||
confoverrides={
|
||||
'latex_documents': [('index', 'test.tex', 'title', 'author', 'howto')]
|
||||
})
|
||||
def test_latex_basic_howto(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'test.tex').read_text(encoding='utf8')
|
||||
print(result)
|
||||
assert r'\def\sphinxdocclass{article}' in result
|
||||
assert r'\documentclass[letterpaper,10pt,english]{sphinxhowto}' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='basic',
|
||||
confoverrides={
|
||||
'language': 'ja',
|
||||
'latex_documents': [('index', 'test.tex', 'title', 'author', 'manual')]
|
||||
})
|
||||
def test_latex_basic_manual_ja(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'test.tex').read_text(encoding='utf8')
|
||||
print(result)
|
||||
assert r'\def\sphinxdocclass{jsbook}' in result
|
||||
assert r'\documentclass[letterpaper,10pt,dvipdfmx]{sphinxmanual}' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='basic',
|
||||
confoverrides={
|
||||
'language': 'ja',
|
||||
'latex_documents': [('index', 'test.tex', 'title', 'author', 'howto')]
|
||||
})
|
||||
def test_latex_basic_howto_ja(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'test.tex').read_text(encoding='utf8')
|
||||
print(result)
|
||||
assert r'\def\sphinxdocclass{jreport}' in result
|
||||
assert r'\documentclass[letterpaper,10pt,dvipdfmx]{sphinxhowto}' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='latex-theme')
|
||||
def test_latex_theme(app, status, warning):
|
||||
app.builder.build_all()
|
||||
result = (app.outdir / 'python.tex').read_text(encoding='utf8')
|
||||
print(result)
|
||||
assert r'\def\sphinxdocclass{book}' in result
|
||||
assert r'\documentclass[letterpaper,10pt,english]{sphinxbook}' in result
|
||||
|
||||
|
||||
@pytest.mark.sphinx('latex', testroot='basic', confoverrides={'language': 'zh'})
|
||||
def test_latex_additional_settings_for_language_code(app, status, warning):
|
||||
app.builder.build_all()
|
||||
@@ -1415,6 +1474,7 @@ def test_default_latex_documents():
|
||||
'author': "Wolfgang Schäuble & G'Beckstein."})
|
||||
config.init_values()
|
||||
config.add('latex_engine', None, True, None)
|
||||
config.add('latex_theme', 'manual', True, None)
|
||||
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
|
||||
r"Wolfgang Schäuble \& G\textquotesingle{}Beckstein.\@{}", 'manual')]
|
||||
assert default_latex_documents(config) == expected
|
||||
|
||||
@@ -145,24 +145,24 @@ def test_domain_py_objects(app, status, warning):
|
||||
assert 'module_b.submodule' in modules
|
||||
assert 'module_b.submodule' in objects
|
||||
|
||||
assert objects['module_a.submodule.ModTopLevel'] == ('module', 'class')
|
||||
assert objects['module_a.submodule.ModTopLevel.mod_child_1'] == ('module', 'method')
|
||||
assert objects['module_a.submodule.ModTopLevel.mod_child_2'] == ('module', 'method')
|
||||
assert objects['module_a.submodule.ModTopLevel'][2] == 'class'
|
||||
assert objects['module_a.submodule.ModTopLevel.mod_child_1'][2] == 'method'
|
||||
assert objects['module_a.submodule.ModTopLevel.mod_child_2'][2] == 'method'
|
||||
assert 'ModTopLevel.ModNoModule' not in objects
|
||||
assert objects['ModNoModule'] == ('module', 'class')
|
||||
assert objects['module_b.submodule.ModTopLevel'] == ('module', 'class')
|
||||
assert objects['ModNoModule'][2] == 'class'
|
||||
assert objects['module_b.submodule.ModTopLevel'][2] == 'class'
|
||||
|
||||
assert objects['TopLevel'] == ('roles', 'class')
|
||||
assert objects['top_level'] == ('roles', 'method')
|
||||
assert objects['NestedParentA'] == ('roles', 'class')
|
||||
assert objects['NestedParentA.child_1'] == ('roles', 'method')
|
||||
assert objects['NestedParentA.any_child'] == ('roles', 'method')
|
||||
assert objects['NestedParentA.NestedChildA'] == ('roles', 'class')
|
||||
assert objects['NestedParentA.NestedChildA.subchild_1'] == ('roles', 'method')
|
||||
assert objects['NestedParentA.NestedChildA.subchild_2'] == ('roles', 'method')
|
||||
assert objects['NestedParentA.child_2'] == ('roles', 'method')
|
||||
assert objects['NestedParentB'] == ('roles', 'class')
|
||||
assert objects['NestedParentB.child_1'] == ('roles', 'method')
|
||||
assert objects['TopLevel'][2] == 'class'
|
||||
assert objects['top_level'][2] == 'method'
|
||||
assert objects['NestedParentA'][2] == 'class'
|
||||
assert objects['NestedParentA.child_1'][2] == 'method'
|
||||
assert objects['NestedParentA.any_child'][2] == 'method'
|
||||
assert objects['NestedParentA.NestedChildA'][2] == 'class'
|
||||
assert objects['NestedParentA.NestedChildA.subchild_1'][2] == 'method'
|
||||
assert objects['NestedParentA.NestedChildA.subchild_2'][2] == 'method'
|
||||
assert objects['NestedParentA.child_2'][2] == 'method'
|
||||
assert objects['NestedParentB'][2] == 'class'
|
||||
assert objects['NestedParentB.child_1'][2] == 'method'
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='domain-py')
|
||||
@@ -170,11 +170,11 @@ def test_resolve_xref_for_properties(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
content = (app.outdir / 'module.html').read_text()
|
||||
assert ('Link to <a class="reference internal" href="#module_a.submodule.ModTopLevel.prop"'
|
||||
assert ('Link to <a class="reference internal" href="#module-a-submodule-modtoplevel-prop"'
|
||||
' title="module_a.submodule.ModTopLevel.prop">'
|
||||
'<code class="xref py py-attr docutils literal notranslate"><span class="pre">'
|
||||
'prop</span> <span class="pre">attribute</span></code></a>' in content)
|
||||
assert ('Link to <a class="reference internal" href="#module_a.submodule.ModTopLevel.prop"'
|
||||
assert ('Link to <a class="reference internal" href="#module-a-submodule-modtoplevel-prop"'
|
||||
' title="module_a.submodule.ModTopLevel.prop">'
|
||||
'<code class="xref py py-meth docutils literal notranslate"><span class="pre">'
|
||||
'prop</span> <span class="pre">method</span></code></a>' in content)
|
||||
@@ -191,17 +191,20 @@ def test_domain_py_find_obj(app, status, warning):
|
||||
|
||||
assert (find_obj(None, None, 'NONEXISTANT', 'class') == [])
|
||||
assert (find_obj(None, None, 'NestedParentA', 'class') ==
|
||||
[('NestedParentA', ('roles', 'class'))])
|
||||
[('NestedParentA', ('roles', 'nestedparenta', 'class'))])
|
||||
assert (find_obj(None, None, 'NestedParentA.NestedChildA', 'class') ==
|
||||
[('NestedParentA.NestedChildA', ('roles', 'class'))])
|
||||
[('NestedParentA.NestedChildA', ('roles', 'nestedparenta-nestedchilda', 'class'))])
|
||||
assert (find_obj(None, 'NestedParentA', 'NestedChildA', 'class') ==
|
||||
[('NestedParentA.NestedChildA', ('roles', 'class'))])
|
||||
[('NestedParentA.NestedChildA', ('roles', 'nestedparenta-nestedchilda', 'class'))])
|
||||
assert (find_obj(None, None, 'NestedParentA.NestedChildA.subchild_1', 'meth') ==
|
||||
[('NestedParentA.NestedChildA.subchild_1', ('roles', 'method'))])
|
||||
[('NestedParentA.NestedChildA.subchild_1',
|
||||
('roles', 'nestedparenta-nestedchilda-subchild-1', 'method'))])
|
||||
assert (find_obj(None, 'NestedParentA', 'NestedChildA.subchild_1', 'meth') ==
|
||||
[('NestedParentA.NestedChildA.subchild_1', ('roles', 'method'))])
|
||||
[('NestedParentA.NestedChildA.subchild_1',
|
||||
('roles', 'nestedparenta-nestedchilda-subchild-1', 'method'))])
|
||||
assert (find_obj(None, 'NestedParentA.NestedChildA', 'subchild_1', 'meth') ==
|
||||
[('NestedParentA.NestedChildA.subchild_1', ('roles', 'method'))])
|
||||
[('NestedParentA.NestedChildA.subchild_1',
|
||||
('roles', 'nestedparenta-nestedchilda-subchild-1', 'method'))])
|
||||
|
||||
|
||||
def test_get_full_qualified_name():
|
||||
@@ -402,7 +405,7 @@ def test_pydata(app):
|
||||
[desc, ([desc_signature, desc_name, "var"],
|
||||
[desc_content, ()])]))
|
||||
assert 'var' in domain.objects
|
||||
assert domain.objects['var'] == ('index', 'data')
|
||||
assert domain.objects['var'] == ('index', 'var', 'data')
|
||||
|
||||
|
||||
def test_pyfunction(app):
|
||||
@@ -421,9 +424,9 @@ def test_pyfunction(app):
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()])]))
|
||||
assert 'func1' in domain.objects
|
||||
assert domain.objects['func1'] == ('index', 'function')
|
||||
assert domain.objects['func1'] == ('index', 'func1', 'function')
|
||||
assert 'func2' in domain.objects
|
||||
assert domain.objects['func2'] == ('index', 'function')
|
||||
assert domain.objects['func2'] == ('index', 'func2', 'function')
|
||||
|
||||
|
||||
def test_pymethod_options(app):
|
||||
@@ -460,61 +463,61 @@ def test_pymethod_options(app):
|
||||
|
||||
# method
|
||||
assert_node(doctree[1][1][0], addnodes.index,
|
||||
entries=[('single', 'meth1() (Class method)', 'Class.meth1', '', None)])
|
||||
entries=[('single', 'meth1() (Class method)', 'class-meth1', '', None)])
|
||||
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "meth1"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth1' in domain.objects
|
||||
assert domain.objects['Class.meth1'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth1'] == ('index', 'class-meth1', 'method')
|
||||
|
||||
# :classmethod:
|
||||
assert_node(doctree[1][1][2], addnodes.index,
|
||||
entries=[('single', 'meth2() (Class class method)', 'Class.meth2', '', None)])
|
||||
entries=[('single', 'meth2() (Class class method)', 'class-meth2', '', None)])
|
||||
assert_node(doctree[1][1][3], ([desc_signature, ([desc_annotation, "classmethod "],
|
||||
[desc_name, "meth2"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth2' in domain.objects
|
||||
assert domain.objects['Class.meth2'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth2'] == ('index', 'class-meth2', 'method')
|
||||
|
||||
# :staticmethod:
|
||||
assert_node(doctree[1][1][4], addnodes.index,
|
||||
entries=[('single', 'meth3() (Class static method)', 'Class.meth3', '', None)])
|
||||
entries=[('single', 'meth3() (Class static method)', 'class-meth3', '', None)])
|
||||
assert_node(doctree[1][1][5], ([desc_signature, ([desc_annotation, "static "],
|
||||
[desc_name, "meth3"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth3' in domain.objects
|
||||
assert domain.objects['Class.meth3'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth3'] == ('index', 'class-meth3', 'method')
|
||||
|
||||
# :async:
|
||||
assert_node(doctree[1][1][6], addnodes.index,
|
||||
entries=[('single', 'meth4() (Class method)', 'Class.meth4', '', None)])
|
||||
entries=[('single', 'meth4() (Class method)', 'class-meth4', '', None)])
|
||||
assert_node(doctree[1][1][7], ([desc_signature, ([desc_annotation, "async "],
|
||||
[desc_name, "meth4"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth4' in domain.objects
|
||||
assert domain.objects['Class.meth4'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth4'] == ('index', 'class-meth4', 'method')
|
||||
|
||||
# :property:
|
||||
assert_node(doctree[1][1][8], addnodes.index,
|
||||
entries=[('single', 'meth5() (Class property)', 'Class.meth5', '', None)])
|
||||
entries=[('single', 'meth5() (Class property)', 'class-meth5', '', None)])
|
||||
assert_node(doctree[1][1][9], ([desc_signature, ([desc_annotation, "property "],
|
||||
[desc_name, "meth5"])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth5' in domain.objects
|
||||
assert domain.objects['Class.meth5'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth5'] == ('index', 'class-meth5', 'method')
|
||||
|
||||
# :abstractmethod:
|
||||
assert_node(doctree[1][1][10], addnodes.index,
|
||||
entries=[('single', 'meth6() (Class method)', 'Class.meth6', '', None)])
|
||||
entries=[('single', 'meth6() (Class method)', 'class-meth6', '', None)])
|
||||
assert_node(doctree[1][1][11], ([desc_signature, ([desc_annotation, "abstract "],
|
||||
[desc_name, "meth6"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth6' in domain.objects
|
||||
assert domain.objects['Class.meth6'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth6'] == ('index', 'class-meth6', 'method')
|
||||
|
||||
|
||||
def test_pyclassmethod(app):
|
||||
@@ -529,13 +532,13 @@ def test_pyclassmethod(app):
|
||||
[desc_content, (addnodes.index,
|
||||
desc)])]))
|
||||
assert_node(doctree[1][1][0], addnodes.index,
|
||||
entries=[('single', 'meth() (Class class method)', 'Class.meth', '', None)])
|
||||
entries=[('single', 'meth() (Class class method)', 'class-meth', '', None)])
|
||||
assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "classmethod "],
|
||||
[desc_name, "meth"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth' in domain.objects
|
||||
assert domain.objects['Class.meth'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth'] == ('index', 'class-meth', 'method')
|
||||
|
||||
|
||||
def test_pystaticmethod(app):
|
||||
@@ -550,13 +553,13 @@ def test_pystaticmethod(app):
|
||||
[desc_content, (addnodes.index,
|
||||
desc)])]))
|
||||
assert_node(doctree[1][1][0], addnodes.index,
|
||||
entries=[('single', 'meth() (Class static method)', 'Class.meth', '', None)])
|
||||
entries=[('single', 'meth() (Class static method)', 'class-meth', '', None)])
|
||||
assert_node(doctree[1][1][1], ([desc_signature, ([desc_annotation, "static "],
|
||||
[desc_name, "meth"],
|
||||
[desc_parameterlist, ()])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.meth' in domain.objects
|
||||
assert domain.objects['Class.meth'] == ('index', 'method')
|
||||
assert domain.objects['Class.meth'] == ('index', 'class-meth', 'method')
|
||||
|
||||
|
||||
def test_pyattribute(app):
|
||||
@@ -573,13 +576,13 @@ def test_pyattribute(app):
|
||||
[desc_content, (addnodes.index,
|
||||
desc)])]))
|
||||
assert_node(doctree[1][1][0], addnodes.index,
|
||||
entries=[('single', 'attr (Class attribute)', 'Class.attr', '', None)])
|
||||
entries=[('single', 'attr (Class attribute)', 'class-attr', '', None)])
|
||||
assert_node(doctree[1][1][1], ([desc_signature, ([desc_name, "attr"],
|
||||
[desc_annotation, ": str"],
|
||||
[desc_annotation, " = ''"])],
|
||||
[desc_content, ()]))
|
||||
assert 'Class.attr' in domain.objects
|
||||
assert domain.objects['Class.attr'] == ('index', 'attribute')
|
||||
assert domain.objects['Class.attr'] == ('index', 'class-attr', 'attribute')
|
||||
|
||||
|
||||
@pytest.mark.sphinx(freshenv=True)
|
||||
@@ -595,10 +598,10 @@ def test_module_index(app):
|
||||
assert index.generate() == (
|
||||
[('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]),
|
||||
('s', [IndexEntry('sphinx', 1, 'index', 'module-sphinx', '', '', ''),
|
||||
IndexEntry('sphinx.builders', 2, 'index', 'module-sphinx.builders', '', '', ''), # NOQA
|
||||
IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx.builders.html', '', '', ''), # NOQA
|
||||
IndexEntry('sphinx.config', 2, 'index', 'module-sphinx.config', '', '', ''),
|
||||
IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx_intl', '', '', '')])],
|
||||
IndexEntry('sphinx.builders', 2, 'index', 'module-sphinx-builders', '', '', ''), # NOQA
|
||||
IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx-builders-html', '', '', ''), # NOQA
|
||||
IndexEntry('sphinx.config', 2, 'index', 'module-sphinx-config', '', '', ''),
|
||||
IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx-intl', '', '', '')])],
|
||||
False
|
||||
)
|
||||
|
||||
@@ -610,7 +613,7 @@ def test_module_index_submodule(app):
|
||||
index = PythonModuleIndex(app.env.get_domain('py'))
|
||||
assert index.generate() == (
|
||||
[('s', [IndexEntry('sphinx', 1, '', '', '', '', ''),
|
||||
IndexEntry('sphinx.config', 2, 'index', 'module-sphinx.config', '', '', '')])],
|
||||
IndexEntry('sphinx.config', 2, 'index', 'module-sphinx-config', '', '', '')])],
|
||||
False
|
||||
)
|
||||
|
||||
@@ -639,12 +642,12 @@ def test_modindex_common_prefix(app):
|
||||
restructuredtext.parse(app, text)
|
||||
index = PythonModuleIndex(app.env.get_domain('py'))
|
||||
assert index.generate() == (
|
||||
[('b', [IndexEntry('sphinx.builders', 1, 'index', 'module-sphinx.builders', '', '', ''), # NOQA
|
||||
IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx.builders.html', '', '', '')]), # NOQA
|
||||
('c', [IndexEntry('sphinx.config', 0, 'index', 'module-sphinx.config', '', '', '')]),
|
||||
[('b', [IndexEntry('sphinx.builders', 1, 'index', 'module-sphinx-builders', '', '', ''), # NOQA
|
||||
IndexEntry('sphinx.builders.html', 2, 'index', 'module-sphinx-builders-html', '', '', '')]), # NOQA
|
||||
('c', [IndexEntry('sphinx.config', 0, 'index', 'module-sphinx-config', '', '', '')]),
|
||||
('d', [IndexEntry('docutils', 0, 'index', 'module-docutils', '', '', '')]),
|
||||
('s', [IndexEntry('sphinx', 0, 'index', 'module-sphinx', '', '', ''),
|
||||
IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx_intl', '', '', '')])],
|
||||
IndexEntry('sphinx_intl', 0, 'index', 'module-sphinx-intl', '', '', '')])],
|
||||
True
|
||||
)
|
||||
|
||||
|
||||
@@ -352,23 +352,23 @@ def test_productionlist(app, status, warning):
|
||||
linkText = span.text.strip()
|
||||
cases.append((text, link, linkText))
|
||||
assert cases == [
|
||||
('A', 'Bare.html#grammar-token-_a', 'A'),
|
||||
('B', 'Bare.html#grammar-token-_b', 'B'),
|
||||
('P1:A', 'P1.html#grammar-token-p1_a', 'P1:A'),
|
||||
('P1:B', 'P1.html#grammar-token-p1_b', 'P1:B'),
|
||||
('P2:A', 'P1.html#grammar-token-p1_a', 'P1:A'),
|
||||
('P2:B', 'P2.html#grammar-token-p2_b', 'P2:B'),
|
||||
('Explicit title A, plain', 'Bare.html#grammar-token-_a', 'MyTitle'),
|
||||
('Explicit title A, colon', 'Bare.html#grammar-token-_a', 'My:Title'),
|
||||
('Explicit title P1:A, plain', 'P1.html#grammar-token-p1_a', 'MyTitle'),
|
||||
('Explicit title P1:A, colon', 'P1.html#grammar-token-p1_a', 'My:Title'),
|
||||
('Tilde A', 'Bare.html#grammar-token-_a', 'A'),
|
||||
('Tilde P1:A', 'P1.html#grammar-token-p1_a', 'A'),
|
||||
('Tilde explicit title P1:A', 'P1.html#grammar-token-p1_a', '~MyTitle'),
|
||||
('Tilde, explicit title P1:A', 'P1.html#grammar-token-p1_a', 'MyTitle'),
|
||||
('Dup', 'Dup2.html#grammar-token-_dup', 'Dup'),
|
||||
('FirstLine', 'firstLineRule.html#grammar-token-_firstline', 'FirstLine'),
|
||||
('SecondLine', 'firstLineRule.html#grammar-token-_secondline', 'SecondLine'),
|
||||
('A', 'Bare.html#grammar-token-a', 'A'),
|
||||
('B', 'Bare.html#grammar-token-b', 'B'),
|
||||
('P1:A', 'P1.html#grammar-token-p1-a', 'P1:A'),
|
||||
('P1:B', 'P1.html#grammar-token-p1-b', 'P1:B'),
|
||||
('P2:A', 'P1.html#grammar-token-p1-a', 'P1:A'),
|
||||
('P2:B', 'P2.html#grammar-token-p2-b', 'P2:B'),
|
||||
('Explicit title A, plain', 'Bare.html#grammar-token-a', 'MyTitle'),
|
||||
('Explicit title A, colon', 'Bare.html#grammar-token-a', 'My:Title'),
|
||||
('Explicit title P1:A, plain', 'P1.html#grammar-token-p1-a', 'MyTitle'),
|
||||
('Explicit title P1:A, colon', 'P1.html#grammar-token-p1-a', 'My:Title'),
|
||||
('Tilde A', 'Bare.html#grammar-token-a', 'A'),
|
||||
('Tilde P1:A', 'P1.html#grammar-token-p1-a', 'A'),
|
||||
('Tilde explicit title P1:A', 'P1.html#grammar-token-p1-a', '~MyTitle'),
|
||||
('Tilde, explicit title P1:A', 'P1.html#grammar-token-p1-a', 'MyTitle'),
|
||||
('Dup', 'Dup2.html#grammar-token-dup', 'Dup'),
|
||||
('FirstLine', 'firstLineRule.html#grammar-token-firstline', 'FirstLine'),
|
||||
('SecondLine', 'firstLineRule.html#grammar-token-secondline', 'SecondLine'),
|
||||
]
|
||||
|
||||
text = (app.outdir / 'LineContinuation.html').read_text()
|
||||
|
||||
@@ -84,7 +84,7 @@ def test_object_inventory(app):
|
||||
refs = app.env.domaindata['py']['objects']
|
||||
|
||||
assert 'func_without_module' in refs
|
||||
assert refs['func_without_module'] == ('objects', 'function')
|
||||
assert refs['func_without_module'] == ('objects', 'func-without-module', 'function')
|
||||
assert 'func_without_module2' in refs
|
||||
assert 'mod.func_in_module' in refs
|
||||
assert 'mod.Cls' in refs
|
||||
@@ -99,7 +99,7 @@ def test_object_inventory(app):
|
||||
assert 'func_noindex' not in refs
|
||||
|
||||
assert app.env.domaindata['py']['modules']['mod'] == \
|
||||
('objects', 'Module synopsis.', 'UNIX', False)
|
||||
('objects', 'module-mod', 'Module synopsis.', 'UNIX', False)
|
||||
|
||||
assert app.env.domains['py'].data is app.env.domaindata['py']
|
||||
assert app.env.domains['c'].data is app.env.domaindata['c']
|
||||
|
||||
@@ -870,7 +870,7 @@ def test_xml_refs_in_python_domain(app):
|
||||
assert_elem(
|
||||
para0[0],
|
||||
['SEE THIS DECORATOR:', 'sensitive_variables()', '.'],
|
||||
['sensitive.sensitive_variables'])
|
||||
['sensitive-sensitive-variables'])
|
||||
|
||||
|
||||
@sphinx_intl
|
||||
|
||||
@@ -230,6 +230,13 @@ def get_verifier(verify, verify_re):
|
||||
'<p><span class="guilabel">Foo</span></p>',
|
||||
r'\sphinxguilabel{Foo}',
|
||||
),
|
||||
(
|
||||
# kbd role
|
||||
'verify',
|
||||
':kbd:`space`',
|
||||
'<p><kbd class="kbd docutils literal notranslate">space</kbd></p>',
|
||||
'\\sphinxkeyboard{\\sphinxupquote{space}}',
|
||||
),
|
||||
(
|
||||
# non-interpolation of dashes in option role
|
||||
'verify_re',
|
||||
|
||||
Reference in New Issue
Block a user