Merge branch 'master' into 3606_load_mathjax_async

This commit is contained in:
Takeshi KOMIYA 2018-05-28 23:04:13 +09:00 committed by GitHub
commit 1deceda6da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 365 additions and 149 deletions

15
CHANGES
View File

@ -65,9 +65,14 @@ Deprecated
* ``sphinx.writers.latex.Table.caption_footnotetexts`` is deprecated
* ``sphinx.writers.latex.Table.header_footnotetexts`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.footnotestack`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.in_container_literal_block`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.next_section_ids`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.next_hyperlink_ids`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.restrict_footnote()`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.unrestrict_footnote()`` is deprecated
* ``LaTeXWriter.bibitems`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.push_hyperlink_ids()`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.pop_hyperlink_ids()`` is deprecated
* ``sphinx.writers.latex.LaTeXWriter.bibitems`` is deprecated
* ``BuildEnvironment.load()`` is deprecated
* ``BuildEnvironment.loads()`` is deprecated
* ``BuildEnvironment.frompickle()`` is deprecated
@ -117,6 +122,8 @@ Features added
* #4785: napoleon: Add strings to translation file for localisation
* #4927: Display a warning when invalid values are passed to linenothreshold
option of highlight directive
* C++, add a ``cpp:texpr`` role as a sibling to ``cpp:expr``.
* C++, add support for unions.
* #3606: MathJax should be loaded with async attribute
Bugs fixed
@ -175,6 +182,12 @@ Bugs fixed
mocked module
* #4973: latex: glossary directive adds whitespace to each item
* #4980: latex: Explicit labels on code blocks are duplicated
* #4919: node.asdom() crashes if toctree has :numbered: option
* #4914: autodoc: Parsing error when using dataclasses without default values
* #4931: autodoc: crashed when handler for autodoc-skip-member raises an error
* #4931: autodoc: crashed when subclass of mocked class are processed by
napoleon module
* #5007: sphinx-build crashes when error log contains a "%" character
Testing
--------

View File

@ -3,7 +3,7 @@
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = python ../sphinx/cmd/build.py
SPHINXBUILD = python3 ../sphinx/cmd/build.py
SPHINXPROJ = sphinx
SOURCEDIR = .
BUILDDIR = _build

View File

@ -73,7 +73,7 @@ package.
.. automethod:: Sphinx.add_js_file(filename, **kwargs)
.. automethod:: Sphinx.add_stylesheet(filename, alternate=None, title=None)
.. automethod:: Sphinx.add_css_file(filename, **kwargs)
.. automethod:: Sphinx.add_latex_package(packagename, options=None)

View File

@ -176,6 +176,21 @@ The following is a list of deprecated interface.
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.in_container_literal_block``
- 1.8
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.next_section_ids``
- 1.8
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.next_hyperlink_ids``
- 1.8
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.restrict_footnote()``
- 1.8
- 3.0
@ -186,6 +201,16 @@ The following is a list of deprecated interface.
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.push_hyperlink_ids()``
- 1.8
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.pop_hyperlink_ids()``
- 1.8
- 3.0
- N/A
* - ``sphinx.writers.latex.LaTeXWriter.bibitems``
- 1.8
- 3.0

View File

