summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2021-01-16 21:51:46 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2021-01-16 21:51:46 +0900
commit30f8640bab786b28e2fbc3a12a4cf212e6f953d1 (patch)
treef5cf23900a7bc509fe970262195995ddc526fda1
parent5460ea103bd91ce910e50e11e05c1e5340c2a9e0 (diff)
parent7c340e1c1c43f173f11efc14feb29cd08cedb995 (diff)
downloadsphinx-git-30f8640bab786b28e2fbc3a12a4cf212e6f953d1.tar.gz
Merge branch '3.x'
-rw-r--r--.readthedocs.yml8
-rw-r--r--CHANGES13
-rw-r--r--doc/extdev/deprecated.rst5
-rw-r--r--doc/usage/configuration.rst30
-rw-r--r--doc/usage/extensions/autodoc.rst6
-rw-r--r--doc/usage/restructuredtext/directives.rst11
-rw-r--r--sphinx/config.py13
-rw-r--r--sphinx/directives/code.py8
-rw-r--r--sphinx/domains/c.py21
-rw-r--r--sphinx/domains/cpp.py43
-rw-r--r--sphinx/domains/std.py4
-rw-r--r--sphinx/environment/adapters/toctree.py4
-rw-r--r--sphinx/ext/autodoc/directive.py10
-rw-r--r--sphinx/pycode/ast.py4
-rw-r--r--sphinx/util/i18n.py4
-rw-r--r--sphinx/writers/html.py12
-rw-r--r--sphinx/writers/html5.py12
-rw-r--r--sphinx/writers/latex.py21
-rw-r--r--sphinx/writers/manpage.py3
-rw-r--r--sphinx/writers/texinfo.py21
-rw-r--r--tests/roots/test-domain-c-intersphinx/conf.py4
-rw-r--r--tests/roots/test-domain-c-intersphinx/index.rst62
-rw-r--r--tests/roots/test-domain-cpp-intersphinx/conf.py4
-rw-r--r--tests/roots/test-domain-cpp-intersphinx/index.rst112
-rw-r--r--tests/roots/test-domain-cpp/roles-targets-ok.rst24
-rw-r--r--tests/roots/test-domain-cpp/roles-targets-warn.rst24
-rw-r--r--tests/roots/test-domain-py/abbr.rst10
-rw-r--r--tests/roots/test-highlight_options/conf.py4
-rw-r--r--tests/roots/test-highlight_options/index.rst14
-rw-r--r--tests/test_build_html.py34
-rw-r--r--tests/test_directive_code.py8
-rw-r--r--tests/test_domain_c.py52
-rw-r--r--tests/test_domain_cpp.py70
-rw-r--r--tests/test_domain_py.py24
-rw-r--r--tests/test_domain_std.py10
-rw-r--r--tests/test_util_i18n.py6
36 files changed, 596 insertions, 119 deletions
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 000000000..680a0e3b5
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,8 @@
+version: 2
+python:
+ version: 3
+ install:
+ - method: pip
+ path: .
+ extra_requirements:
+ - docs
diff --git a/CHANGES b/CHANGES
index 16920e78a..08526bc61 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
--------
diff --git a/doc/extdev/deprecated.rst b/doc/extdev/deprecated.rst
index 47b0f68e7..117cabad8 100644
--- a/doc/extdev/deprecated.rst
+++ b/doc/extdev/deprecated.rst
@@ -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
diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst
index 7a92cc12a..ba5c15bb3 100644
--- a/doc/usage/configuration.rst
+++ b/doc/usage/configuration.rst
@@ -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
diff --git a/doc/usage/extensions/autodoc.rst b/doc/usage/extensions/autodoc.rst
index 2bd220c6d..ed85c941e 100644
--- a/doc/usage/extensions/autodoc.rst
+++ b/doc/usage/extensions/autodoc.rst
@@ -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:
diff --git a/doc/usage/restructuredtext/directives.rst b/doc/usage/restructuredtext/directives.rst
index 92bf78489..a5c1427cf 100644
--- a/doc/usage/restructuredtext/directives.rst
+++ b/doc/usage/restructuredtext/directives.rst
@@ -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
diff --git a/sphinx/config.py b/sphinx/config.py
index 6a8224272..735a3e0b3 100644
--- a/sphinx/config.py
+++ b/sphinx/config.py
@@ -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)
diff --git a/sphinx/directives/code.py b/sphinx/directives/code.py
index d4f73f84f..f5cd92b82 100644
--- a/sphinx/directives/code.py
+++ b/sphinx/directives/code.py
@@ -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,
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index fb4da502d..064318e08 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -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 = {
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index f6e746809..4d6e189a3 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -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'),
- 'concept': ObjType(_('concept'), 'concept', 'identifier'),
- 'enum': ObjType(_('enum'), 'enum', 'type', 'identifier'),
- 'enumerator': ObjType(_('enumerator'), 'enumerator')
+ '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', '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':
+ if typ == 'any':
return True
- if declTyp == 'templateParam':
- # TODO: perhaps this should be strengthened one day
- return True
- if declTyp == 'functionParam':
- if typ == 'var' or typ == 'member':
- 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:
diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py
index 18e62c3cb..864c338f4 100644
--- a/sphinx/domains/std.py
+++ b/sphinx/domains/std.py
@@ -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:
diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py
index 5b91293a4..2e33cf702 100644
--- a/sphinx/environment/adapters/toctree.py
+++ b/sphinx/environment/adapters/toctree.py
@@ -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)
diff --git a/sphinx/ext/autodoc/directive.py b/sphinx/ext/autodoc/directive.py
index c134258d0..72407de35 100644
--- a/sphinx/ext/autodoc/directive.py
+++ b/sphinx/ext/autodoc/directive.py
@@ -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:
diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py
index db9bfefb3..b9fbfc83d 100644
--- a/sphinx/pycode/ast.py
+++ b/sphinx/pycode/ast.py
@@ -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.
diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py
index 16c7521d5..3a5aca58e 100644
--- a/sphinx/util/i18n.py
+++ b/sphinx/util/i18n.py
@@ -161,7 +161,9 @@ date_format_mappings = {
'%X': 'medium', # Locale’s 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).
'%%': '%',
}
diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py
index 63c15dd96..ca05b7e6d 100644
--- a/sphinx/writers/html.py
+++ b/sphinx/writers/html.py
@@ -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,
diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py
index 5e0be1a41..a08f62f73 100644
--- a/sphinx/writers/html5.py
+++ b/sphinx/writers/html5.py
@@ -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,
diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py
index 52432c120..56cc4bd7c 100644
--- a/sphinx/writers/latex.py
+++ b/sphinx/writers/latex.py
@@ -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
diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py
index b5034c8e7..917a71b3b 100644
--- a/sphinx/writers/manpage.py
+++ b/sphinx/writers/manpage.py
@@ -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([
diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py
index a4fd941a3..a70ffd5e4 100644
--- a/sphinx/writers/texinfo.py
+++ b/sphinx/writers/texinfo.py
@@ -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
diff --git a/tests/roots/test-domain-c-intersphinx/conf.py b/tests/roots/test-domain-c-intersphinx/conf.py
new file mode 100644
index 000000000..c176af775
--- /dev/null
+++ b/tests/roots/test-domain-c-intersphinx/conf.py
@@ -0,0 +1,4 @@
+exclude_patterns = ['_build']
+extensions = [
+ 'sphinx.ext.intersphinx',
+]
diff --git a/tests/roots/test-domain-c-intersphinx/index.rst b/tests/roots/test-domain-c-intersphinx/index.rst
new file mode 100644
index 000000000..5d6d3e098
--- /dev/null
+++ b/tests/roots/test-domain-c-intersphinx/index.rst
@@ -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`
diff --git a/tests/roots/test-domain-cpp-intersphinx/conf.py b/tests/roots/test-domain-cpp-intersphinx/conf.py
new file mode 100644
index 000000000..c176af775
--- /dev/null
+++ b/tests/roots/test-domain-cpp-intersphinx/conf.py
@@ -0,0 +1,4 @@
+exclude_patterns = ['_build']
+extensions = [
+ 'sphinx.ext.intersphinx',
+]
diff --git a/tests/roots/test-domain-cpp-intersphinx/index.rst b/tests/roots/test-domain-cpp-intersphinx/index.rst
new file mode 100644
index 000000000..9ed9493ed
--- /dev/null
+++ b/tests/roots/test-domain-cpp-intersphinx/index.rst
@@ -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`
diff --git a/tests/roots/test-domain-cpp/roles-targets-ok.rst b/tests/roots/test-domain-cpp/roles-targets-ok.rst
index e70b9259f..783f7b985 100644
--- a/tests/roots/test-domain-cpp/roles-targets-ok.rst
+++ b/tests/roots/test-domain-cpp/roles-targets-ok.rst
@@ -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)
diff --git a/tests/roots/test-domain-cpp/roles-targets-warn.rst b/tests/roots/test-domain-cpp/roles-targets-warn.rst
index decebe170..57083ff15 100644
--- a/tests/roots/test-domain-cpp/roles-targets-warn.rst
+++ b/tests/roots/test-domain-cpp/roles-targets-warn.rst
@@ -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)
diff --git a/tests/roots/test-domain-py/abbr.rst b/tests/roots/test-domain-py/abbr.rst
new file mode 100644
index 000000000..67f11578b
--- /dev/null
+++ b/tests/roots/test-domain-py/abbr.rst
@@ -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`
diff --git a/tests/roots/test-highlight_options/conf.py b/tests/roots/test-highlight_options/conf.py
new file mode 100644
index 000000000..90997d444
--- /dev/null
+++ b/tests/roots/test-highlight_options/conf.py
@@ -0,0 +1,4 @@
+highlight_options = {
+ 'default': {'default_option': True},
+ 'python': {'python_option': True}
+}
diff --git a/tests/roots/test-highlight_options/index.rst b/tests/roots/test-highlight_options/index.rst
new file mode 100644
index 000000000..389041ace
--- /dev/null
+++ b/tests/roots/test-highlight_options/index.rst
@@ -0,0 +1,14 @@
+test-highlight_options
+======================
+
+.. code-block::
+
+ blah blah blah
+
+.. code-block:: python
+
+ blah blah blah
+
+.. code-block:: java
+
+ blah blah blah
diff --git a/tests/test_build_html.py b/tests/test_build_html.py
index eecd25d07..6bfbe422b 100644
--- a/tests/test_build_html.py
+++ b/tests/test_build_html.py
@@ -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={})
diff --git a/tests/test_directive_code.py b/tests/test_directive_code.py
index 9eecabe10..0ae11baf3 100644
--- a/tests/test_directive_code.py
+++ b/tests/test_directive_code.py
@@ -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):
diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py
index 10d618712..0f17fd041 100644
--- a/tests/test_domain_c.py
+++ b/tests/test_domain_c.py
@@ -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
diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py
index 1c53150e0..da05c1261 100644
--- a/tests/test_domain_cpp.py
+++ b/tests/test_domain_cpp.py
@@ -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
diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py
index 537bae15b..a1e37fa5e 100644
--- a/tests/test_domain_py.py
+++ b/tests/test_domain_py.py
@@ -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()
diff --git a/tests/test_domain_std.py b/tests/test_domain_std.py
index f3f45d9c5..d0230ee2e 100644
--- a/tests/test_domain_std.py
+++ b/tests/test_domain_std.py
@@ -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')
diff --git a/tests/test_util_i18n.py b/tests/test_util_i18n.py
index f15f3cb95..180350e86 100644
--- a/tests/test_util_i18n.py
+++ b/tests/test_util_i18n.py
@@ -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):