Merge branch '3.x'

This commit is contained in:
Takeshi KOMIYA
2021-01-16 21:51:46 +09:00
36 changed files with 596 additions and 119 deletions

8
.readthedocs.yml Normal file
View File

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

13
CHANGES
View File

@@ -70,6 +70,7 @@ Deprecated
----------
* ``sphinx.ext.autodoc.AttributeDocumenter.isinstanceattribute()``
* ``sphinx.ext.autodoc.directive.DocumenterBridge.reporter``
* ``sphinx.ext.autodoc.importer.get_module_members()``
Features added
@@ -87,7 +88,11 @@ Features added
* #8649: imgconverter: Skip availability check if builder supports the image
type
* #6241: mathjax: Include mathjax.js only on the document using equations
* #8651: std domain: cross-reference for a rubric having inline item is broken
* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright`
* #207: Now :confval:`highlight_language` supports multiple languages
* #2030: :rst:dir:`code-block` and :rst:dir:`literalinclude` supports automatic
dedent via no-argument ``:dedent:`` option
Bugs fixed
----------
@@ -97,13 +102,21 @@ Bugs fixed
* #8592: autodoc: ``:meta public:`` does not effect to variables
* #8594: autodoc: empty __all__ attribute is ignored
* #8315: autodoc: Failed to resolve struct.Struct type annotation
* #8652: autodoc: All variable comments in the module are ignored if the module
contains invalid type comments
* #8306: autosummary: mocked modules are documented as empty page when using
:recursive: option
* #8618: html: kbd role produces incorrect HTML when compound-key separators (-,
+ or ^) are used as keystrokes
* #8629: html: A type warning for html_use_opensearch is shown twice
* #8665: html theme: Could not override globaltoc_maxdepth in theme.conf
* #8094: texinfo: image files on the different directory with document are not
copied
* #8671: :confval:`highlight_options` is not working
* #8341: C, fix intersphinx lookup types for names in declarations.
* C, C++: in general fix intersphinx and role lookup types.
* #8683: :confval:`html_last_updated_fmt` does not support UTC offset (%z)
* #8683: :confval:`html_last_updated_fmt` generates wrong time zone for %Z
Testing
--------

View File

@@ -107,6 +107,11 @@ The following is a list of deprecated interfaces.
- 5.0
- ``sphinx.ext.autodoc.DataDocumenter``
* - ``sphinx.ext.autodoc.directive.DocumenterBridge.reporter``
- 3.5
- 5.0
- ``sphinx.util.logging``
* - ``sphinx.ext.autodoc.importer._getannotations()``
- 3.4
- 4.0

View File

@@ -581,12 +581,27 @@ General configuration
.. confval:: highlight_options
A dictionary of options that modify how the lexer specified by
:confval:`highlight_language` generates highlighted source code. These are
lexer-specific; for the options understood by each, see the
`Pygments documentation <https://pygments.org/docs/lexers>`_.
A dictionary that maps language names to options for the lexer modules of
Pygments. These are lexer-specific; for the options understood by each,
see the `Pygments documentation <https://pygments.org/docs/lexers>`_.
Example::
highlight_options = {
'default': {'stripall': True},
'php': {'startinline': True},
}
A single dictionary of options are also allowed. Then it is recognized
as options to the lexer specified by :confval:`highlight_language`::
# configuration for the ``highlight_language``
highlight_options = {'stripall': True}
.. versionadded:: 1.3
.. versionchanged:: 3.5
Allow to configure highlight options for multiple languages
.. confval:: pygments_style
@@ -944,8 +959,11 @@ that use Sphinx's HTMLWriter class.
.. confval:: html_baseurl
The URL which points to the root of the HTML documentation. It is used to
indicate the location of document like ``canonical_url``.
The base URL which points to the root of the HTML documentation. It is used
to indicate the location of document using `The Canonical Link Relation`_.
Default: ``''``.
.. _The Canonical Link Relation: https://tools.ietf.org/html/rfc6596
.. versionadded:: 1.8

View File

@@ -157,7 +157,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
``:meta private:`` in its :ref:`info-field-lists`.
For example:
.. code-block:: rst
.. code-block:: python
def my_function(my_arg, my_other_arg):
"""blah blah blah
@@ -172,7 +172,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
an underscore.
For example:
.. code-block:: rst
.. code-block:: python
def _my_function(my_arg, my_other_arg):
"""blah blah blah
@@ -186,7 +186,7 @@ inserting them into the page source under a suitable :rst:dir:`py:module`,
docstring contains ``:meta hide-value:`` in its :ref:`info-field-lists`.
Example:
.. code-block:: rst
.. code-block:: python
var1 = None #: :meta hide-value:

View File

@@ -572,9 +572,11 @@ __ http://pygments.org/docs/lexers
.. versionadded:: 1.3
.. rst:directive:option:: dedent: number
:type: number
:type: number or no value
Strip indentation characters from the code block. For example::
Strip indentation characters from the code block. When number given,
leading N characters are removed. When no argument given, leading spaces
are removed via :func:`textwrap.dedent()`. For example::
.. code-block:: ruby
:dedent: 4
@@ -582,6 +584,8 @@ __ http://pygments.org/docs/lexers
some ruby code
.. versionadded:: 1.3
.. versionchanged:: 3.5
Support automatic dedent.
.. rst:directive:option:: force
:type: no value
@@ -742,6 +746,9 @@ __ http://pygments.org/docs/lexers
.. versionchanged:: 2.1
Added the ``force`` option.
.. versionchanged:: 3.5
Support automatic dedent.
.. _glossary-directive:
Glossary