@ -702,6 +702,10 @@ visibility statement (``public``, ``private`` or ``protected``).
.. cpp:enumerator:: MyEnum::myOtherEnumerator = 42
.. rst:directive:: .. cpp:union:: name
Describe a union.
.. rst:directive:: .. cpp:concept:: template-parameter-list name
.. warning:: The support for concepts is experimental. It is based on the
@ -815,15 +819,19 @@ Inline Expressions and Tpes
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. rst:role:: cpp:expr
cpp:texpr
A role for inserting a C++ expression or type as inline text. For example::
Insert a C++ expression or type either as inline code (``cpp:expr``)
or inline text (``cpp:texpr``). For example::
.. cpp:var:: int a = 42
.. cpp:function:: int f(int i)
An expression: :cpp:expr:`a * f(a)`.
A type: :cpp:expr:`const MySortedContainer<int>&`.
An expression: :cpp:expr:`a * f(a)` (or as text: :cpp:texpr:`a * f(a)`).
A type: :cpp:expr:`const MySortedContainer<int>&`
(or as text :cpp:texpr:`const MySortedContainer<int>&`).
will be rendered as follows:
@ -831,8 +839,11 @@ Inline Expressions and Tpes
.. cpp:function:: int f(int i)
An expression: :cpp:expr:`a * f(a)`. A type: :cpp:expr:`const
MySortedContainer<int>&`.
An expression: :cpp:expr:`a * f(a)` (or as text: :cpp:texpr:`a * f(a)`).
A type: :cpp:expr:`const MySortedContainer<int>&`
(or as text :cpp:texpr:`const MySortedContainer<int>&`).
Namespacing
~~~~~~~~~~~
@ -880,7 +891,7 @@ The ``cpp:namespace-pop`` directive undoes the most recent
.. cpp:function:: std::size_t size() const
or:::
or::
.. cpp:class:: template<typename T> \
std::vector
@ -949,20 +960,23 @@ These roles link to the given declaration types:
.. admonition:: Note on References with Templates Parameters/Arguments
Sphinx's syntax to give references a custom title can interfere with linking
to class templates, if nothing follows the closing angle bracket, i.e. if
the link looks like this: ``:cpp:class:`MyClass<int>```. This is
interpreted as a link to ``int`` with a title of ``MyClass``. In this case,
please escape the opening angle bracket with a backslash, like this:
``:cpp:class:`MyClass\<int>```.
These roles follow the Sphinx :ref:`xref-syntax` rules. This means care must be
taken when referencing a (partial) template specialization, e.g. if the link looks like
this: ``:cpp:class:`MyClass<int>```.
This is interpreted as a link to ``int`` with a title of ``MyClass``.
In this case, escape the opening angle bracket with a backslash,
like this: ``:cpp:class:`MyClass\<int>```.
When a custom title is not needed it may be useful to use the roles for inline expressions,
:rst:role:`cpp:expr` and :rst:role:`cpp:texpr`, where angle brackets do not need escaping.
.. admonition:: Note on References to Overloaded Functions
It is currently impossible to link to a specific version of an overloaded
method. Currently the C++ domain is the first domain that has basic support
for overloaded methods and until there is more data for comparison we don't
want to select a bad syntax to reference a specific overload. Currently
Sphinx will link to the first overloaded version of the method / function.
function. Currently the C++ domain is the first domain that has basic
support for overloaded functions and until there is more data for comparison
we don't want to select a bad syntax to reference a specific overload.
Currently Sphinx will link to the first overloaded version of the function.
Declarations without template parameters and template arguments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -983,7 +997,7 @@ Assume the following declarations.
.. cpp:class:: template<typename TInner> \
Inner
In general the reference must include the template paraemter declarations,
In general the reference must include the template parameter declarations,
e.g., ``template\<typename TOuter> Wrapper::Outer``
(:cpp:class:`template\<typename TOuter> Wrapper::Outer`). Currently the lookup
only succeed if the template parameter identifiers are equal strings. That is,

View File

@ -20,7 +20,8 @@ from sphinx import package_dir, addnodes, highlighting
from sphinx.builders import Builder
from sphinx.builders.latex.transforms import (
BibliographyTransform, CitationReferenceTransform, MathReferenceTransform,
FootnoteDocnameUpdater, LaTeXFootnoteTransform, ShowUrlsTransform
FootnoteDocnameUpdater, LaTeXFootnoteTransform, LiteralBlockTransform,
ShowUrlsTransform, DocumentTargetTransform,
)
from sphinx.config import string_classes, ENUM
from sphinx.environment import NoUri
@ -223,7 +224,9 @@ class LaTeXBuilder(Builder):
transformer.set_environment(self.env)
transformer.add_transforms([BibliographyTransform,
ShowUrlsTransform,
LaTeXFootnoteTransform])
LaTeXFootnoteTransform,
LiteralBlockTransform,
DocumentTargetTransform])
transformer.apply_transforms()
def finish(self):

View File

