Merge branch '2.0' into 6709_mock_class_decorators

This commit is contained in:
Takeshi KOMIYA 2019-10-14 11:00:24 +09:00 committed by GitHub
commit a20c7e6eb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 227 additions and 225 deletions

View File

@ -16,6 +16,9 @@ Deprecated
Features added
--------------
* #6707: C++, support bit-fields.
* #267: html: Eliminate prompt characters of doctest block from copyable text
Bugs fixed
----------
@ -24,6 +27,9 @@ Bugs fixed
.. _latex3/latex2e#173: https://github.com/latex3/latex2e/issues/173
* #6618: LaTeX: Avoid section names at the end of a page
* #6704: linkcheck: Be defensive and handle newly defined HTTP error code
* #6655: image URLs containing ``data:`` causes gettext builder crashed
* #6584: i18n: Error when compiling message catalogs on Hindi
* #6709: autodoc: mock object does not work as a class decorator
Testing

View File

@ -237,13 +237,16 @@ class CheckExternalLinksBuilder(Builder):
else:
logger.info(red('broken ') + uri + red(' - ' + info))
elif status == 'redirected':
text, color = {
301: ('permanently', darkred),
302: ('with Found', purple),
303: ('with See Other', purple),
307: ('temporarily', turquoise),
0: ('with unknown code', purple),
}[code]
try:
text, color = {
301: ('permanently', darkred),
302: ('with Found', purple),
303: ('with See Other', purple),
307: ('temporarily', turquoise),
0: ('with unknown code', purple),
}[code]
except KeyError:
text, color = ('with unknown code', purple)
self.write_entry('redirected ' + text, docname, lineno,
uri + ' to ' + info)
logger.info(color('redirect ') + uri + color(' - ' + text + ' to ' + info))

View File

@ -3191,6 +3191,52 @@ class ASTDeclaratorNameParamQual(ASTBase):
self.paramQual.describe_signature(signode, mode, env, symbol)
class ASTDeclaratorNameBitField(ASTBase):
def __init__(self, declId, size):
self.declId = declId
self.size = size
@property
def name(self):
# type: () -> ASTNestedName
return self.declId
def get_param_id(self, version): # only the parameters (if any)
# type: (int) -> str
return ''
def get_ptr_suffix_id(self, version): # only the array specifiers
# type: (int) -> str
return ''
# ------------------------------------------------------------------------
def require_space_after_declSpecs(self):
# type: () -> bool
return self.declId is not None
def is_function_type(self):
# type: () -> bool
return False
def _stringify(self, transform):
# type: (Callable[[Any], str]) -> str
res = []
if self.declId:
res.append(transform(self.declId))
res.append(" : ")
res.append(transform(self.size))
return ''.join(res)
def describe_signature(self, signode, mode, env, symbol):
# type: (addnodes.desc_signature, str, BuildEnvironment, Symbol) -> None
_verify_description_mode(mode)
if self.declId:
self.declId.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(' : ', ' : '))
self.size.describe_signature(signode, mode, env, symbol)
class ASTParenExprList(ASTBase):
def __init__(self, exprs):
# type: (List[Any]) -> None
@ -5716,8 +5762,12 @@ class DefinitionParser:
trailing = None
return ASTDeclSpecs(outer, leftSpecs, rightSpecs, trailing)
def _parse_declarator_name_param_qual(self, named, paramMode, typed):
# type: (Union[bool, str], str, bool) -> ASTDeclaratorNameParamQual
def _parse_declarator_name_suffix(self,
named, # type: Union[bool, str]
paramMode, # type: str
typed # type: bool
):
# type: (...) -> Union[ASTDeclaratorNameParamQual, ASTDeclaratorNameBitField]
# now we should parse the name, and then suffixes
if named == 'maybe':
pos = self.pos
@ -5760,6 +5810,13 @@ class DefinitionParser:
else:
break
paramQual = self._parse_parameters_and_qualifiers(paramMode)
if paramQual is None and len(arrayOps) == 0:
# perhaps a bit-field
if named and paramMode == 'type' and typed:
self.skip_ws()
if self.skip_string(':'):
size = self._parse_constant_expression(inTemplate=False)
return ASTDeclaratorNameBitField(declId=declId, size=size)
return ASTDeclaratorNameParamQual(declId=declId, arrayOps=arrayOps,
paramQual=paramQual)
@ -5842,8 +5899,8 @@ class DefinitionParser:
pos = self.pos
try:
# assume this is params and quals
res = self._parse_declarator_name_param_qual(named, paramMode,
typed)
res = self._parse_declarator_name_suffix(named, paramMode,
typed)
return res
except DefinitionError as exParamQual:
prevErrors.append((exParamQual, "If declId, parameters, and qualifiers"))
@ -5868,7 +5925,7 @@ class DefinitionParser:
raise self._make_multi_error(prevErrors, header)
pos = self.pos
try:
return self._parse_declarator_name_param_qual(named, paramMode, typed)
return self._parse_declarator_name_suffix(named, paramMode, typed)
except DefinitionError as e:
self.pos = pos
prevErrors.append((e, "If declarator-id"))