View File

@@ -362,6 +362,18 @@ def convert_source_suffix(app: "Sphinx", config: Config) -> None:
"But `%r' is given." % source_suffix))
def convert_highlight_options(app: "Sphinx", config: Config) -> None:
"""Convert old styled highlight_options to new styled one.
* old style: options
* new style: dict that maps language names to options
"""
options = config.highlight_options
if options and not all(isinstance(v, dict) for v in options.values()):
# old styled option detected because all values are not dictionary.
config.highlight_options = {config.highlight_language: options} # type: ignore
def init_numfig_format(app: "Sphinx", config: Config) -> None:
"""Initialize :confval:`numfig_format`."""
numfig_format = {'section': _('Section %s'),
@@ -466,6 +478,7 @@ def check_master_doc(app: "Sphinx", env: "BuildEnvironment", added: Set[str],
def setup(app: "Sphinx") -> Dict[str, Any]:
app.connect('config-inited', convert_source_suffix, priority=800)
app.connect('config-inited', convert_highlight_options, priority=800)
app.connect('config-inited', init_numfig_format, priority=800)
app.connect('config-inited', correct_copyright_year, priority=800)
app.connect('config-inited', check_confval_types, priority=800)

View File

@@ -7,6 +7,7 @@
"""
import sys
import textwrap
from difflib import unified_diff
from typing import TYPE_CHECKING, Any, Dict, List, Tuple
@@ -17,6 +18,7 @@ from docutils.statemachine import StringList
from sphinx import addnodes
from sphinx.config import Config
from sphinx.directives import optional_int
from sphinx.locale import __
from sphinx.util import logging, parselinenos
from sphinx.util.docutils import SphinxDirective
@@ -55,7 +57,7 @@ class Highlight(SphinxDirective):
def dedent_lines(lines: List[str], dedent: int, location: Tuple[str, int] = None) -> List[str]:
if not dedent:
return lines
return textwrap.dedent(''.join(lines)).splitlines(True)
if any(s[:dedent].strip() for s in lines):
logger.warning(__('non-whitespace stripped by dedent'), location=location)
@@ -104,7 +106,7 @@ class CodeBlock(SphinxDirective):
option_spec = {
'force': directives.flag,
'linenos': directives.flag,
'dedent': int,
'dedent': optional_int,
'lineno-start': int,
'emphasize-lines': directives.unchanged_required,
'caption': directives.unchanged_required,
@@ -378,7 +380,7 @@ class LiteralInclude(SphinxDirective):
optional_arguments = 0
final_argument_whitespace = True
option_spec = {
'dedent': int,
'dedent': optional_int,
'linenos': directives.flag,
'lineno-start': int,
'lineno-match': directives.flag,

View File

@@ -3657,15 +3657,18 @@ class CDomain(Domain):
name = 'c'
label = 'C'
object_types = {
'function': ObjType(_('function'), 'func'),
'member': ObjType(_('member'), 'member'),
'macro': ObjType(_('macro'), 'macro'),
'type': ObjType(_('type'), 'type'),
'var': ObjType(_('variable'), 'data'),
'enum': ObjType(_('enum'), 'enum'),
'enumerator': ObjType(_('enumerator'), 'enumerator'),
'struct': ObjType(_('struct'), 'struct'),
'union': ObjType(_('union'), 'union'),
# 'identifier' is the one used for xrefs generated in signatures, not in roles
'member': ObjType(_('member'), 'var', 'member', 'data', 'identifier'),
'var': ObjType(_('variable'), 'var', 'member', 'data', 'identifier'),
'function': ObjType(_('function'), 'func', 'identifier', 'type'),
'macro': ObjType(_('macro'), 'macro', 'identifier'),
'struct': ObjType(_('struct'), 'struct', 'identifier', 'type'),
'union': ObjType(_('union'), 'union', 'identifier', 'type'),
'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
'type': ObjType(_('type'), 'identifier', 'type'),
# generated object types
'functionParam': ObjType(_('function parameter'), 'identifier', 'var', 'member', 'data'), # noqa
}
directives = {

View File

@@ -7251,14 +7251,18 @@ class CPPDomain(Domain):
name = 'cpp'
label = 'C++'
object_types = {
'class': ObjType(_('class'), 'class', 'type', 'identifier'),
'union': ObjType(_('union'), 'union', 'type', 'identifier'),
'function': ObjType(_('function'), 'function', 'func', 'type', 'identifier'),
'member': ObjType(_('member'), 'member', 'var'),
'type': ObjType(_('type'), 'type', 'identifier'),
'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'),
'union': ObjType(_('union'), 'union', 'identifier', 'type'),
'function': ObjType(_('function'), 'func', 'identifier', 'type'),
'member': ObjType(_('member'), 'member', 'var', 'identifier'),
'type': ObjType(_('type'), 'identifier', 'type'),
'concept': ObjType(_('concept'), 'concept', 'identifier'),
'enum': ObjType(_('enum'), 'enum', 'type', 'identifier'),
'enumerator': ObjType(_('enumerator'), 'enumerator')
'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
# generated object types
'functionParam': ObjType(_('function parameter'), 'identifier', 'member', 'var'), # noqa
'templateParam': ObjType(_('template parameter'),
'identifier', 'class', 'struct', 'union', 'member', 'var', 'type'), # noqa
}
directives = {
@@ -7435,30 +7439,19 @@ class CPPDomain(Domain):
if typ.startswith('cpp:'):
typ = typ[4:]
origTyp = typ
if typ == 'func':
typ = 'function'
if typ == 'struct':
typ = 'class'
declTyp = s.declaration.objectType
def checkType() -> bool:
if typ == 'any' or typ == 'identifier':
return True
if declTyp == 'templateParam':
# TODO: perhaps this should be strengthened one day
return True
if declTyp == 'functionParam':
if typ == 'var' or typ == 'member':
if typ == 'any':
return True
objtypes = self.objtypes_for_role(typ)
if objtypes:
return declTyp in objtypes
print("Type is %s (originally: %s), declType is %s" % (typ, origTyp, declTyp))
print("Type is %s, declaration type is %s" % (typ, declTyp))
assert False
if not checkType():
logger.warning("cpp:%s targets a %s (%s).",
origTyp, s.declaration.objectType,
typ, s.declaration.objectType,
s.get_full_nested_name(),
location=node)
@@ -7488,10 +7481,10 @@ class CPPDomain(Domain):
if env.config.add_function_parentheses and typ == 'any':
addParen += 1
# and now this stuff for operator()
if (env.config.add_function_parentheses and typ == 'function' and
if (env.config.add_function_parentheses and typ == 'func' and
title.endswith('operator()')):
addParen += 1
if ((typ == 'any' or typ == 'function') and
if ((typ == 'any' or typ == 'func') and
title.endswith('operator') and
displayName.endswith('operator()')):
addParen += 1
@@ -7500,7 +7493,7 @@ class CPPDomain(Domain):
if env.config.add_function_parentheses:
if typ == 'any' and displayName.endswith('()'):
addParen += 1
elif typ == 'function':
elif typ == 'func':
if title.endswith('()') and not displayName.endswith('()'):
title = title[:-2]
else:

View File

@@ -730,9 +730,11 @@ class StandardDomain(Domain):
name, env.doc2path(self.labels[name][0]),
location=node)
self.anonlabels[name] = docname, labelid
if node.tagname in ('section', 'rubric'):
if node.tagname == 'section':
title = cast(nodes.title, node[0])
sectname = clean_astext(title)
elif node.tagname == 'rubric':
sectname = clean_astext(node)
elif self.is_enumerable_node(node):
sectname = self.get_numfig_title(node)
if not sectname:

View File

@@ -319,8 +319,10 @@ class TocTree:
toctrees = [] # type: List[Element]
if 'includehidden' not in kwargs:
kwargs['includehidden'] = True
if 'maxdepth' not in kwargs:
if 'maxdepth' not in kwargs or not kwargs['maxdepth']:
kwargs['maxdepth'] = 0
else:
kwargs['maxdepth'] = int(kwargs['maxdepth'])
kwargs['collapse'] = collapse
for toctreenode in doctree.traverse(addnodes.toctree):
toctree = self.resolve(docname, builder, toctreenode, prune=True, **kwargs)

View File

@@ -6,6 +6,7 @@
:license: BSD, see LICENSE for details.
"""
import warnings
from typing import Any, Callable, Dict, List, Set, Type
from docutils import nodes
@@ -15,6 +16,7 @@ from docutils.statemachine import StringList
from docutils.utils import Reporter, assemble_option_dict
from sphinx.config import Config
from sphinx.deprecation import RemovedInSphinx50Warning
from sphinx.environment import BuildEnvironment
from sphinx.ext.autodoc import Documenter, Options
from sphinx.util import logging
@@ -48,7 +50,7 @@ class DocumenterBridge:
def __init__(self, env: BuildEnvironment, reporter: Reporter, options: Options,
lineno: int, state: Any) -> None:
self.env = env
self.reporter = reporter
self._reporter = reporter
self.genopt = options
self.lineno = lineno
self.filename_set = set() # type: Set[str]
@@ -58,6 +60,12 @@ class DocumenterBridge:
def warn(self, msg: str) -> None:
logger.warning(msg, location=(self.env.docname, self.lineno))
@property
def reporter(self) -> Reporter:
warnings.warn('DocumenterBridge.reporter is deprecated.',
RemovedInSphinx50Warning, stacklevel=2)
return self._reporter
def process_documenter_options(documenter: "Type[Documenter]", config: Config, options: Dict
) -> Options:

View File

@@ -52,6 +52,10 @@ def parse(code: str, mode: str = 'exec') -> "ast.AST":
try:
# type_comments parameter is available on py38+
return ast.parse(code, mode=mode, type_comments=True) # type: ignore
except SyntaxError:
# Some syntax error found. To ignore invalid type comments, retry parsing without
# type_comments parameter (refs: https://github.com/sphinx-doc/sphinx/issues/8652).
return ast.parse(code, mode=mode)
except TypeError:
# fallback to ast module.
# typed_ast is used to parse type_comments if installed.

View File

@@ -161,7 +161,9 @@ date_format_mappings = {
'%X': 'medium', # Locales appropriate time representation.
'%y': 'YY', # Year without century as a zero-padded decimal number.
'%Y': 'yyyy', # Year with century as a decimal number.
'%Z': 'zzzz', # Time zone name (no characters if no time zone exists).
'%Z': 'zzz', # Time zone name (no characters if no time zone exists).
'%z': 'ZZZ', # UTC offset in the form ±HHMM[SS[.ffffff]]
# (empty string if the object is naive).
'%%': '%',
}

View File

@@ -305,7 +305,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
if figure_id in self.builder.fignumbers.get(key, {}):
self.body.append('<span class="caption-number">')
prefix = self.builder.config.numfig_format.get(figtype)
prefix = self.config.numfig_format.get(figtype)
if prefix is None:
msg = __('numfig_format is not defined for %s') % figtype
logger.warning(msg)
@@ -429,14 +429,10 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator):
linenos = node.get('linenos', False)
highlight_args = node.get('highlight_args', {})
highlight_args['force'] = node.get('force', False)
if lang is self.builder.config.highlight_language:
# only pass highlighter options for original language
opts = self.builder.config.highlight_options
else:
opts = {}
opts = self.config.highlight_options.get(lang, {})
if linenos and self.builder.config.html_codeblock_linenos_style:
linenos = self.builder.config.html_codeblock_linenos_style
if linenos and self.config.html_codeblock_linenos_style:
linenos = self.config.html_codeblock_linenos_style
highlighted = self.highlighter.highlight_block(
node.rawsource, lang, opts=opts, linenos=linenos,

View File

@@ -278,7 +278,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
if figure_id in self.builder.fignumbers.get(key, {}):
self.body.append('<span class="caption-number">')
prefix = self.builder.config.numfig_format.get(figtype)
prefix = self.config.numfig_format.get(figtype)
if prefix is None:
msg = __('numfig_format is not defined for %s') % figtype
logger.warning(msg)
@@ -382,14 +382,10 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
linenos = node.get('linenos', False)
highlight_args = node.get('highlight_args', {})
highlight_args['force'] = node.get('force', False)
if lang is self.builder.config.highlight_language:
# only pass highlighter options for original language
opts = self.builder.config.highlight_options
else:
opts = {}
opts = self.config.highlight_options.get(lang, {})
if linenos and self.builder.config.html_codeblock_linenos_style:
linenos = self.builder.config.html_codeblock_linenos_style
if linenos and self.config.html_codeblock_linenos_style:
linenos = self.config.html_codeblock_linenos_style
highlighted = self.highlighter.highlight_block(
node.rawsource, lang, opts=opts, linenos=linenos,

View File

@@ -521,7 +521,7 @@ class LaTeXTranslator(SphinxTranslator):
ret = []
# latex_domain_indices can be False/True or a list of index names
indices_config = self.builder.config.latex_domain_indices
indices_config = self.config.latex_domain_indices
if indices_config:
for domain in self.builder.env.domains.values():
for indexcls in domain.indices:
@@ -541,7 +541,7 @@ class LaTeXTranslator(SphinxTranslator):
def render(self, template_name: str, variables: Dict) -> str:
renderer = LaTeXRenderer(latex_engine=self.config.latex_engine)
for template_dir in self.builder.config.templates_path:
for template_dir in self.config.templates_path:
template = path.join(self.builder.confdir, template_dir,
template_name)
if path.exists(template):
@@ -961,7 +961,7 @@ class LaTeXTranslator(SphinxTranslator):
cell = self.table.cell()
context = ''
if cell.width > 1:
if self.builder.config.latex_use_latex_multicolumn:
if self.config.latex_use_latex_multicolumn:
if self.table.col == 0:
self.body.append('\\multicolumn{%d}{|l|}{%%\n' % cell.width)
else:
@@ -1541,7 +1541,7 @@ class LaTeXTranslator(SphinxTranslator):
id = self.curfilestack[-1] + ':' + uri[1:]
self.body.append(self.hyperlink(id))
self.body.append(r'\emph{')
if self.builder.config.latex_show_pagerefs and not \
if self.config.latex_show_pagerefs and not \
self.in_production_list:
self.context.append('}}} (%s)' % self.hyperpageref(id))
else:
@@ -1565,8 +1565,7 @@ class LaTeXTranslator(SphinxTranslator):
self.body.append(r'\sphinxtermref{')
else:
self.body.append(r'\sphinxcrossref{')
if self.builder.config.latex_show_pagerefs and not \
self.in_production_list:
if self.config.latex_show_pagerefs and not self.in_production_list:
self.context.append('}}} (%s)' % self.hyperpageref(id))
else:
self.context.append('}}}')
@@ -1750,11 +1749,7 @@ class LaTeXTranslator(SphinxTranslator):
linenos = node.get('linenos', False)
highlight_args = node.get('highlight_args', {})
highlight_args['force'] = node.get('force', False)
if lang is self.builder.config.highlight_language:
# only pass highlighter options for original language
opts = self.builder.config.highlight_options
else:
opts = {}
opts = self.config.highlight_options.get(lang, {})
hlcode = self.highlighter.highlight_block(
node.rawsource, lang, opts=opts, linenos=linenos,
@@ -2016,12 +2011,12 @@ class LaTeXTranslator(SphinxTranslator):
else:
from sphinx.util.math import wrap_displaymath
self.body.append(wrap_displaymath(node.astext(), label,
self.builder.config.math_number_all))
self.config.math_number_all))
raise nodes.SkipNode
def visit_math_reference(self, node: Element) -> None:
label = "equation:%s:%s" % (node['docname'], node['target'])
eqref_format = self.builder.config.math_eqref_format
eqref_format = self.config.math_eqref_format
if eqref_format:
try:
ref = r'\ref{%s}' % label

View File

@@ -287,8 +287,7 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator):
if uri.startswith('mailto:') or uri.startswith('http:') or \
uri.startswith('https:') or uri.startswith('ftp:'):
# if configured, put the URL after the link
if self.builder.config.man_show_urls and \
node.astext() != uri:
if self.config.man_show_urls and node.astext() != uri:
if uri.startswith('mailto:'):
uri = uri[7:]
self.body.extend([

View File

@@ -232,12 +232,12 @@ class TexinfoTranslator(SphinxTranslator):
'author': self.settings.author,
# if empty, use basename of input file
'filename': self.settings.texinfo_filename,
'release': self.escape(self.builder.config.release),
'project': self.escape(self.builder.config.project),
'copyright': self.escape(self.builder.config.copyright),
'date': self.escape(self.builder.config.today or
format_date(self.builder.config.today_fmt or _('%b %d, %Y'),
language=self.builder.config.language))
'release': self.escape(self.config.release),
'project': self.escape(self.config.project),
'copyright': self.escape(self.config.copyright),
'date': self.escape(self.config.today or
format_date(self.config.today_fmt or _('%b %d, %Y'),
language=self.config.language))
})
# title
title = self.settings.title # type: str
@@ -433,7 +433,7 @@ class TexinfoTranslator(SphinxTranslator):
self.add_menu_entries(entries)
if (node_name != 'Top' or
not self.node_menus[entries[0]] or
self.builder.config.texinfo_no_detailmenu):
self.config.texinfo_no_detailmenu):
self.body.append('\n@end menu\n')
return
@@ -483,7 +483,7 @@ class TexinfoTranslator(SphinxTranslator):
ret.append('@end menu\n')
return ''.join(ret)
indices_config = self.builder.config.texinfo_domain_indices
indices_config = self.config.texinfo_domain_indices
if indices_config:
for domain in self.builder.env.domains.values():
for indexcls in domain.indices:
@@ -738,7 +738,7 @@ class TexinfoTranslator(SphinxTranslator):
else:
uri = self.escape_arg(uri)
name = self.escape_arg(name)
show_urls = self.builder.config.texinfo_show_urls
show_urls = self.config.texinfo_show_urls
if self.in_footnote:
show_urls = 'inline'
if not name or uri == name:
@@ -1394,9 +1394,8 @@ class TexinfoTranslator(SphinxTranslator):
# use the full name of the objtype for the category
try:
domain = self.builder.env.get_domain(node.parent['domain'])
primary = self.builder.config.primary_domain
name = domain.get_type_name(domain.object_types[objtype],
primary == domain.name)
self.config.primary_domain == domain.name)
except (KeyError, ExtensionError):
name = objtype
# by convention, the deffn category should be capitalized like a title