@ -12,6 +12,11 @@
from docutils import nodes
class captioned_literal_block(nodes.container):
"""A node for a container of literal_block having a caption."""
pass
class footnotemark(nodes.Inline, nodes.Referential, nodes.TextElement):
"""A node represents ``\footnotemark``."""
pass

View File

@ -13,7 +13,7 @@ from docutils import nodes
from sphinx import addnodes
from sphinx.builders.latex.nodes import (
footnotemark, footnotetext, math_reference, thebibliography
captioned_literal_block, footnotemark, footnotetext, math_reference, thebibliography
)
from sphinx.transforms import SphinxTransform
@ -566,3 +566,33 @@ class MathReferenceTransform(SphinxTransform):
if docname:
refnode = math_reference('', docname=docname, target=node['reftarget'])
node.replace_self(refnode)
class LiteralBlockTransform(SphinxTransform):
"""Replace container nodes for literal_block by captioned_literal_block."""
default_priority = 400
def apply(self):
# type: () -> None
if self.app.builder.name != 'latex':
return
for node in self.document.traverse(nodes.container):
if node['literal_block'] is True:
newnode = captioned_literal_block('', *node.children, **node.attributes)
node.replace_self(newnode)
class DocumentTargetTransform(SphinxTransform):
"""Add :doc label to the first section of each document."""
default_priority = 400
def apply(self):
# type: () -> None
if self.app.builder.name != 'latex':
return
for node in self.document.traverse(addnodes.start_of_file):
section = node.next_node(nodes.section)
if section:
section['ids'].append(':doc') # special label for :doc:

View File