View File

@ -338,7 +338,7 @@ msgstr "%r भूमिका पहले से अधिकार-क्ष
#: sphinx/registry.py:226
#, python-format
msgid "The %r index is already registered to domain %s"
msgstr "r% अनुक्रमणिका पहले से अधिकार-क्षेत्र %s में पंजीकृत है"
msgstr "%r अनुक्रमणिका पहले से अधिकार-क्षेत्र %s में पंजीकृत है"
#: sphinx/registry.py:250
#, python-format

View File

@ -672,6 +672,10 @@ div.code-block-caption + div > div.highlight > pre {
margin-top: 0;
}
div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */
user-select: none;
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;

View File

@ -9,8 +9,10 @@
"""
import re
from typing import Any, Dict, Generator, List, Tuple
from docutils import nodes
from docutils.nodes import Element, Node, Text
from docutils.transforms import Transform, Transformer
from docutils.transforms.parts import ContentsFilter
from docutils.transforms.universal import SmartQuotes
@ -18,6 +20,7 @@ from docutils.utils import normalize_language_tag
from docutils.utils.smartquotes import smartchars
from sphinx import addnodes
from sphinx.config import Config
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
from sphinx.locale import _, __
from sphinx.util import logging
@ -27,11 +30,9 @@ from sphinx.util.nodes import NodeMatcher, apply_source_workaround, is_smartquot
if False:
# For type annotation
from typing import Any, Dict, Generator, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA
from sphinx.domain.std import StandardDomain # NOQA
from sphinx.environment import BuildEnvironment # NOQA
from sphinx.application import Sphinx
from sphinx.domain.std import StandardDomain
from sphinx.environment import BuildEnvironment
logger = logging.getLogger(__name__)
@ -51,20 +52,17 @@ class SphinxTransform(Transform):
"""
@property
def app(self):
# type: () -> Sphinx
def app(self) -> "Sphinx":
"""Reference to the :class:`.Sphinx` object."""
return self.env.app
@property
def env(self):
# type: () -> BuildEnvironment
def env(self) -> "BuildEnvironment":
"""Reference to the :class:`.BuildEnvironment` object."""
return self.document.settings.env
@property
def config(self):
# type: () -> Config
def config(self) -> Config:
"""Reference to the :class:`.Config` object."""
return self.env.config
@ -77,12 +75,10 @@ class SphinxTransformer(Transformer):
document = None # type: nodes.document
env = None # type: BuildEnvironment
def set_environment(self, env):
# type: (BuildEnvironment) -> None
def set_environment(self, env: "BuildEnvironment") -> None:
self.env = env
def apply_transforms(self):
# type: () -> None
def apply_transforms(self) -> None:
if isinstance(self.document, nodes.document):
if not hasattr(self.document.settings, 'env') and self.env:
self.document.settings.env = self.env
@ -108,8 +104,7 @@ class DefaultSubstitutions(SphinxTransform):
# run before the default Substitutions
default_priority = 210
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
# only handle those not otherwise defined in the document
to_handle = default_substitutions - set(self.document.substitution_defs)
for ref in self.document.traverse(nodes.substitution_reference):
@ -132,8 +127,7 @@ class MoveModuleTargets(SphinxTransform):
"""
default_priority = 210
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.traverse(nodes.target):
if not node['ids']:
continue
@ -151,8 +145,7 @@ class HandleCodeBlocks(SphinxTransform):
"""
default_priority = 210
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
# move doctest blocks out of blockquotes
for node in self.document.traverse(nodes.block_quote):
if all(isinstance(child, nodes.doctest_block) for child
@ -176,8 +169,7 @@ class AutoNumbering(SphinxTransform):
"""
default_priority = 210
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
domain = self.env.get_domain('std') # type: StandardDomain
for node in self.document.traverse(nodes.Element):
@ -191,8 +183,7 @@ class SortIds(SphinxTransform):
"""
default_priority = 261
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.traverse(nodes.section):
if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
node['ids'] = node['ids'][1:] + [node['ids'][0]]
@ -213,9 +204,8 @@ class ApplySourceWorkaround(SphinxTransform):
"""
default_priority = 10
def apply(self, **kwargs):
# type: (Any) -> None
for node in self.document.traverse(): # type: nodes.Node
def apply(self, **kwargs) -> None:
for node in self.document.traverse(): # type: Node
if isinstance(node, (nodes.TextElement, nodes.image)):
apply_source_workaround(node)
@ -226,8 +216,7 @@ class AutoIndexUpgrader(SphinxTransform):
"""
default_priority = 210
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.traverse(addnodes.index):
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
msg = __('4 column based index found. '
@ -244,18 +233,16 @@ class ExtraTranslatableNodes(SphinxTransform):
"""
default_priority = 10
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
targets = self.config.gettext_additional_targets
target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
if not target_nodes:
return
def is_translatable_node(node):
# type: (nodes.Node) -> bool
def is_translatable_node(node: Node) -> bool:
return isinstance(node, tuple(target_nodes))
for node in self.document.traverse(is_translatable_node): # type: nodes.Element
for node in self.document.traverse(is_translatable_node): # type: Element
node['translatable'] = True
@ -265,8 +252,7 @@ class UnreferencedFootnotesDetector(SphinxTransform):
"""
default_priority = 200
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.footnotes:
if node['names'] == []:
# footnote having duplicated number. It is already warned at parser.
@ -283,16 +269,25 @@ class UnreferencedFootnotesDetector(SphinxTransform):
location=node)
class DoctestTransform(SphinxTransform):
"""Set "doctest" style to each doctest_block node"""
default_priority = 500
def apply(self, **kwargs):
# type: (Any) -> None
for node in self.document.traverse(nodes.doctest_block):
node['classes'].append('doctest')
class FigureAligner(SphinxTransform):
"""
Align figures to center by default.
"""
default_priority = 700
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
matcher = NodeMatcher(nodes.table, nodes.figure)
for node in self.document.traverse(matcher): # type: nodes.Element
for node in self.document.traverse(matcher): # type: Element
node.setdefault('align', 'default')
@ -300,8 +295,7 @@ class FilterSystemMessages(SphinxTransform):
"""Filter system messages from a doctree."""
default_priority = 999
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
filterlevel = self.config.keep_warnings and 2 or 5
for node in self.document.traverse(nodes.system_message):
if node['level'] < filterlevel:
@ -316,8 +310,7 @@ class SphinxContentsFilter(ContentsFilter):
"""
visit_pending_xref = ContentsFilter.ignore_node_but_process_children
def visit_image(self, node):
# type: (nodes.image) -> None
def visit_image(self, node: nodes.image) -> None:
raise nodes.SkipNode
@ -329,8 +322,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
"""
default_priority = 750
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
if not self.is_available():
return
@ -339,8 +331,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
super().apply()
def is_available(self):
# type: () -> bool
def is_available(self) -> bool:
builders = self.config.smartquotes_excludes.get('builders', [])
languages = self.config.smartquotes_excludes.get('languages', [])
@ -365,8 +356,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
else:
return False
def get_tokens(self, txtnodes):
# type: (List[nodes.Text]) -> Generator[Tuple[str, str], None, None]
def get_tokens(self, txtnodes: List[Text]) -> Generator[Tuple[str, str], None, None]:
# A generator that yields ``(texttype, nodetext)`` tuples for a list
# of "Text" nodes (interface to ``smartquotes.educate_tokens()``).
@ -381,8 +371,7 @@ class DoctreeReadEvent(SphinxTransform):
"""Emit :event:`doctree-read` event."""
default_priority = 880
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
self.app.emit('doctree-read', self.document)
@ -390,8 +379,7 @@ class ManpageLink(SphinxTransform):
"""Find manpage section numbers and names"""
default_priority = 999
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.traverse(addnodes.manpage):
manpage = ' '.join([str(x) for x in node.children
if isinstance(x, nodes.Text)])
@ -417,14 +405,14 @@ deprecated_alias('sphinx.transforms',
RemovedInSphinx40Warning)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_transform(ApplySourceWorkaround)
app.add_transform(ExtraTranslatableNodes)
app.add_transform(DefaultSubstitutions)
app.add_transform(MoveModuleTargets)
app.add_transform(HandleCodeBlocks)
app.add_transform(SortIds)
app.add_transform(DoctestTransform)
app.add_transform(FigureAligner)
app.add_transform(AutoNumbering)
app.add_transform(AutoIndexUpgrader)

View File

@ -8,18 +8,16 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, List
from typing import cast
from docutils import nodes
from docutils.nodes import Node
from sphinx import addnodes
from sphinx.application import Sphinx
from sphinx.transforms import SphinxTransform
if False:
# For type annotation
from typing import Any, Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
class RefOnlyListChecker(nodes.GenericNodeVisitor):
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
@ -28,17 +26,14 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
single reference in it.
"""
def default_visit(self, node):
# type: (nodes.Node) -> None
def default_visit(self, node: Node) -> None:
raise nodes.NodeFound
def visit_bullet_list(self, node):
# type: (nodes.bullet_list) -> None
def visit_bullet_list(self, node: nodes.bullet_list) -> None:
pass
def visit_list_item(self, node):
# type: (nodes.list_item) -> None
children = [] # type: List[nodes.Node]
def visit_list_item(self, node: nodes.list_item) -> None:
children = [] # type: List[Node]
for child in node.children:
if not isinstance(child, nodes.Invisible):
children.append(child)
@ -53,8 +48,7 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
raise nodes.NodeFound
raise nodes.SkipChildren
def invisible_visit(self, node):
# type: (nodes.Node) -> None
def invisible_visit(self, node: Node) -> None:
"""Invisible nodes should be ignored."""
pass
@ -67,13 +61,11 @@ class RefOnlyBulletListTransform(SphinxTransform):
"""
default_priority = 100
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
if self.config.html_compact_lists:
return
def check_refonly_list(node):
# type: (nodes.Node) -> bool
def check_refonly_list(node: Node) -> bool:
"""Check for list with only references in it."""
visitor = RefOnlyListChecker(self.document)
try:
@ -93,8 +85,7 @@ class RefOnlyBulletListTransform(SphinxTransform):
item.replace(para, compact_para)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_transform(RefOnlyBulletListTransform)
return {

View File

@ -10,13 +10,15 @@
from os import path
from textwrap import indent
from typing import Any, TypeVar
from typing import Any, Dict, List, Tuple, TypeVar
from docutils import nodes
from docutils.io import StringInput
from docutils.nodes import Element
from docutils.utils import relative_path
from sphinx import addnodes
from sphinx.config import Config
from sphinx.domains.std import make_glossary_term, split_term_classifiers
from sphinx.locale import __, init as init_locale
from sphinx.transforms import SphinxTransform
@ -29,18 +31,17 @@ from sphinx.util.nodes import (
if False:
# For type annotation
from typing import Dict, List, Tuple # NOQA
from typing import Type # for python3.5.1
from sphinx.application import Sphinx # NOQA
from sphinx.config import Config # NOQA
from sphinx.application import Sphinx
logger = logging.getLogger(__name__)
N = TypeVar('N', bound=nodes.Node)
def publish_msgstr(app, source, source_path, source_line, config, settings):
# type: (Sphinx, str, str, int, Config, Any) -> nodes.Element
def publish_msgstr(app: "Sphinx", source: str, source_path: str, source_line: int,
config: Config, settings: Any) -> Element:
"""Publish msgstr (single line) into docutils document
:param sphinx.application.Sphinx app: sphinx application
@ -75,8 +76,7 @@ class PreserveTranslatableMessages(SphinxTransform):
"""
default_priority = 10 # this MUST be invoked before Locale transform
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.traverse(addnodes.translatable):
node.preserve_original_messages()
@ -87,8 +87,7 @@ class Locale(SphinxTransform):
"""
default_priority = 20
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
settings, source = self.document.settings, self.document['source']
msgstr = ''
@ -268,7 +267,7 @@ class Locale(SphinxTransform):
unexpected = (
nodes.paragraph, # expected form of translation
nodes.title # generated by above "Subelements phase2"
) # type: Tuple[Type[nodes.Element], ...]
) # type: Tuple[Type[Element], ...]
# following types are expected if
# config.gettext_additional_targets is configured
@ -279,8 +278,7 @@ class Locale(SphinxTransform):
continue # skip
# auto-numbered foot note reference should use original 'ids'.
def list_replace_or_append(lst, old, new):
# type: (List[N], N, N) -> None
def list_replace_or_append(lst: List[N], old: N, new: N) -> None:
if old in lst:
lst[lst.index(old)] = new
else:
@ -406,8 +404,7 @@ class Locale(SphinxTransform):
.format(old_xref_rawsources, new_xref_rawsources),
location=node)
def get_ref_key(node):
# type: (addnodes.pending_xref) -> Tuple[str, str, str]
def get_ref_key(node: addnodes.pending_xref) -> Tuple[str, str, str]:
case = node["refdomain"], node["reftype"]
if case == ('std', 'term'):
return None
@ -465,7 +462,7 @@ class Locale(SphinxTransform):
node['entries'] = new_entries
# remove translated attribute that is used for avoiding double translation.
for translated in self.document.traverse(NodeMatcher(translated=Any)): # type: nodes.Element # NOQA
for translated in self.document.traverse(NodeMatcher(translated=Any)): # type: Element # NOQA
translated.delattr('translated')
@ -475,8 +472,7 @@ class RemoveTranslatableInline(SphinxTransform):
"""
default_priority = 999
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
from sphinx.builders.gettext import MessageCatalogBuilder
if isinstance(self.app.builder, MessageCatalogBuilder):
return
@ -487,8 +483,7 @@ class RemoveTranslatableInline(SphinxTransform):
inline.parent += inline.children
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_transform(PreserveTranslatableMessages)
app.add_transform(Locale)
app.add_transform(RemoveTranslatableInline)

View File

@ -8,23 +8,22 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict, List, Tuple
from typing import cast
from docutils import nodes
from docutils.nodes import Element
from sphinx import addnodes
from sphinx.addnodes import pending_xref
from sphinx.application import Sphinx
from sphinx.domains import Domain
from sphinx.errors import NoUri
from sphinx.locale import __
from sphinx.transforms import SphinxTransform
from sphinx.util import logging
from sphinx.util.nodes import process_only_nodes
if False:
# For type annotation
from typing import Any, Dict, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.domains import Domain # NOQA
logger = logging.getLogger(__name__)
@ -39,13 +38,11 @@ class SphinxPostTransform(SphinxTransform):
builders = () # type: Tuple[str, ...]
formats = () # type: Tuple[str, ...]
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
if self.is_supported():
self.run(**kwargs)
def is_supported(self):
# type: () -> bool
def is_supported(self) -> bool:
"""Check this transform working for current builder."""
if self.builders and self.app.builder.name not in self.builders:
return False
@ -54,8 +51,7 @@ class SphinxPostTransform(SphinxTransform):
return True
def run(self, **kwargs):
# type: (Any) -> None
def run(self, **kwargs) -> None:
"""main method of post transforms.
Subclasses should override this method instead of ``apply()``.
@ -70,8 +66,7 @@ class ReferencesResolver(SphinxPostTransform):
default_priority = 10
def run(self, **kwargs):
# type: (Any) -> None
def run(self, **kwargs) -> None:
for node in self.document.traverse(addnodes.pending_xref):
contnode = cast(nodes.TextElement, node[0].deepcopy())
newnode = None
@ -105,12 +100,11 @@ class ReferencesResolver(SphinxPostTransform):
newnode = contnode
node.replace_self(newnode or contnode)
def resolve_anyref(self, refdoc, node, contnode):
# type: (str, addnodes.pending_xref, nodes.TextElement) -> nodes.Element
def resolve_anyref(self, refdoc: str, node: pending_xref, contnode: Element) -> Element:
"""Resolve reference generated by the "any" role."""
stddomain = self.env.get_domain('std')
target = node['reftarget']
results = [] # type: List[Tuple[str, nodes.Element]]
results = [] # type: List[Tuple[str, Element]]
# first, try resolving as :doc:
doc_ref = stddomain.resolve_xref(self.env, refdoc, self.app.builder,
'doc', target, node, contnode)
@ -155,8 +149,8 @@ class ReferencesResolver(SphinxPostTransform):
newnode[0]['classes'].append(res_role.replace(':', '-'))
return newnode
def warn_missing_reference(self, refdoc, typ, target, node, domain):
# type: (str, str, str, addnodes.pending_xref, Domain) -> None
def warn_missing_reference(self, refdoc: str, typ: str, target: str,
node: pending_xref, domain: Domain) -> None:
warn = node.get('refwarn')
if self.config.nitpicky:
warn = True
@ -184,8 +178,7 @@ class ReferencesResolver(SphinxPostTransform):
class OnlyNodeTransform(SphinxPostTransform):
default_priority = 50
def run(self, **kwargs):
# type: (Any) -> None
def run(self, **kwargs) -> None:
# A comment on the comment() nodes being inserted: replacing by [] would
# result in a "Losing ids" exception if there is a target node before
# the only node, so we make sure docutils can transfer the id to
@ -193,8 +186,7 @@ class OnlyNodeTransform(SphinxPostTransform):
process_only_nodes(self.document, self.app.builder.tags)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_post_transform(ReferencesResolver)
app.add_post_transform(OnlyNodeTransform)

View File

@ -9,20 +9,17 @@
"""
import sys
from typing import NamedTuple, Union
from typing import Any, Dict, List, NamedTuple, Union
from docutils import nodes
from docutils.nodes import Node
from pygments.lexers import PythonConsoleLexer, guess_lexer
from sphinx import addnodes
from sphinx.application import Sphinx
from sphinx.ext import doctest
from sphinx.transforms import SphinxTransform
if False:
# For type annotation
from typing import Any, Dict, List # NOQA
from sphinx.application import Sphinx # NOQA
HighlightSetting = NamedTuple('HighlightSetting', [('language', str),
('force', bool),
@ -39,8 +36,7 @@ class HighlightLanguageTransform(SphinxTransform):
"""
default_priority = 400
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
visitor = HighlightLanguageVisitor(self.document,
self.config.highlight_language)
self.document.walkabout(visitor)
@ -50,44 +46,35 @@ class HighlightLanguageTransform(SphinxTransform):
class HighlightLanguageVisitor(nodes.NodeVisitor):
def __init__(self, document, default_language):
# type: (nodes.document, str) -> None
def __init__(self, document: nodes.document, default_language: str) -> None:
self.default_setting = HighlightSetting(default_language, False, sys.maxsize)
self.settings = [] # type: List[HighlightSetting]
super().__init__(document)
def unknown_visit(self, node):
# type: (nodes.Node) -> None
def unknown_visit(self, node: Node) -> None:
pass
def unknown_departure(self, node):
# type: (nodes.Node) -> None
def unknown_departure(self, node: Node) -> None:
pass
def visit_document(self, node):
# type: (nodes.Node) -> None
def visit_document(self, node: Node) -> None:
self.settings.append(self.default_setting)
def depart_document(self, node):
# type: (nodes.Node) -> None
def depart_document(self, node: Node) -> None:
self.settings.pop()
def visit_start_of_file(self, node):
# type: (nodes.Node) -> None
def visit_start_of_file(self, node: Node) -> None:
self.settings.append(self.default_setting)
def depart_start_of_file(self, node):
# type: (nodes.Node) -> None
def depart_start_of_file(self, node: Node) -> None:
self.settings.pop()
def visit_highlightlang(self, node):
# type: (addnodes.highlightlang) -> None
def visit_highlightlang(self, node: addnodes.highlightlang) -> None:
self.settings[-1] = HighlightSetting(node['lang'],
node['force'],
node['linenothreshold'])
def visit_literal_block(self, node):
# type: (nodes.literal_block) -> None
def visit_literal_block(self, node: nodes.literal_block) -> None:
setting = self.settings[-1]
if 'language' not in node:
node['language'] = setting.language
@ -105,8 +92,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
"""
default_priority = HighlightLanguageTransform.default_priority + 1
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
if not self.config.trim_doctest_flags:
return
@ -118,8 +104,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
self.strip_doctest_flags(dbnode)
@staticmethod
def strip_doctest_flags(node):
# type: (Union[nodes.literal_block, nodes.doctest_block]) -> None
def strip_doctest_flags(node: Union[nodes.literal_block, nodes.doctest_block]) -> None:
source = node.rawsource
source = doctest.blankline_re.sub('', source)
source = doctest.doctestopt_re.sub('', source)
@ -127,8 +112,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
node[:] = [nodes.Text(source)]
@staticmethod
def is_pyconsole(node):
# type: (nodes.literal_block) -> bool
def is_pyconsole(node: nodes.literal_block) -> bool:
if node.rawsource != node.astext():
return False # skip parsed-literal node
@ -147,8 +131,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
return False
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_post_transform(HighlightLanguageTransform)
app.add_post_transform(TrimDoctestFlagsTransform)

View File

@ -9,19 +9,17 @@
"""
import warnings
from typing import Any, Dict
from docutils import nodes
from docutils.writers.docutils_xml import XMLTranslator
from sphinx.addnodes import math_block, displaymath
from sphinx.application import Sphinx
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.transforms import SphinxTransform
from sphinx.util import logging
if False:
# For type annotation
from typing import Any, Dict # NOQA
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
@ -35,8 +33,7 @@ class MathNodeMigrator(SphinxTransform):
"""
default_priority = 999
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for math_node in self.document.traverse(nodes.math):
# case: old styled ``math`` node generated by old extensions
if len(math_node) == 0:
@ -79,8 +76,7 @@ class MathNodeMigrator(SphinxTransform):
math_block_node += nodes.Text(latex, latex)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_post_transform(MathNodeMigrator)
return {

View File

@ -11,9 +11,11 @@
import os
from hashlib import sha1
from math import ceil
from typing import Any, Dict, List, Tuple
from docutils import nodes
from sphinx.application import Sphinx
from sphinx.locale import __
from sphinx.transforms import SphinxTransform
from sphinx.util import epoch_to_rfc1123, rfc1123_to_epoch
@ -21,11 +23,6 @@ from sphinx.util import logging, requests
from sphinx.util.images import guess_mimetype, get_image_extension, parse_data_uri
from sphinx.util.osutil import ensuredir, movefile
if False:
# For type annotation
from typing import Any, Dict, List, Tuple # NOQA
from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
@ -33,31 +30,26 @@ MAX_FILENAME_LEN = 32
class BaseImageConverter(SphinxTransform):
def apply(self, **kwargsj):
# type: (Any) -> None
def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(nodes.image):
if self.match(node):
self.handle(node)
def match(self, node):
# type: (nodes.image) -> bool
def match(self, node: nodes.image) -> bool:
return True
def handle(self, node):
# type: (nodes.image) -> None
def handle(self, node: nodes.image) -> None:
pass
@property
def imagedir(self):
# type: () -> str
def imagedir(self) -> str:
return os.path.join(self.app.doctreedir, 'images')
class ImageDownloader(BaseImageConverter):
default_priority = 100
def match(self, node):
# type: (nodes.image) -> bool
def match(self, node: nodes.image) -> bool:
if self.app.builder.supported_image_types == []:
return False
elif self.app.builder.supported_remote_images:
@ -65,8 +57,7 @@ class ImageDownloader(BaseImageConverter):
else:
return '://' in node['uri']
def handle(self, node):
# type: (nodes.image) -> None
def handle(self, node: nodes.image) -> None:
try:
basename = os.path.basename(node['uri'])
if '?' in basename:
@ -123,17 +114,15 @@ class ImageDownloader(BaseImageConverter):
class DataURIExtractor(BaseImageConverter):
default_priority = 150
def match(self, node):
# type: (nodes.image) -> bool
def match(self, node: nodes.image) -> bool:
if self.app.builder.supported_remote_images == []:
return False
elif self.app.builder.supported_data_uri_images is True:
return False
else:
return 'data:' in node['uri']
return node['uri'].startswith('data:')
def handle(self, node):
# type: (nodes.image) -> None
def handle(self, node: nodes.image) -> None:
image = parse_data_uri(node['uri'])
ext = get_image_extension(image.mimetype)
if ext is None:
@ -155,8 +144,7 @@ class DataURIExtractor(BaseImageConverter):
self.app.env.images.add_file(self.env.docname, path)
def get_filename_for(filename, mimetype):
# type: (str, str) -> str
def get_filename_for(filename: str, mimetype: str) -> str:
basename = os.path.basename(filename)
return os.path.splitext(basename)[0] + get_image_extension(mimetype)
@ -195,15 +183,13 @@ class ImageConverter(BaseImageConverter):
#: ]
conversion_rules = [] # type: List[Tuple[str, str]]
def __init__(self, *args, **kwargs):
# type: (Any, Any) -> None
def __init__(self, *args, **kwargs) -> None:
self.available = None # type: bool
# the converter is available or not.
# Will be checked at first conversion
super().__init__(*args, **kwargs)
def match(self, node):
# type: (nodes.image) -> bool
def match(self, node: nodes.image) -> bool:
if self.available is None:
self.available = self.is_available()
@ -219,8 +205,7 @@ class ImageConverter(BaseImageConverter):
else:
return False
def get_conversion_rule(self, node):
# type: (nodes.image) -> Tuple[str, str]
def get_conversion_rule(self, node: nodes.image) -> Tuple[str, str]:
for candidate in self.guess_mimetypes(node):
for supported in self.app.builder.supported_image_types:
rule = (candidate, supported)
@ -229,13 +214,11 @@ class ImageConverter(BaseImageConverter):
return None
def is_available(self):
# type: () -> bool
def is_available(self) -> bool:
"""Return the image converter is available or not."""
raise NotImplementedError()
def guess_mimetypes(self, node):
# type: (nodes.image) -> List[str]
def guess_mimetypes(self, node: nodes.image) -> List[str]:
if '?' in node['candidates']:
return []
elif '*' in node['candidates']:
@ -244,8 +227,7 @@ class ImageConverter(BaseImageConverter):
else:
return node['candidates'].keys()
def handle(self, node):
# type: (nodes.image) -> None
def handle(self, node: nodes.image) -> None:
_from, _to = self.get_conversion_rule(node)
if _from in node['candidates']:
@ -268,8 +250,7 @@ class ImageConverter(BaseImageConverter):
self.env.original_image_uri[destpath] = srcpath
self.env.images.add_file(self.env.docname, destpath)
def convert(self, _from, _to):
# type: (str, str) -> bool
def convert(self, _from: str, _to: str) -> bool:
"""Convert a image file to expected format.
*_from* is a path for source image file, and *_to* is a path for
@ -278,8 +259,7 @@ class ImageConverter(BaseImageConverter):
raise NotImplementedError()
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: Sphinx) -> Dict[str, Any]:
app.add_post_transform(ImageDownloader)
app.add_post_transform(DataURIExtractor)

View File

@ -8,6 +8,8 @@
:license: BSD, see LICENSE for details.
"""
from typing import Any, Dict
from docutils import nodes
from docutils.transforms.references import DanglingReferences, Substitutions
@ -15,8 +17,7 @@ from sphinx.transforms import SphinxTransform
if False:
# For type annotation
from typing import Any, Dict # NOQA
from sphinx.application import Sphinx # NOQA
from sphinx.application import Sphinx
class SubstitutionDefinitionsRemover(SphinxTransform):
@ -25,8 +26,7 @@ class SubstitutionDefinitionsRemover(SphinxTransform):
# should be invoked after Substitutions process
default_priority = Substitutions.default_priority + 1
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for node in self.document.traverse(nodes.substitution_definition):
node.parent.remove(node)
@ -34,8 +34,7 @@ class SubstitutionDefinitionsRemover(SphinxTransform):
class SphinxDanglingReferences(DanglingReferences):
"""DanglingReferences transform which does not output info messages."""
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
try:
reporter = self.document.reporter
report_level = reporter.report_level
@ -51,14 +50,12 @@ class SphinxDomains(SphinxTransform):
"""Collect objects to Sphinx domains for cross references."""
default_priority = 850
def apply(self, **kwargs):
# type: (Any) -> None
def apply(self, **kwargs) -> None:
for domain in self.env.domains.values():
domain.process_doc(self.env, self.env.docname, self.document)
def setup(app):
# type: (Sphinx) -> Dict[str, Any]
def setup(app: "Sphinx") -> Dict[str, Any]:
app.add_transform(SubstitutionDefinitionsRemover)
app.add_transform(SphinxDanglingReferences)
app.add_transform(SphinxDomains)

View File

@ -98,7 +98,7 @@ def skip_if_stylefiles_notfound(testfunc):
@pytest.mark.sphinx('latex')
def test_build_latex_doc(app, status, warning, engine, docclass):
app.config.latex_engine = engine
app.config.latex_documents[0] = app.config.latex_documents[0][:4] + (docclass,)
app.config.latex_documents = [app.config.latex_documents[0][:4] + (docclass,)]
app.builder.init_context()
LaTeXTranslator.ignore_missing_images = True

View File

@ -334,6 +334,16 @@ def test_member_definitions():
check('member', 'thread_local extern int myInt', {1: 'myInt__i', 2: '5myInt'},
'extern thread_local int myInt')
# tests based on https://en.cppreference.com/w/cpp/language/bit_field
check('member', 'int b : 3', {1: 'b__i', 2: '1b'})
check('member', 'int b : 8 = 42', {1: 'b__i', 2: '1b'})
check('member', 'int b : 8{42}', {1: 'b__i', 2: '1b'})
# TODO: enable once the ternary operator is supported
#check('member', 'int b : true ? 8 : a = 42', {1: 'b__i', 2: '1b'})
# TODO: enable once the ternary operator is supported
#check('member', 'int b : (true ? 8 : a) = 42', {1: 'b__i', 2: '1b'})
check('member', 'int b : 1 || new int{0}', {1: 'b__i', 2: '1b'})
def test_function_definitions():
check('function', 'void f(volatile int)', {1: "f__iV", 2: "1fVi"})