View File

@@ -0,0 +1,4 @@
exclude_patterns = ['_build']
extensions = [
'sphinx.ext.intersphinx',
]

View File

@@ -0,0 +1,62 @@
.. c:member:: void __member = _member
- :any:`_member`
- :c:member:`_member`
- :c:var:`_member`
- :c:data:`_member`
.. c:member:: void __var = _var
- :any:`_var`
- :c:member:`_var`
- :c:var:`_var`
- :c:data:`_var`
.. c:member:: void __function = _function
- :any:`_function`
- :c:func:`_function`
- :c:type:`_function`
.. c:member:: void __macro = _macro
- :any:`_macro`
- :c:macro:`_macro`
.. c:type:: _struct __struct
struct _struct __structTagged
- :any:`_struct`
- :c:struct:`_struct`
- :c:type:`_struct`
.. c:type:: _union __union
union _union __unionTagged
- :any:`_union`
- :c:union:`_union`
- :c:type:`_union`
.. c:type:: _enum __enum
enum _enum __enumTagged
- :any:`_enum`
- :c:enum:`_enum`
- :c:type:`_enum`
.. c:member:: void __enumerator = _enumerator
- :any:`_enumerator`
- :c:enumerator:`_enumerator`
.. c:type:: _type __type
- :any:`_type`
- :c:type:`_type`
.. c:member:: void __functionParam = _functionParam.param
- :any:`_functionParam.param`
- :c:member:`_functionParam.param`
- :c:var:`_functionParam.param`
- :c:data:`_functionParam.param`