@ -3196,6 +3196,27 @@ class ASTClass(ASTBase):
signode.pop()
class ASTUnion(ASTBase):
def __init__(self, name):
# type: (Any) -> None
self.name = name
def get_id(self, version, objectType, symbol):
# type: (int, unicode, Symbol) -> unicode
if version == 1:
raise NoOldIdError()
return symbol.get_full_nested_name().get_id(version)
def __unicode__(self):
# type: () -> unicode
return text_type(self.name)
def describe_signature(self, signode, mode, env, symbol):
# type: (addnodes.desc_signature, unicode, BuildEnvironment, Symbol) -> None
_verify_description_mode(mode)
self.name.describe_signature(signode, mode, env, symbol=symbol)
class ASTEnum(ASTBase):
def __init__(self, name, scoped, underlyingType):
# type: (Any, unicode, Any) -> None
@ -3361,6 +3382,8 @@ class ASTDeclaration(ASTBase):
pass
elif self.objectType == 'class':
mainDeclNode += addnodes.desc_annotation('class ', 'class ')
elif self.objectType == 'union':
mainDeclNode += addnodes.desc_annotation('union ', 'union ')
elif self.objectType == 'enum':
prefix = 'enum '
if self.scoped: # type: ignore
@ -5259,6 +5282,11 @@ class DefinitionParser(object):
break
return ASTClass(name, final, bases)
def _parse_union(self):
# type: () -> ASTUnion
name = self._parse_nested_name()
return ASTUnion(name)
def _parse_enum(self):
# type: () -> ASTEnum
scoped = None # type: unicode # is set by CPPEnumObject
@ -5466,7 +5494,7 @@ class DefinitionParser(object):
def parse_declaration(self, objectType):
# type: (unicode) -> ASTDeclaration
if objectType not in ('type', 'concept', 'member',
'function', 'class', 'enum', 'enumerator'):
'function', 'class', 'union', 'enum', 'enumerator'):
raise Exception('Internal error, unknown objectType "%s".' % objectType)
visibility = None
templatePrefix = None
@ -5505,6 +5533,8 @@ class DefinitionParser(object):
declaration = self._parse_type(named=True, outer='function')
elif objectType == 'class':
declaration = self._parse_class()
elif objectType == 'union':
declaration = self._parse_union()
elif objectType == 'enum':
declaration = self._parse_enum()
elif objectType == 'enumerator':
@ -5807,6 +5837,16 @@ class CPPClassObject(CPPObject):
return parser.parse_declaration("class")
class CPPUnionObject(CPPObject):
def get_index_text(self, name):
# type: (unicode) -> unicode
return _('%s (C++ union)') % name
def parse_definition(self, parser):
# type: (Any) -> Any
return parser.parse_declaration("union")
class CPPEnumObject(CPPObject):
def get_index_text(self, name):
# type: (unicode) -> unicode
@ -5965,6 +6005,16 @@ class CPPXRefRole(XRefRole):
class CPPExprRole(object):
def __init__(self, asCode):
if asCode:
# render the expression as inline code
self.class_type = 'cpp-expr'
self.node_type = nodes.literal
else:
# render the expression as inline text
self.class_type = 'cpp-texpr'
self.node_type = nodes.inline
def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]):
class Warner(object):
def warn(self, msg):
@ -5972,18 +6022,23 @@ class CPPExprRole(object):
text = utils.unescape(text).replace('\n', ' ')
env = inliner.document.settings.env
parser = DefinitionParser(text, Warner(), env.config)
# attempt to mimic XRefRole classes, except that...
classes = ['xref', 'cpp', self.class_type]
try:
ast = parser.parse_expression()
except DefinitionError as ex:
Warner().warn('Unparseable C++ expression: %r\n%s'
% (text, text_type(ex.description)))
return [nodes.literal(text)], []
# see below
return [self.node_type(text, text, classes=classes)], []
parentSymbol = env.temp_data.get('cpp:parent_symbol', None)
if parentSymbol is None:
parentSymbol = env.domaindata['cpp']['root_symbol']
p = nodes.literal()
ast.describe_signature(p, 'markType', env, parentSymbol)
return [p], []
# ...most if not all of these classes should really apply to the individual references,
# not the container node
signode = self.node_type(classes=classes)
ast.describe_signature(signode, 'markType', env, parentSymbol)
return [signode], []
class CPPDomain(Domain):
@ -5992,6 +6047,7 @@ class CPPDomain(Domain):
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'),
@ -6002,6 +6058,7 @@ class CPPDomain(Domain):
directives = {
'class': CPPClassObject,
'union': CPPUnionObject,
'function': CPPFunctionObject,
'member': CPPMemberObject,
'var': CPPMemberObject,
@ -6018,6 +6075,7 @@ class CPPDomain(Domain):
roles = {
'any': CPPXRefRole(),
'class': CPPXRefRole(),
'union': CPPXRefRole(),
'func': CPPXRefRole(fix_parens=True),
'member': CPPXRefRole(),
'var': CPPXRefRole(),
@ -6025,7 +6083,8 @@ class CPPDomain(Domain):
'concept': CPPXRefRole(),
'enum': CPPXRefRole(),
'enumerator': CPPXRefRole(),
'expr': CPPExprRole()
'expr': CPPExprRole(asCode=True),
'texpr': CPPExprRole(asCode=False)
}
initial_data = {
'root_symbol': Symbol(None, None, None, None, None, None),

View File

@ -313,19 +313,6 @@ class BuildEnvironment(object):
"""Like :meth:`warn`, but with source information taken from *node*."""
self._warnfunc(msg, '%s:%s' % get_source_line(node), **kwargs)
def need_refresh(self, app):
# type: (Sphinx) -> Tuple[bool, unicode]
"""Check refresh environment is needed.
If needed, this method returns the reason for refresh.
"""
if self.version != app.registry.get_envversion(app):
return True, __('build environment version not current')
elif self.srcdir != app.srcdir:
return True, __('source directory has changed')
else:
return False, None
def clear_doc(self, docname):
# type: (unicode) -> None
"""Remove all traces of a source file in the inventory."""

View File

@ -172,10 +172,10 @@ class TocTreeCollector(EnvironmentCollector):
number = tuple(numstack)
else:
number = None
secnums[subnode[0]['anchorname']] = \
subnode[0]['secnumber'] = number
secnums[subnode[0]['anchorname']] = number
subnode[0]['secnumber'] = list(number)
if titlenode:
titlenode['secnumber'] = number
titlenode['secnumber'] = list(number)
titlenode = None
elif isinstance(subnode, addnodes.toctree):
_walk_toctree(subnode, depth)

View File

@ -643,11 +643,17 @@ class Documenter(object):
# should be skipped
if self.env.app:
# let extensions preprocess docstrings
try:
skip_user = self.env.app.emit_firstresult(
'autodoc-skip-member', self.objtype, membername, member,
not keep, self.options)
if skip_user is not None:
keep = not skip_user
except Exception as exc:
logger.warning(__('autodoc: failed to determine %r to be documented.'
'the following exception was raised:\n%s'),
member, exc)
keep = False
if keep:
ret.append((membername, member, isattr))

View File

@ -23,7 +23,7 @@ from sphinx.util.inspect import isenumclass, safe_getattr
if False:
# For type annotation
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple # NOQA
from typing import Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple # NOQA
logger = logging.getLogger(__name__)
@ -41,7 +41,7 @@ class _MockObject(object):
def __init__(self, *args, **kwargs):
# type: (Any, Any) -> None
pass
self.__qualname__ = ''
def __len__(self):
# type: () -> int
@ -52,8 +52,8 @@ class _MockObject(object):
return False
def __iter__(self):
# type: () -> None
pass
# type: () -> Iterator
return iter([])
def __mro_entries__(self, bases):
# type: (Tuple) -> Tuple

View File

@ -225,11 +225,12 @@ class AfterCommentParser(TokenProcessor):
def parse(self):
# type: () -> None
"""Parse the code and obtain comment after assignment."""
# skip lvalue (until '=' operator)
while self.fetch_token() != [OP, '=']:
# skip lvalue (or whole of AnnAssign)
while not self.fetch_token().match([OP, '='], NEWLINE, COMMENT):
assert self.current
# skip rvalue
# skip rvalue (if exists)
if self.current == [OP, '=']:
self.fetch_rvalue()
if self.current == COMMENT:

View File

@ -392,7 +392,7 @@ class WarningIsErrorFilter(logging.Filter):
location = getattr(record, 'location', '')
try:
message = record.msg % record.args
except TypeError:
except (TypeError, ValueError):
message = record.msg # use record.msg itself
if location:

View File

@ -56,8 +56,7 @@ def repr_domxml(node, length=80):
returns full of DOM XML representation.
:return: DOM XML representation
"""
# text = node.asdom().toxml() # #4919 crush if node has secnumber with tuple value
text = text_type(node) # workaround for #4919
text = node.asdom().toxml()
if length and len(text) > length:
text = text[:length] + '...'
return text
@ -82,9 +81,8 @@ def apply_source_workaround(node):
get_full_module_name(node), repr_domxml(node))
node.source, node.line = node.parent.source, node.parent.line
if isinstance(node, nodes.title) and node.source is None:
# Uncomment these lines after merging into master(1.8)
# logger.debug('[i18n] PATCH: %r to have source: %s',
# get_full_module_name(node), repr_domxml(node))
logger.debug('[i18n] PATCH: %r to have source: %s',
get_full_module_name(node), repr_domxml(node))
node.source, node.line = node.parent.source, node.parent.line
if isinstance(node, nodes.term):
logger.debug('[i18n] PATCH: %r to have rawsource: %s',

View File

@ -25,7 +25,7 @@ from six import itervalues, text_type
from sphinx import addnodes
from sphinx import highlighting
from sphinx.builders.latex.nodes import footnotetext
from sphinx.builders.latex.nodes import captioned_literal_block, footnotetext
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.errors import SphinxError
from sphinx.locale import admonitionlabels, _, __
@ -58,6 +58,7 @@ HYPERLINK_SUPPORT_NODES = (
nodes.literal_block,
nodes.table,
nodes.section,
captioned_literal_block,
)
DEFAULT_SETTINGS = {
@ -465,7 +466,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.in_production_list = 0
self.in_footnote = 0
self.in_caption = 0
self.in_container_literal_block = 0
self.in_term = 0
self.needs_linetrimming = 0
self.in_minipage = 0
@ -691,8 +691,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.pending_footnotes = [] # type: List[nodes.footnote_reference]
self.curfilestack = [] # type: List[unicode]
self.handled_abbrs = set() # type: Set[unicode]
self.next_hyperlink_ids = {} # type: Dict[unicode, Set[unicode]]
self.next_section_ids = set() # type: Set[unicode]
def pushbody(self, newbody):
# type: (List[unicode]) -> None
@ -705,15 +703,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body = self.bodystack.pop()
return body
def push_hyperlink_ids(self, figtype, ids):
# type: (unicode, Set[unicode]) -> None
hyperlink_ids = self.next_hyperlink_ids.setdefault(figtype, set())
hyperlink_ids.update(ids)
def pop_hyperlink_ids(self, figtype):
# type: (unicode) -> Set[unicode]
return self.next_hyperlink_ids.pop(figtype, set())
def check_latex_elements(self):
# type: () -> None
for key in self.builder.config.latex_elements:
@ -931,8 +920,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_start_of_file(self, node):
# type: (nodes.Node) -> None
# also add a document target
self.next_section_ids.add(':doc')
self.curfilestack.append(node['docname'])
# use default highlight settings for new file
self.hlsettingstack.append(self.hlsettingstack[0])
@ -1067,11 +1054,6 @@ class LaTeXTranslator(nodes.NodeVisitor):
# just use "subparagraph", it's not numbered anyway
self.body.append(r'\%s%s{' % (self.sectionnames[-1], short))
self.context.append('}\n' + self.hypertarget_to(node.parent))
if self.next_section_ids:
for id in self.next_section_ids:
self.context[-1] += self.hypertarget(id, anchor=False)
self.next_section_ids.clear()
elif isinstance(parent, nodes.topic):
self.body.append(r'\sphinxstyletopictitle{')
self.context.append('}\n')
@ -1790,7 +1772,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_caption(self, node):
# type: (nodes.Node) -> None
self.in_caption += 1
if self.in_container_literal_block:
if isinstance(node.parent, captioned_literal_block):
self.body.append('\\sphinxSetupCaptionForVerbatim{')
elif self.in_minipage and isinstance(node.parent, nodes.figure):
self.body.append('\\captionof{figure}{')
@ -1883,35 +1865,13 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append(self.hypertarget(id, anchor=anchor))
# skip if visitor for next node supports hyperlink
domain = self.builder.env.get_domain('std')
next_node = node.next_node(ascend=True)
if isinstance(next_node, HYPERLINK_SUPPORT_NODES):
return
# postpone the labels until after the sectioning command
parindex = node.parent.index(node)
try:
try:
next = node.parent[parindex + 1]
except IndexError:
# last node in parent, look at next after parent
# (for section of equal level) if it exists
if node.parent.parent is not None:
next = node.parent.parent[
node.parent.parent.index(node.parent)]
else:
raise
domain = self.builder.env.get_domain('std')
figtype = domain.get_enumerable_node_type(next)
if figtype and domain.get_numfig_title(next):
ids = set()
# labels for figures go in the figure body, not before
if node.get('refid'):
ids.add(node['refid'])
ids.update(node['ids'])
self.push_hyperlink_ids(figtype, ids)
elif domain.get_enumerable_node_type(next_node) and domain.get_numfig_title(next_node):
return
except IndexError:
pass
if 'refuri' in node:
return
if node.get('refid'):
@ -2221,6 +2181,14 @@ class LaTeXTranslator(nodes.NodeVisitor):
# the \ignorespaces in particular for after table header use
self.body.append('%\n\\end{footnotetext}\\ignorespaces ')
def visit_captioned_literal_block(self, node):
# type: (nodes.Node) -> None
pass
def depart_captioned_literal_block(self, node):
# type: (nodes.Node) -> None
pass
def visit_literal_block(self, node):
# type: (nodes.Node) -> None
if node.rawsource != node.astext():
@ -2229,9 +2197,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
self.body.append('\\begin{sphinxalltt}\n')
else:
labels = self.hypertarget_to(node)
# LaTeX code will insert \phantomsection prior to \label
if isinstance(node.parent, captioned_literal_block):
labels += self.hypertarget_to(node.parent)
if labels and not self.in_footnote:
self.body.append('\n\\def\\sphinxLiteralBlockLabel{' + labels + '}')
code = node.astext()
lang = self.hlsettingstack[-1][0]
linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1
@ -2458,22 +2428,11 @@ class LaTeXTranslator(nodes.NodeVisitor):
def visit_container(self, node):
# type: (nodes.Node) -> None
if node.get('literal_block'):
self.in_container_literal_block += 1
ids = '' # type: unicode
for id in self.pop_hyperlink_ids('code-block'):
ids += self.hypertarget(id, anchor=False)
if node['ids']:
# suppress with anchor=False \phantomsection insertion
ids += self.hypertarget(node['ids'][0], anchor=False)
# define label for use in caption.
if ids:
self.body.append('\n\\def\\sphinxLiteralBlockLabel{' + ids + '}\n')
pass
def depart_container(self, node):
# type: (nodes.Node) -> None
if node.get('literal_block'):
self.in_container_literal_block -= 1
pass
def visit_decoration(self, node):
# type: (nodes.Node) -> None
@ -2603,6 +2562,39 @@ class LaTeXTranslator(nodes.NodeVisitor):
RemovedInSphinx30Warning)
return []
@property
def in_container_literal_block(self):
# type: () -> int
warnings.warn('LaTeXTranslator.in_container_literal_block is deprecated.',
RemovedInSphinx30Warning)
return 0
@property
def next_section_ids(self):
# type: () -> Set[unicode]
warnings.warn('LaTeXTranslator.next_section_ids is deprecated.',
RemovedInSphinx30Warning)
return set()
@property
def next_hyperlink_ids(self):
# type: () -> Dict
warnings.warn('LaTeXTranslator.next_hyperlink_ids is deprecated.',
RemovedInSphinx30Warning)
return {}
def push_hyperlink_ids(self, figtype, ids):
# type: (unicode, Set[unicode]) -> None
warnings.warn('LaTeXTranslator.push_hyperlink_ids() is deprecated.',
RemovedInSphinx30Warning)
pass
def pop_hyperlink_ids(self, figtype):
# type: (unicode) -> Set[unicode]
warnings.warn('LaTeXTranslator.pop_hyperlink_ids() is deprecated.',
RemovedInSphinx30Warning)
return set()
# Import old modules here for compatibility
# They should be imported after `LaTeXTranslator` to avoid recursive import.

View File

@ -0,0 +1,12 @@
xref consistency
----------------
.. cpp:namespace:: xref_consistency
.. cpp:class:: item
code-role: :code:`item`
any-role: :any:`item`
cpp-any-role: :cpp:any:`item`
cpp-expr-role: :cpp:expr:`item`
cpp-texpr-role: :cpp:texpr:`item`

View File

@ -491,6 +491,10 @@ def test_class_definitions():
{2: 'I0E7has_varI1TNSt6void_tIDTadN1T3varEEEEE'})
def test_union_definitions():
check('union', 'A', {2: "1A"})
def test_enum_definitions():
check('enum', 'A', {2: "1A"})
check('enum', 'A : std::underlying_type<B>::type', {2: "1A"})
@ -735,3 +739,68 @@ def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, wa
t = (app.outdir / f).text()
for s in parenPatterns:
check(s, t, f)
@pytest.mark.sphinx(testroot='domain-cpp')
def test_xref_consistency(app, status, warning):
app.builder.build_all()
test = 'xref_consistency.html'
output = (app.outdir / test).text()
def classes(role, tag):
pattern = (r'{role}-role:.*?'
'<(?P<tag>{tag}) .*?class=["\'](?P<classes>.*?)["\'].*?>'
'.*'
'</(?P=tag)>').format(role=role, tag=tag)
result = re.search(pattern, output)
expect = '''\
Pattern for role `{role}` with tag `{tag}`
\t{pattern}
not found in `{test}`
'''.format(role=role, tag=tag, pattern=pattern, test=test)
assert result, expect
return set(result.group('classes').split())
class RoleClasses(object):
"""Collect the classes from the layout that was generated for a given role."""
def __init__(self, role, root, contents):
self.name = role
self.classes = classes(role, root)
self.content_classes = dict()
for tag in contents:
self.content_classes[tag] = classes(role, tag)
# not actually used as a reference point
#code_role = RoleClasses('code', 'code', [])
any_role = RoleClasses('any', 'a', ['code'])
cpp_any_role = RoleClasses('cpp-any', 'a', ['code'])
# NYI: consistent looks
#texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'code'])
expr_role = RoleClasses('cpp-expr', 'code', ['a'])
texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'span'])
# XRefRole-style classes
## any and cpp:any do not put these classes at the root
# n.b. the generic any machinery finds the specific 'cpp-class' object type
expect = 'any uses XRefRole classes'
assert {'xref', 'any', 'cpp', 'cpp-class'} <= any_role.content_classes['code'], expect
expect = 'cpp:any uses XRefRole classes'
assert {'xref', 'cpp-any', 'cpp'} <= cpp_any_role.content_classes['code'], expect
for role in (expr_role, texpr_role):
name = role.name
expect = '`{name}` puts the domain and role classes at its root'.format(name=name)
# NYI: xref should go in the references
assert {'xref', 'cpp', name} <= role.classes, expect
# reference classes
expect = 'the xref roles use the same reference classes'
assert any_role.classes == cpp_any_role.classes, expect
assert any_role.classes == expr_role.content_classes['a'], expect
assert any_role.classes == texpr_role.content_classes['a'], expect

View File

@ -227,11 +227,11 @@ def test_get_toctree_for(app):
[list_item, compact_paragraph, reference, "foo.1"],
[list_item, compact_paragraph, reference, "foo.2"]))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1))
assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2))
assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3))
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1])
assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1])
assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2])
assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3])
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2])
assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
assert_node(toctree[2],
@ -258,8 +258,8 @@ def test_get_toctree_for_collapse(app):
([list_item, compact_paragraph, reference, "foo"],
[list_item, compact_paragraph, reference, "bar"],
[list_item, compact_paragraph, reference, "http://sphinx-doc.org/"]))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1])
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2])
assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
assert_node(toctree[2],
@ -296,13 +296,13 @@ def test_get_toctree_for_maxdepth(app):
assert_node(toctree[1][0][1][1][1],
[bullet_list, list_item, compact_paragraph, reference, "foo.1-1"])
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1))
assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1])
assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1])
assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2])
assert_node(toctree[1][0][1][1][1][0][0][0],
reference, refuri="foo#foo-1-1", secnumber=(1, 2, 1))
assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3))
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
reference, refuri="foo#foo-1-1", secnumber=[1, 2, 1])
assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3])
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2])
assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
assert_node(toctree[2],
@ -335,11 +335,11 @@ def test_get_toctree_for_includehidden(app):
[list_item, compact_paragraph, reference, "foo.1"],
[list_item, compact_paragraph, reference, "foo.2"]))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=(1,))
assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=(1, 1))
assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=(1, 2))
assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=(1, 3))
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=(2,))
assert_node(toctree[1][0][0][0], reference, refuri="foo", secnumber=[1])
assert_node(toctree[1][0][1][0][0][0], reference, refuri="quux", secnumber=[1, 1])
assert_node(toctree[1][0][1][1][0][0], reference, refuri="foo#foo-1", secnumber=[1, 2])
assert_node(toctree[1][0][1][2][0][0], reference, refuri="foo#foo-2", secnumber=[1, 3])
assert_node(toctree[1][1][0][0], reference, refuri="bar", secnumber=[2])
assert_node(toctree[1][2][0][0], reference, refuri="http://sphinx-doc.org/")
assert_node(toctree[2],

View File

@ -100,11 +100,13 @@ def test_comment_picker_location():
def test_annotated_assignment_py36():
source = ('a: str = "Sphinx" #: comment\n'
'b: int = 1\n'
'"""string on next line"""')
'"""string on next line"""\n'
'c: int #: comment')
parser = Parser(source)
parser.parse()
assert parser.comments == {('', 'a'): 'comment',
('', 'b'): 'string on next line'}
('', 'b'): 'string on next line',
('', 'c'): 'comment'}
assert parser.definitions == {}