View File

@@ -0,0 +1,4 @@
exclude_patterns = ['_build']
extensions = [
'sphinx.ext.intersphinx',
]

View File

@@ -0,0 +1,112 @@
.. cpp:type:: _class __class
- :any:`_class`
- :cpp:any:`_class`
- :cpp:class:`_class`
- :cpp:struct:`_class`
- :cpp:type:`_class`
.. cpp:type:: _struct __struct
- :any:`_struct`
- :cpp:any:`_struct`
- :cpp:class:`_struct`
- :cpp:struct:`_struct`
- :cpp:type:`_struct`
.. cpp:type:: _union __union
- :any:`_union`
- :cpp:any:`_union`
- :cpp:union:`_union`
- :cpp:type:`_union`
.. cpp:member:: void __function = _function
- :any:`_function`
- :cpp:any:`_function`
- :cpp:func:`_function`
- :cpp:type:`_function`
.. cpp:member:: void __member = _member
- :any:`_member`
- :cpp:any:`_member`
- :cpp:member:`_member`
- :cpp:var:`_member`
.. cpp:member:: void __var = _var
- :any:`_var`
- :cpp:any:`_var`
- :cpp:member:`_var`
- :cpp:var:`_var`
.. cpp:type:: _type __type
- :any:`_type`
- :cpp:any:`_type`
- :cpp:type:`_type`
.. cpp:function:: template<_concept T> void __concept()
- :any:`_concept`
- :cpp:any:`_concept`
- :cpp:concept:`_concept`
.. cpp:type:: _enum __enum
- :any:`_enum`
- :cpp:any:`_enum`
- :cpp:enum:`_enum`
- :cpp:type:`_enum`
.. cpp:type:: _enumStruct __enumStruct
- :any:`_enumStruct`
- :cpp:any:`_enumStruct`
- :cpp:enum:`_enumStruct`
- :cpp:type:`_enumStruct`
.. cpp:type:: _enumClass __enumClass
- :any:`_enumClass`
- :cpp:any:`_enumClass`
- :cpp:enum:`_enumClass`
- :cpp:type:`_enumClass`
.. cpp:member:: void __enumerator = _enumerator
- :any:`_enumerator`
- :cpp:any:`_enumerator`
- :cpp:enumerator:`_enumerator`
.. cpp:member:: void __scopedEnumerator = _enumStruct::_scopedEnumerator
- :any:`_enumStruct::_scopedEnumerator`
- :cpp:any:`_enumStruct::_scopedEnumerator`
- :cpp:enumerator:`_enumStruct::_scopedEnumerator`
.. cpp:member:: void __enumerator2 = _enum::_enumerator
- :any:`_enum::_enumerator`
- :cpp:any:`_enum::_enumerator`
- :cpp:enumerator:`_enum::_enumerator`
.. cpp:member:: void __functionParam = _functionParam::param
- :any:`_functionParam::param`
- :cpp:any:`_functionParam::param`
- :cpp:member:`_functionParam::param`
- :cpp:var:`_functionParam::param`
.. cpp:type:: _templateParam::TParam __templateParam
- :any:`_templateParam::TParam`
- :cpp:any:`_templateParam::TParam`
- :cpp:type:`_templateParam::TParam`
- :cpp:member:`_templateParam::TParam`
- :cpp:var:`_templateParam::TParam`
- :cpp:class:`_templateParam::TParam`
- :cpp:struct:`_templateParam::TParam`
- :cpp:union:`_templateParam::TParam`

View File

@@ -123,37 +123,37 @@
:class:`TParamType`
:struct:`TParamType`
:union:`TParamType`
:func:`TParamType`
function
:member:`TParamType`
:var:`TParamType`
:type:`TParamType`
:concept:`TParamType`
:enum:`TParamType`
:enumerator:`TParamType`
concept
enum
enumerator
:cpp:any:`TParamVar`
:class:`TParamVar`
:struct:`TParamVar`
:union:`TParamVar`
:func:`TParamVar`
function
:member:`TParamVar`
:var:`TParamVar`
:type:`TParamVar`
:concept:`TParamVar`
:enum:`TParamVar`
:enumerator:`TParamVar`
concept
enum
enumerator
:cpp:any:`TParamTemplate`
:class:`TParamTemplate`
:struct:`TParamTemplate`
:union:`TParamTemplate`
:func:`TParamTemplate`
function
:member:`TParamTemplate`
:var:`TParamTemplate`
:type:`TParamTemplate`
:concept:`TParamTemplate`
:enum:`TParamTemplate`
:enumerator:`TParamTemplate`
concept
enum
enumerator
.. function:: void FunctionParams(int FunctionParam)

View File

@@ -114,35 +114,35 @@
class
struct
union
func
:func:`TParamType`
member
var
type
concept
enum
enumerator
:concept:`TParamType`
:enum:`TParamType`
:enumerator:`TParamType`
class
struct
union
func
:func:`TParamVar`
member
var
type
concept
enum
enumerator
:concept:`TParamVar`
:enum:`TParamVar`
:enumerator:`TParamVar`
class
struct
union
func
:func:`TParamTemplate`
member
var
type
concept
enum
enumerator
:concept:`TParamTemplate`
:enum:`TParamTemplate`
:enumerator:`TParamTemplate`
.. function:: void FunctionParams(int FunctionParam)

View File

@@ -0,0 +1,10 @@
abbrev
======
.. currentmodule:: module_a.submodule
* normal: :py:meth:`module_a.submodule.ModTopLevel.mod_child_1`
* relative: :py:meth:`.ModTopLevel.mod_child_1`
* short name: :py:meth:`~module_a.submodule.ModTopLevel.mod_child_1`
* relative + short name: :py:meth:`~.ModTopLevel.mod_child_1`
* short name + relative: :py:meth:`~.ModTopLevel.mod_child_1`

View File

@@ -0,0 +1,4 @@
highlight_options = {
'default': {'default_option': True},
'python': {'python_option': True}
}

View File

@@ -0,0 +1,14 @@
test-highlight_options
======================
.. code-block::
blah blah blah
.. code-block:: python
blah blah blah
.. code-block:: java
blah blah blah

View File

@@ -12,6 +12,7 @@ import os
import re
from distutils.version import LooseVersion
from itertools import chain, cycle
from unittest.mock import ANY, call, patch
import pygments
import pytest
@@ -1607,3 +1608,36 @@ def test_html_codeblock_linenos_style_inline(app):
assert '<span class="linenos">1</span>' in content
else:
assert '<span class="lineno">1 </span>' in content
@pytest.mark.sphinx('html', testroot='highlight_options')
def test_highlight_options(app):
subject = app.builder.highlighter
with patch.object(subject, 'highlight_block', wraps=subject.highlight_block) as highlight:
app.build()
call_args = highlight.call_args_list
assert len(call_args) == 3
assert call_args[0] == call(ANY, 'default', force=False, linenos=False,
location=ANY, opts={'default_option': True})
assert call_args[1] == call(ANY, 'python', force=False, linenos=False,
location=ANY, opts={'python_option': True})
assert call_args[2] == call(ANY, 'java', force=False, linenos=False,
location=ANY, opts={})
@pytest.mark.sphinx('html', testroot='highlight_options',
confoverrides={'highlight_options': {'default_option': True}})
def test_highlight_options_old(app):
subject = app.builder.highlighter
with patch.object(subject, 'highlight_block', wraps=subject.highlight_block) as highlight:
app.build()
call_args = highlight.call_args_list
assert len(call_args) == 3
assert call_args[0] == call(ANY, 'default', force=False, linenos=False,
location=ANY, opts={'default_option': True})
assert call_args[1] == call(ANY, 'python', force=False, linenos=False,
location=ANY, opts={})
assert call_args[2] == call(ANY, 'java', force=False, linenos=False,
location=ANY, opts={})

View File

@@ -250,6 +250,14 @@ def test_LiteralIncludeReader_dedent(literal_inc_path):
" pass\n"
"\n")
# dedent: None
options = {'lines': '9-11', 'dedent': None}
reader = LiteralIncludeReader(literal_inc_path, options, DUMMY_CONFIG)
content, lines = reader.read()
assert content == ("def baz():\n"
" pass\n"
"\n")
@pytest.mark.xfail(os.name != 'posix', reason="Not working on windows")
def test_LiteralIncludeReader_tabwidth(testroot):

View File

@@ -7,6 +7,8 @@
:copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import zlib
from xml.etree import ElementTree
import pytest
@@ -14,6 +16,7 @@ import pytest
from sphinx import addnodes
from sphinx.addnodes import desc
from sphinx.domains.c import DefinitionError, DefinitionParser, Symbol, _id_prefix, _max_id
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.testing import restructuredtext
from sphinx.testing.util import assert_node
@@ -642,3 +645,52 @@ def test_noindexentry(app):
assert_node(doctree, (addnodes.index, desc, addnodes.index, desc))
assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C function)', 'c.f', '', None)])
assert_node(doctree[2], addnodes.index, entries=[])
@pytest.mark.sphinx(testroot='domain-c-intersphinx', confoverrides={'nitpicky': True})
def test_intersphinx(tempdir, app, status, warning):
origSource = """\
.. c:member:: int _member
.. c:var:: int _var
.. c:function:: void _function()
.. c:macro:: _macro
.. c:struct:: _struct
.. c:union:: _union
.. c:enum:: _enum
.. c:enumerator:: _enumerator
.. c:type:: _type
.. c:function:: void _functionParam(int param)
""" # noqa
inv_file = tempdir / 'inventory'
inv_file.write_bytes(b'''\
# Sphinx inventory version 2
# Project: C Intersphinx Test
# Version:
# The remainder of this file is compressed using zlib.
''' + zlib.compress(b'''\
_enum c:enum 1 index.html#c.$ -
_enum._enumerator c:enumerator 1 index.html#c.$ -
_enumerator c:enumerator 1 index.html#c._enum.$ -
_function c:function 1 index.html#c.$ -
_functionParam c:function 1 index.html#c.$ -
_functionParam.param c:functionParam 1 index.html#c._functionParam -
_macro c:macro 1 index.html#c.$ -
_member c:member 1 index.html#c.$ -
_struct c:struct 1 index.html#c.$ -
_type c:type 1 index.html#c.$ -
_union c:union 1 index.html#c.$ -
_var c:member 1 index.html#c.$ -
''')) # noqa
app.config.intersphinx_mapping = {
'https://localhost/intersphinx/c/': inv_file,
}
app.config.intersphinx_cache_limit = 0
# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
load_mappings(app)
app.builder.build_all()
ws = filter_warnings(warning, "index")
assert len(ws) == 0

View File

@@ -9,6 +9,7 @@
"""
import re
import zlib
import pytest
@@ -17,6 +18,7 @@ from sphinx import addnodes
from sphinx.addnodes import desc
from sphinx.domains.cpp import (DefinitionError, DefinitionParser, NoOldIdError, Symbol,
_id_prefix, _max_id)
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.testing import restructuredtext
from sphinx.testing.util import assert_node
@@ -1048,8 +1050,8 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning):
('concept', ['concept']),
('enum', ['type', 'enum']),
('enumerator', ['enumerator']),
('tParam', ['class', 'struct', 'union', 'func', 'member', 'var', 'type', 'concept', 'enum', 'enumerator', 'functionParam']),
('functionParam', ['member', 'var']),
('templateParam', ['class', 'struct', 'union', 'member', 'var', 'type']),
]
warn = []
for targetType, roles in ok:
@@ -1057,6 +1059,9 @@ def test_build_domain_cpp_misuse_of_roles(app, status, warning):
for r in allRoles:
if r not in roles:
warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType))
if targetType == 'templateParam':
warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType))
warn.append("WARNING: cpp:{} targets a {} (".format(r, txtTargetType))
warn = list(sorted(warn))
for w in ws:
assert "targets a" in w
@@ -1245,3 +1250,66 @@ def test_mix_decl_duplicate(app, warning):
assert "index.rst:3: WARNING: Duplicate C++ declaration, also defined at index:1." in ws[2]
assert "Declaration is '.. cpp:struct:: A'." in ws[3]
assert ws[4] == ""
@pytest.mark.sphinx(testroot='domain-cpp-intersphinx', confoverrides={'nitpicky': True})
def test_intersphinx(tempdir, app, status, warning):
origSource = """\
.. cpp:class:: _class
.. cpp:struct:: _struct
.. cpp:union:: _union
.. cpp:function:: void _function()
.. cpp:member:: int _member
.. cpp:var:: int _var
.. cpp:type:: _type
.. cpp:concept:: template<typename T> _concept
.. cpp:enum:: _enum
.. cpp:enumerator:: _enumerator
.. cpp:enum-struct:: _enumStruct
.. cpp:enumerator:: _scopedEnumerator
.. cpp:enum-class:: _enumClass
.. cpp:function:: void _functionParam(int param)
.. cpp:function:: template<typename TParam> void _templateParam()
""" # noqa
inv_file = tempdir / 'inventory'
inv_file.write_bytes(b'''\
# Sphinx inventory version 2
# Project: C Intersphinx Test
# Version:
# The remainder of this file is compressed using zlib.
''' + zlib.compress(b'''\
_class cpp:class 1 index.html#_CPPv46$ -
_concept cpp:concept 1 index.html#_CPPv4I0E8$ -
_concept::T cpp:templateParam 1 index.html#_CPPv4I0E8_concept -
_enum cpp:enum 1 index.html#_CPPv45$ -
_enum::_enumerator cpp:enumerator 1 index.html#_CPPv4N5_enum11_enumeratorE -
_enumClass cpp:enum 1 index.html#_CPPv410$ -
_enumStruct cpp:enum 1 index.html#_CPPv411$ -
_enumStruct::_scopedEnumerator cpp:enumerator 1 index.html#_CPPv4N11_enumStruct17_scopedEnumeratorE -
_enumerator cpp:enumerator 1 index.html#_CPPv4N5_enum11_enumeratorE -
_function cpp:function 1 index.html#_CPPv49_functionv -
_functionParam cpp:function 1 index.html#_CPPv414_functionParami -
_functionParam::param cpp:functionParam 1 index.html#_CPPv414_functionParami -
_member cpp:member 1 index.html#_CPPv47$ -
_struct cpp:class 1 index.html#_CPPv47$ -
_templateParam cpp:function 1 index.html#_CPPv4I0E14_templateParamvv -
_templateParam::TParam cpp:templateParam 1 index.html#_CPPv4I0E14_templateParamvv -
_type cpp:type 1 index.html#_CPPv45$ -
_union cpp:union 1 index.html#_CPPv46$ -
_var cpp:member 1 index.html#_CPPv44$ -
''')) # noqa
app.config.intersphinx_mapping = {
'https://localhost/intersphinx/cpp/': inv_file,
}
app.config.intersphinx_cache_limit = 0
# load the inventory and check if it's done correctly
normalize_intersphinx_mapping(app, app.config)
load_mappings(app)
app.builder.build_all()
ws = filter_warnings(warning, "index")
assert len(ws) == 0

View File

@@ -8,6 +8,7 @@
:license: BSD, see LICENSE for details.
"""
import re
import sys
from unittest.mock import Mock
@@ -132,6 +133,29 @@ def test_domain_py_xrefs(app, status, warning):
assert len(refnodes) == 2
@pytest.mark.sphinx('html', testroot='domain-py')
def test_domain_py_xrefs_abbreviations(app, status, warning):
app.builder.build_all()
content = (app.outdir / 'abbr.html').read_text()
assert re.search(r'normal: <a .* href="module.html#module_a.submodule.ModTopLevel.'
r'mod_child_1" .*><.*>module_a.submodule.ModTopLevel.mod_child_1\(\)'
r'<.*></a>',
content)
assert re.search(r'relative: <a .* href="module.html#module_a.submodule.ModTopLevel.'
r'mod_child_1" .*><.*>ModTopLevel.mod_child_1\(\)<.*></a>',
content)
assert re.search(r'short name: <a .* href="module.html#module_a.submodule.ModTopLevel.'
r'mod_child_1" .*><.*>mod_child_1\(\)<.*></a>',
content)
assert re.search(r'relative \+ short name: <a .* href="module.html#module_a.submodule.'
r'ModTopLevel.mod_child_1" .*><.*>mod_child_1\(\)<.*></a>',
content)
assert re.search(r'short name \+ relative: <a .* href="module.html#module_a.submodule.'
r'ModTopLevel.mod_child_1" .*><.*>mod_child_1\(\)<.*></a>',
content)
@pytest.mark.sphinx('dummy', testroot='domain-py')
def test_domain_py_objects(app, status, warning):
app.builder.build_all()

View File

@@ -409,3 +409,13 @@ def test_disabled_docref(app):
assert_node(doctree, ([nodes.paragraph, ([pending_xref, nodes.inline, "index"],
"\n",
[nodes.inline, "index"])],))
def test_labeled_rubric(app):
text = (".. _label:\n"
".. rubric:: blah *blah* blah\n")
restructuredtext.parse(app, text)
domain = app.env.get_domain("std")
assert 'label' in domain.labels
assert domain.labels['label'] == ('index', 'label', 'blah blah blah')

View File

@@ -87,6 +87,12 @@ def test_format_date():
assert i18n.format_date(format, date=datet) == 'Feb 7, 2016, 5:11:17 AM'
assert i18n.format_date(format, date=date) == 'Feb 7, 2016'
# timezone
format = '%Z'
assert i18n.format_date(format, date=datet) == 'UTC'
format = '%z'
assert i18n.format_date(format, date=datet) == '+0000'
@pytest.mark.xfail(os.name != 'posix', reason="Path separators don't match on windows")
def test_get_filename_for_language(app):