mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge branch '2.0'
This commit is contained in:
commit
618cc26c64
5
CHANGES
5
CHANGES
@ -48,6 +48,8 @@ Deprecated
|
|||||||
Features added
|
Features added
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
* #6707: C++, support bit-fields.
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@ -56,6 +58,9 @@ Bugs fixed
|
|||||||
|
|
||||||
.. _latex3/latex2e#173: https://github.com/latex3/latex2e/issues/173
|
.. _latex3/latex2e#173: https://github.com/latex3/latex2e/issues/173
|
||||||
* #6618: LaTeX: Avoid section names at the end of a page
|
* #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
|
||||||
|
|
||||||
Testing
|
Testing
|
||||||
--------
|
--------
|
||||||
|
@ -237,13 +237,16 @@ class CheckExternalLinksBuilder(Builder):
|
|||||||
else:
|
else:
|
||||||
logger.info(red('broken ') + uri + red(' - ' + info))
|
logger.info(red('broken ') + uri + red(' - ' + info))
|
||||||
elif status == 'redirected':
|
elif status == 'redirected':
|
||||||
text, color = {
|
try:
|
||||||
301: ('permanently', darkred),
|
text, color = {
|
||||||
302: ('with Found', purple),
|
301: ('permanently', darkred),
|
||||||
303: ('with See Other', purple),
|
302: ('with Found', purple),
|
||||||
307: ('temporarily', turquoise),
|
303: ('with See Other', purple),
|
||||||
0: ('with unknown code', purple),
|
307: ('temporarily', turquoise),
|
||||||
}[code]
|
0: ('with unknown code', purple),
|
||||||
|
}[code]
|
||||||
|
except KeyError:
|
||||||
|
text, color = ('with unknown code', purple)
|
||||||
self.write_entry('redirected ' + text, docname, lineno,
|
self.write_entry('redirected ' + text, docname, lineno,
|
||||||
uri + ' to ' + info)
|
uri + ' to ' + info)
|
||||||
logger.info(color('redirect ') + uri + color(' - ' + text + ' to ' + info))
|
logger.info(color('redirect ') + uri + color(' - ' + text + ' to ' + info))
|
||||||
|
@ -3191,6 +3191,52 @@ class ASTDeclaratorNameParamQual(ASTBase):
|
|||||||
self.paramQual.describe_signature(signode, mode, env, symbol)
|
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):
|
class ASTParenExprList(ASTBase):
|
||||||
def __init__(self, exprs):
|
def __init__(self, exprs):
|
||||||
# type: (List[Any]) -> None
|
# type: (List[Any]) -> None
|
||||||
@ -5716,8 +5762,12 @@ class DefinitionParser:
|
|||||||
trailing = None
|
trailing = None
|
||||||
return ASTDeclSpecs(outer, leftSpecs, rightSpecs, trailing)
|
return ASTDeclSpecs(outer, leftSpecs, rightSpecs, trailing)
|
||||||
|
|
||||||
def _parse_declarator_name_param_qual(self, named, paramMode, typed):
|
def _parse_declarator_name_suffix(self,
|
||||||
# type: (Union[bool, str], str, bool) -> ASTDeclaratorNameParamQual
|
named, # type: Union[bool, str]
|
||||||
|
paramMode, # type: str
|
||||||
|
typed # type: bool
|
||||||
|
):
|
||||||
|
# type: (...) -> Union[ASTDeclaratorNameParamQual, ASTDeclaratorNameBitField]
|
||||||
# now we should parse the name, and then suffixes
|
# now we should parse the name, and then suffixes
|
||||||
if named == 'maybe':
|
if named == 'maybe':
|
||||||
pos = self.pos
|
pos = self.pos
|
||||||
@ -5760,6 +5810,13 @@ class DefinitionParser:
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
paramQual = self._parse_parameters_and_qualifiers(paramMode)
|
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,
|
return ASTDeclaratorNameParamQual(declId=declId, arrayOps=arrayOps,
|
||||||
paramQual=paramQual)
|
paramQual=paramQual)
|
||||||
|
|
||||||
@ -5842,8 +5899,8 @@ class DefinitionParser:
|
|||||||
pos = self.pos
|
pos = self.pos
|
||||||
try:
|
try:
|
||||||
# assume this is params and quals
|
# assume this is params and quals
|
||||||
res = self._parse_declarator_name_param_qual(named, paramMode,
|
res = self._parse_declarator_name_suffix(named, paramMode,
|
||||||
typed)
|
typed)
|
||||||
return res
|
return res
|
||||||
except DefinitionError as exParamQual:
|
except DefinitionError as exParamQual:
|
||||||
prevErrors.append((exParamQual, "If declId, parameters, and qualifiers"))
|
prevErrors.append((exParamQual, "If declId, parameters, and qualifiers"))
|
||||||
@ -5868,7 +5925,7 @@ class DefinitionParser:
|
|||||||
raise self._make_multi_error(prevErrors, header)
|
raise self._make_multi_error(prevErrors, header)
|
||||||
pos = self.pos
|
pos = self.pos
|
||||||
try:
|
try:
|
||||||
return self._parse_declarator_name_param_qual(named, paramMode, typed)
|
return self._parse_declarator_name_suffix(named, paramMode, typed)
|
||||||
except DefinitionError as e:
|
except DefinitionError as e:
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
prevErrors.append((e, "If declarator-id"))
|
prevErrors.append((e, "If declarator-id"))
|
||||||
|
@ -338,7 +338,7 @@ msgstr "%r भूमिका पहले से अधिकार-क्ष
|
|||||||
#: sphinx/registry.py:226
|
#: sphinx/registry.py:226
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The %r index is already registered to domain %s"
|
msgid "The %r index is already registered to domain %s"
|
||||||
msgstr "r% अनुक्रमणिका पहले से अधिकार-क्षेत्र %s में पंजीकृत है"
|
msgstr "%r अनुक्रमणिका पहले से अधिकार-क्षेत्र %s में पंजीकृत है"
|
||||||
|
|
||||||
#: sphinx/registry.py:250
|
#: sphinx/registry.py:250
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -9,8 +9,10 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
from typing import Any, Dict, Generator, List, Tuple
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
from docutils.nodes import Element, Node, Text
|
||||||
from docutils.transforms import Transform, Transformer
|
from docutils.transforms import Transform, Transformer
|
||||||
from docutils.transforms.parts import ContentsFilter
|
from docutils.transforms.parts import ContentsFilter
|
||||||
from docutils.transforms.universal import SmartQuotes
|
from docutils.transforms.universal import SmartQuotes
|
||||||
@ -18,6 +20,7 @@ from docutils.utils import normalize_language_tag
|
|||||||
from docutils.utils.smartquotes import smartchars
|
from docutils.utils.smartquotes import smartchars
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
|
from sphinx.config import Config
|
||||||
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
from sphinx.deprecation import RemovedInSphinx40Warning, deprecated_alias
|
||||||
from sphinx.locale import _, __
|
from sphinx.locale import _, __
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
@ -27,11 +30,9 @@ from sphinx.util.nodes import NodeMatcher, apply_source_workaround, is_smartquot
|
|||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
from typing import Any, Dict, Generator, List, Tuple # NOQA
|
from sphinx.application import Sphinx
|
||||||
from sphinx.application import Sphinx # NOQA
|
from sphinx.domain.std import StandardDomain
|
||||||
from sphinx.config import Config # NOQA
|
from sphinx.environment import BuildEnvironment
|
||||||
from sphinx.domain.std import StandardDomain # NOQA
|
|
||||||
from sphinx.environment import BuildEnvironment # NOQA
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -51,20 +52,17 @@ class SphinxTransform(Transform):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def app(self):
|
def app(self) -> "Sphinx":
|
||||||
# type: () -> Sphinx
|
|
||||||
"""Reference to the :class:`.Sphinx` object."""
|
"""Reference to the :class:`.Sphinx` object."""
|
||||||
return self.env.app
|
return self.env.app
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def env(self):
|
def env(self) -> "BuildEnvironment":
|
||||||
# type: () -> BuildEnvironment
|
|
||||||
"""Reference to the :class:`.BuildEnvironment` object."""
|
"""Reference to the :class:`.BuildEnvironment` object."""
|
||||||
return self.document.settings.env
|
return self.document.settings.env
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def config(self):
|
def config(self) -> Config:
|
||||||
# type: () -> Config
|
|
||||||
"""Reference to the :class:`.Config` object."""
|
"""Reference to the :class:`.Config` object."""
|
||||||
return self.env.config
|
return self.env.config
|
||||||
|
|
||||||
@ -77,12 +75,10 @@ class SphinxTransformer(Transformer):
|
|||||||
document = None # type: nodes.document
|
document = None # type: nodes.document
|
||||||
env = None # type: BuildEnvironment
|
env = None # type: BuildEnvironment
|
||||||
|
|
||||||
def set_environment(self, env):
|
def set_environment(self, env: "BuildEnvironment") -> None:
|
||||||
# type: (BuildEnvironment) -> None
|
|
||||||
self.env = env
|
self.env = env
|
||||||
|
|
||||||
def apply_transforms(self):
|
def apply_transforms(self) -> None:
|
||||||
# type: () -> None
|
|
||||||
if isinstance(self.document, nodes.document):
|
if isinstance(self.document, nodes.document):
|
||||||
if not hasattr(self.document.settings, 'env') and self.env:
|
if not hasattr(self.document.settings, 'env') and self.env:
|
||||||
self.document.settings.env = self.env
|
self.document.settings.env = self.env
|
||||||
@ -108,8 +104,7 @@ class DefaultSubstitutions(SphinxTransform):
|
|||||||
# run before the default Substitutions
|
# run before the default Substitutions
|
||||||
default_priority = 210
|
default_priority = 210
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
# only handle those not otherwise defined in the document
|
# only handle those not otherwise defined in the document
|
||||||
to_handle = default_substitutions - set(self.document.substitution_defs)
|
to_handle = default_substitutions - set(self.document.substitution_defs)
|
||||||
for ref in self.document.traverse(nodes.substitution_reference):
|
for ref in self.document.traverse(nodes.substitution_reference):
|
||||||
@ -132,8 +127,7 @@ class MoveModuleTargets(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 210
|
default_priority = 210
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(nodes.target):
|
for node in self.document.traverse(nodes.target):
|
||||||
if not node['ids']:
|
if not node['ids']:
|
||||||
continue
|
continue
|
||||||
@ -151,8 +145,7 @@ class HandleCodeBlocks(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 210
|
default_priority = 210
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
# move doctest blocks out of blockquotes
|
# move doctest blocks out of blockquotes
|
||||||
for node in self.document.traverse(nodes.block_quote):
|
for node in self.document.traverse(nodes.block_quote):
|
||||||
if all(isinstance(child, nodes.doctest_block) for child
|
if all(isinstance(child, nodes.doctest_block) for child
|
||||||
@ -176,8 +169,7 @@ class AutoNumbering(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 210
|
default_priority = 210
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
domain = self.env.get_domain('std') # type: StandardDomain
|
domain = self.env.get_domain('std') # type: StandardDomain
|
||||||
|
|
||||||
for node in self.document.traverse(nodes.Element):
|
for node in self.document.traverse(nodes.Element):
|
||||||
@ -191,8 +183,7 @@ class SortIds(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 261
|
default_priority = 261
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(nodes.section):
|
for node in self.document.traverse(nodes.section):
|
||||||
if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
|
if len(node['ids']) > 1 and node['ids'][0].startswith('id'):
|
||||||
node['ids'] = node['ids'][1:] + [node['ids'][0]]
|
node['ids'] = node['ids'][1:] + [node['ids'][0]]
|
||||||
@ -213,9 +204,8 @@ class ApplySourceWorkaround(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 10
|
default_priority = 10
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
for node in self.document.traverse(): # type: Node
|
||||||
for node in self.document.traverse(): # type: nodes.Node
|
|
||||||
if isinstance(node, (nodes.TextElement, nodes.image)):
|
if isinstance(node, (nodes.TextElement, nodes.image)):
|
||||||
apply_source_workaround(node)
|
apply_source_workaround(node)
|
||||||
|
|
||||||
@ -226,8 +216,7 @@ class AutoIndexUpgrader(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 210
|
default_priority = 210
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(addnodes.index):
|
for node in self.document.traverse(addnodes.index):
|
||||||
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
|
if 'entries' in node and any(len(entry) == 4 for entry in node['entries']):
|
||||||
msg = __('4 column based index found. '
|
msg = __('4 column based index found. '
|
||||||
@ -244,18 +233,16 @@ class ExtraTranslatableNodes(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 10
|
default_priority = 10
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
targets = self.config.gettext_additional_targets
|
targets = self.config.gettext_additional_targets
|
||||||
target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
|
target_nodes = [v for k, v in TRANSLATABLE_NODES.items() if k in targets]
|
||||||
if not target_nodes:
|
if not target_nodes:
|
||||||
return
|
return
|
||||||
|
|
||||||
def is_translatable_node(node):
|
def is_translatable_node(node: Node) -> bool:
|
||||||
# type: (nodes.Node) -> bool
|
|
||||||
return isinstance(node, tuple(target_nodes))
|
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
|
node['translatable'] = True
|
||||||
|
|
||||||
|
|
||||||
@ -265,8 +252,7 @@ class UnreferencedFootnotesDetector(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 200
|
default_priority = 200
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.footnotes:
|
for node in self.document.footnotes:
|
||||||
if node['names'] == []:
|
if node['names'] == []:
|
||||||
# footnote having duplicated number. It is already warned at parser.
|
# footnote having duplicated number. It is already warned at parser.
|
||||||
@ -289,10 +275,9 @@ class FigureAligner(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 700
|
default_priority = 700
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
matcher = NodeMatcher(nodes.table, nodes.figure)
|
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')
|
node.setdefault('align', 'default')
|
||||||
|
|
||||||
|
|
||||||
@ -300,8 +285,7 @@ class FilterSystemMessages(SphinxTransform):
|
|||||||
"""Filter system messages from a doctree."""
|
"""Filter system messages from a doctree."""
|
||||||
default_priority = 999
|
default_priority = 999
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
filterlevel = self.config.keep_warnings and 2 or 5
|
filterlevel = self.config.keep_warnings and 2 or 5
|
||||||
for node in self.document.traverse(nodes.system_message):
|
for node in self.document.traverse(nodes.system_message):
|
||||||
if node['level'] < filterlevel:
|
if node['level'] < filterlevel:
|
||||||
@ -316,8 +300,7 @@ class SphinxContentsFilter(ContentsFilter):
|
|||||||
"""
|
"""
|
||||||
visit_pending_xref = ContentsFilter.ignore_node_but_process_children
|
visit_pending_xref = ContentsFilter.ignore_node_but_process_children
|
||||||
|
|
||||||
def visit_image(self, node):
|
def visit_image(self, node: nodes.image) -> None:
|
||||||
# type: (nodes.image) -> None
|
|
||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
|
|
||||||
|
|
||||||
@ -329,8 +312,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 750
|
default_priority = 750
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
if not self.is_available():
|
if not self.is_available():
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -339,8 +321,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
|
|||||||
|
|
||||||
super().apply()
|
super().apply()
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self) -> bool:
|
||||||
# type: () -> bool
|
|
||||||
builders = self.config.smartquotes_excludes.get('builders', [])
|
builders = self.config.smartquotes_excludes.get('builders', [])
|
||||||
languages = self.config.smartquotes_excludes.get('languages', [])
|
languages = self.config.smartquotes_excludes.get('languages', [])
|
||||||
|
|
||||||
@ -365,8 +346,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_tokens(self, txtnodes):
|
def get_tokens(self, txtnodes: List[Text]) -> Generator[Tuple[str, str], None, None]:
|
||||||
# type: (List[nodes.Text]) -> Generator[Tuple[str, str], None, None]
|
|
||||||
# A generator that yields ``(texttype, nodetext)`` tuples for a list
|
# A generator that yields ``(texttype, nodetext)`` tuples for a list
|
||||||
# of "Text" nodes (interface to ``smartquotes.educate_tokens()``).
|
# of "Text" nodes (interface to ``smartquotes.educate_tokens()``).
|
||||||
|
|
||||||
@ -381,8 +361,7 @@ class DoctreeReadEvent(SphinxTransform):
|
|||||||
"""Emit :event:`doctree-read` event."""
|
"""Emit :event:`doctree-read` event."""
|
||||||
default_priority = 880
|
default_priority = 880
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
self.app.emit('doctree-read', self.document)
|
self.app.emit('doctree-read', self.document)
|
||||||
|
|
||||||
|
|
||||||
@ -390,8 +369,7 @@ class ManpageLink(SphinxTransform):
|
|||||||
"""Find manpage section numbers and names"""
|
"""Find manpage section numbers and names"""
|
||||||
default_priority = 999
|
default_priority = 999
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(addnodes.manpage):
|
for node in self.document.traverse(addnodes.manpage):
|
||||||
manpage = ' '.join([str(x) for x in node.children
|
manpage = ' '.join([str(x) for x in node.children
|
||||||
if isinstance(x, nodes.Text)])
|
if isinstance(x, nodes.Text)])
|
||||||
@ -417,8 +395,7 @@ deprecated_alias('sphinx.transforms',
|
|||||||
RemovedInSphinx40Warning)
|
RemovedInSphinx40Warning)
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_transform(ApplySourceWorkaround)
|
app.add_transform(ApplySourceWorkaround)
|
||||||
app.add_transform(ExtraTranslatableNodes)
|
app.add_transform(ExtraTranslatableNodes)
|
||||||
app.add_transform(DefaultSubstitutions)
|
app.add_transform(DefaultSubstitutions)
|
||||||
|
@ -8,18 +8,16 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Any, Dict, List
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
from docutils.nodes import Node
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
|
from sphinx.application import Sphinx
|
||||||
from sphinx.transforms import SphinxTransform
|
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):
|
class RefOnlyListChecker(nodes.GenericNodeVisitor):
|
||||||
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
|
"""Raise `nodes.NodeFound` if non-simple list item is encountered.
|
||||||
@ -28,17 +26,14 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
|
|||||||
single reference in it.
|
single reference in it.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def default_visit(self, node):
|
def default_visit(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
raise nodes.NodeFound
|
raise nodes.NodeFound
|
||||||
|
|
||||||
def visit_bullet_list(self, node):
|
def visit_bullet_list(self, node: nodes.bullet_list) -> None:
|
||||||
# type: (nodes.bullet_list) -> None
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def visit_list_item(self, node):
|
def visit_list_item(self, node: nodes.list_item) -> None:
|
||||||
# type: (nodes.list_item) -> None
|
children = [] # type: List[Node]
|
||||||
children = [] # type: List[nodes.Node]
|
|
||||||
for child in node.children:
|
for child in node.children:
|
||||||
if not isinstance(child, nodes.Invisible):
|
if not isinstance(child, nodes.Invisible):
|
||||||
children.append(child)
|
children.append(child)
|
||||||
@ -53,8 +48,7 @@ class RefOnlyListChecker(nodes.GenericNodeVisitor):
|
|||||||
raise nodes.NodeFound
|
raise nodes.NodeFound
|
||||||
raise nodes.SkipChildren
|
raise nodes.SkipChildren
|
||||||
|
|
||||||
def invisible_visit(self, node):
|
def invisible_visit(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
"""Invisible nodes should be ignored."""
|
"""Invisible nodes should be ignored."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -67,13 +61,11 @@ class RefOnlyBulletListTransform(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 100
|
default_priority = 100
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
if self.config.html_compact_lists:
|
if self.config.html_compact_lists:
|
||||||
return
|
return
|
||||||
|
|
||||||
def check_refonly_list(node):
|
def check_refonly_list(node: Node) -> bool:
|
||||||
# type: (nodes.Node) -> bool
|
|
||||||
"""Check for list with only references in it."""
|
"""Check for list with only references in it."""
|
||||||
visitor = RefOnlyListChecker(self.document)
|
visitor = RefOnlyListChecker(self.document)
|
||||||
try:
|
try:
|
||||||
@ -93,8 +85,7 @@ class RefOnlyBulletListTransform(SphinxTransform):
|
|||||||
item.replace(para, compact_para)
|
item.replace(para, compact_para)
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_transform(RefOnlyBulletListTransform)
|
app.add_transform(RefOnlyBulletListTransform)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -10,13 +10,15 @@
|
|||||||
|
|
||||||
from os import path
|
from os import path
|
||||||
from textwrap import indent
|
from textwrap import indent
|
||||||
from typing import Any, TypeVar
|
from typing import Any, Dict, List, Tuple, TypeVar
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.io import StringInput
|
from docutils.io import StringInput
|
||||||
|
from docutils.nodes import Element
|
||||||
from docutils.utils import relative_path
|
from docutils.utils import relative_path
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
|
from sphinx.config import Config
|
||||||
from sphinx.domains.std import make_glossary_term, split_term_classifiers
|
from sphinx.domains.std import make_glossary_term, split_term_classifiers
|
||||||
from sphinx.locale import __, init as init_locale
|
from sphinx.locale import __, init as init_locale
|
||||||
from sphinx.transforms import SphinxTransform
|
from sphinx.transforms import SphinxTransform
|
||||||
@ -29,18 +31,17 @@ from sphinx.util.nodes import (
|
|||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
from typing import Dict, List, Tuple # NOQA
|
|
||||||
from typing import Type # for python3.5.1
|
from typing import Type # for python3.5.1
|
||||||
from sphinx.application import Sphinx # NOQA
|
from sphinx.application import Sphinx
|
||||||
from sphinx.config import Config # NOQA
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
N = TypeVar('N', bound=nodes.Node)
|
N = TypeVar('N', bound=nodes.Node)
|
||||||
|
|
||||||
|
|
||||||
def publish_msgstr(app, source, source_path, source_line, config, settings):
|
def publish_msgstr(app: "Sphinx", source: str, source_path: str, source_line: int,
|
||||||
# type: (Sphinx, str, str, int, Config, Any) -> nodes.Element
|
config: Config, settings: Any) -> Element:
|
||||||
"""Publish msgstr (single line) into docutils document
|
"""Publish msgstr (single line) into docutils document
|
||||||
|
|
||||||
:param sphinx.application.Sphinx app: sphinx application
|
:param sphinx.application.Sphinx app: sphinx application
|
||||||
@ -75,8 +76,7 @@ class PreserveTranslatableMessages(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 10 # this MUST be invoked before Locale transform
|
default_priority = 10 # this MUST be invoked before Locale transform
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(addnodes.translatable):
|
for node in self.document.traverse(addnodes.translatable):
|
||||||
node.preserve_original_messages()
|
node.preserve_original_messages()
|
||||||
|
|
||||||
@ -87,8 +87,7 @@ class Locale(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 20
|
default_priority = 20
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
settings, source = self.document.settings, self.document['source']
|
settings, source = self.document.settings, self.document['source']
|
||||||
msgstr = ''
|
msgstr = ''
|
||||||
|
|
||||||
@ -268,7 +267,7 @@ class Locale(SphinxTransform):
|
|||||||
unexpected = (
|
unexpected = (
|
||||||
nodes.paragraph, # expected form of translation
|
nodes.paragraph, # expected form of translation
|
||||||
nodes.title # generated by above "Subelements phase2"
|
nodes.title # generated by above "Subelements phase2"
|
||||||
) # type: Tuple[Type[nodes.Element], ...]
|
) # type: Tuple[Type[Element], ...]
|
||||||
|
|
||||||
# following types are expected if
|
# following types are expected if
|
||||||
# config.gettext_additional_targets is configured
|
# config.gettext_additional_targets is configured
|
||||||
@ -279,8 +278,7 @@ class Locale(SphinxTransform):
|
|||||||
continue # skip
|
continue # skip
|
||||||
|
|
||||||
# auto-numbered foot note reference should use original 'ids'.
|
# auto-numbered foot note reference should use original 'ids'.
|
||||||
def list_replace_or_append(lst, old, new):
|
def list_replace_or_append(lst: List[N], old: N, new: N) -> None:
|
||||||
# type: (List[N], N, N) -> None
|
|
||||||
if old in lst:
|
if old in lst:
|
||||||
lst[lst.index(old)] = new
|
lst[lst.index(old)] = new
|
||||||
else:
|
else:
|
||||||
@ -406,8 +404,7 @@ class Locale(SphinxTransform):
|
|||||||
.format(old_xref_rawsources, new_xref_rawsources),
|
.format(old_xref_rawsources, new_xref_rawsources),
|
||||||
location=node)
|
location=node)
|
||||||
|
|
||||||
def get_ref_key(node):
|
def get_ref_key(node: addnodes.pending_xref) -> Tuple[str, str, str]:
|
||||||
# type: (addnodes.pending_xref) -> Tuple[str, str, str]
|
|
||||||
case = node["refdomain"], node["reftype"]
|
case = node["refdomain"], node["reftype"]
|
||||||
if case == ('std', 'term'):
|
if case == ('std', 'term'):
|
||||||
return None
|
return None
|
||||||
@ -465,7 +462,7 @@ class Locale(SphinxTransform):
|
|||||||
node['entries'] = new_entries
|
node['entries'] = new_entries
|
||||||
|
|
||||||
# remove translated attribute that is used for avoiding double translation.
|
# 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')
|
translated.delattr('translated')
|
||||||
|
|
||||||
|
|
||||||
@ -475,8 +472,7 @@ class RemoveTranslatableInline(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 999
|
default_priority = 999
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
from sphinx.builders.gettext import MessageCatalogBuilder
|
from sphinx.builders.gettext import MessageCatalogBuilder
|
||||||
if isinstance(self.app.builder, MessageCatalogBuilder):
|
if isinstance(self.app.builder, MessageCatalogBuilder):
|
||||||
return
|
return
|
||||||
@ -487,8 +483,7 @@ class RemoveTranslatableInline(SphinxTransform):
|
|||||||
inline.parent += inline.children
|
inline.parent += inline.children
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_transform(PreserveTranslatableMessages)
|
app.add_transform(PreserveTranslatableMessages)
|
||||||
app.add_transform(Locale)
|
app.add_transform(Locale)
|
||||||
app.add_transform(RemoveTranslatableInline)
|
app.add_transform(RemoveTranslatableInline)
|
||||||
|
@ -8,23 +8,22 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Any, Dict, List, Tuple
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
from docutils.nodes import Element
|
||||||
|
|
||||||
from sphinx import addnodes
|
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.errors import NoUri
|
||||||
from sphinx.locale import __
|
from sphinx.locale import __
|
||||||
from sphinx.transforms import SphinxTransform
|
from sphinx.transforms import SphinxTransform
|
||||||
from sphinx.util import logging
|
from sphinx.util import logging
|
||||||
from sphinx.util.nodes import process_only_nodes
|
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__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -39,13 +38,11 @@ class SphinxPostTransform(SphinxTransform):
|
|||||||
builders = () # type: Tuple[str, ...]
|
builders = () # type: Tuple[str, ...]
|
||||||
formats = () # type: Tuple[str, ...]
|
formats = () # type: Tuple[str, ...]
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
if self.is_supported():
|
if self.is_supported():
|
||||||
self.run(**kwargs)
|
self.run(**kwargs)
|
||||||
|
|
||||||
def is_supported(self):
|
def is_supported(self) -> bool:
|
||||||
# type: () -> bool
|
|
||||||
"""Check this transform working for current builder."""
|
"""Check this transform working for current builder."""
|
||||||
if self.builders and self.app.builder.name not in self.builders:
|
if self.builders and self.app.builder.name not in self.builders:
|
||||||
return False
|
return False
|
||||||
@ -54,8 +51,7 @@ class SphinxPostTransform(SphinxTransform):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def run(self, **kwargs):
|
def run(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
"""main method of post transforms.
|
"""main method of post transforms.
|
||||||
|
|
||||||
Subclasses should override this method instead of ``apply()``.
|
Subclasses should override this method instead of ``apply()``.
|
||||||
@ -70,8 +66,7 @@ class ReferencesResolver(SphinxPostTransform):
|
|||||||
|
|
||||||
default_priority = 10
|
default_priority = 10
|
||||||
|
|
||||||
def run(self, **kwargs):
|
def run(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(addnodes.pending_xref):
|
for node in self.document.traverse(addnodes.pending_xref):
|
||||||
contnode = cast(nodes.TextElement, node[0].deepcopy())
|
contnode = cast(nodes.TextElement, node[0].deepcopy())
|
||||||
newnode = None
|
newnode = None
|
||||||
@ -105,12 +100,11 @@ class ReferencesResolver(SphinxPostTransform):
|
|||||||
newnode = contnode
|
newnode = contnode
|
||||||
node.replace_self(newnode or contnode)
|
node.replace_self(newnode or contnode)
|
||||||
|
|
||||||
def resolve_anyref(self, refdoc, node, contnode):
|
def resolve_anyref(self, refdoc: str, node: pending_xref, contnode: Element) -> Element:
|
||||||
# type: (str, addnodes.pending_xref, nodes.TextElement) -> nodes.Element
|
|
||||||
"""Resolve reference generated by the "any" role."""
|
"""Resolve reference generated by the "any" role."""
|
||||||
stddomain = self.env.get_domain('std')
|
stddomain = self.env.get_domain('std')
|
||||||
target = node['reftarget']
|
target = node['reftarget']
|
||||||
results = [] # type: List[Tuple[str, nodes.Element]]
|
results = [] # type: List[Tuple[str, Element]]
|
||||||
# first, try resolving as :doc:
|
# first, try resolving as :doc:
|
||||||
doc_ref = stddomain.resolve_xref(self.env, refdoc, self.app.builder,
|
doc_ref = stddomain.resolve_xref(self.env, refdoc, self.app.builder,
|
||||||
'doc', target, node, contnode)
|
'doc', target, node, contnode)
|
||||||
@ -155,8 +149,8 @@ class ReferencesResolver(SphinxPostTransform):
|
|||||||
newnode[0]['classes'].append(res_role.replace(':', '-'))
|
newnode[0]['classes'].append(res_role.replace(':', '-'))
|
||||||
return newnode
|
return newnode
|
||||||
|
|
||||||
def warn_missing_reference(self, refdoc, typ, target, node, domain):
|
def warn_missing_reference(self, refdoc: str, typ: str, target: str,
|
||||||
# type: (str, str, str, addnodes.pending_xref, Domain) -> None
|
node: pending_xref, domain: Domain) -> None:
|
||||||
warn = node.get('refwarn')
|
warn = node.get('refwarn')
|
||||||
if self.config.nitpicky:
|
if self.config.nitpicky:
|
||||||
warn = True
|
warn = True
|
||||||
@ -184,8 +178,7 @@ class ReferencesResolver(SphinxPostTransform):
|
|||||||
class OnlyNodeTransform(SphinxPostTransform):
|
class OnlyNodeTransform(SphinxPostTransform):
|
||||||
default_priority = 50
|
default_priority = 50
|
||||||
|
|
||||||
def run(self, **kwargs):
|
def run(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
# A comment on the comment() nodes being inserted: replacing by [] would
|
# A comment on the comment() nodes being inserted: replacing by [] would
|
||||||
# result in a "Losing ids" exception if there is a target node before
|
# 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
|
# 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)
|
process_only_nodes(self.document, self.app.builder.tags)
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_post_transform(ReferencesResolver)
|
app.add_post_transform(ReferencesResolver)
|
||||||
app.add_post_transform(OnlyNodeTransform)
|
app.add_post_transform(OnlyNodeTransform)
|
||||||
|
|
||||||
|
@ -9,20 +9,17 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from typing import NamedTuple, Union
|
from typing import Any, Dict, List, NamedTuple, Union
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
from docutils.nodes import Node
|
||||||
from pygments.lexers import PythonConsoleLexer, guess_lexer
|
from pygments.lexers import PythonConsoleLexer, guess_lexer
|
||||||
|
|
||||||
from sphinx import addnodes
|
from sphinx import addnodes
|
||||||
|
from sphinx.application import Sphinx
|
||||||
from sphinx.ext import doctest
|
from sphinx.ext import doctest
|
||||||
from sphinx.transforms import SphinxTransform
|
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),
|
HighlightSetting = NamedTuple('HighlightSetting', [('language', str),
|
||||||
('force', bool),
|
('force', bool),
|
||||||
@ -39,8 +36,7 @@ class HighlightLanguageTransform(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = 400
|
default_priority = 400
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
visitor = HighlightLanguageVisitor(self.document,
|
visitor = HighlightLanguageVisitor(self.document,
|
||||||
self.config.highlight_language)
|
self.config.highlight_language)
|
||||||
self.document.walkabout(visitor)
|
self.document.walkabout(visitor)
|
||||||
@ -50,44 +46,35 @@ class HighlightLanguageTransform(SphinxTransform):
|
|||||||
|
|
||||||
|
|
||||||
class HighlightLanguageVisitor(nodes.NodeVisitor):
|
class HighlightLanguageVisitor(nodes.NodeVisitor):
|
||||||
def __init__(self, document, default_language):
|
def __init__(self, document: nodes.document, default_language: str) -> None:
|
||||||
# type: (nodes.document, str) -> None
|
|
||||||
self.default_setting = HighlightSetting(default_language, False, sys.maxsize)
|
self.default_setting = HighlightSetting(default_language, False, sys.maxsize)
|
||||||
self.settings = [] # type: List[HighlightSetting]
|
self.settings = [] # type: List[HighlightSetting]
|
||||||
super().__init__(document)
|
super().__init__(document)
|
||||||
|
|
||||||
def unknown_visit(self, node):
|
def unknown_visit(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def unknown_departure(self, node):
|
def unknown_departure(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def visit_document(self, node):
|
def visit_document(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
self.settings.append(self.default_setting)
|
self.settings.append(self.default_setting)
|
||||||
|
|
||||||
def depart_document(self, node):
|
def depart_document(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
self.settings.pop()
|
self.settings.pop()
|
||||||
|
|
||||||
def visit_start_of_file(self, node):
|
def visit_start_of_file(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
self.settings.append(self.default_setting)
|
self.settings.append(self.default_setting)
|
||||||
|
|
||||||
def depart_start_of_file(self, node):
|
def depart_start_of_file(self, node: Node) -> None:
|
||||||
# type: (nodes.Node) -> None
|
|
||||||
self.settings.pop()
|
self.settings.pop()
|
||||||
|
|
||||||
def visit_highlightlang(self, node):
|
def visit_highlightlang(self, node: addnodes.highlightlang) -> None:
|
||||||
# type: (addnodes.highlightlang) -> None
|
|
||||||
self.settings[-1] = HighlightSetting(node['lang'],
|
self.settings[-1] = HighlightSetting(node['lang'],
|
||||||
node['force'],
|
node['force'],
|
||||||
node['linenothreshold'])
|
node['linenothreshold'])
|
||||||
|
|
||||||
def visit_literal_block(self, node):
|
def visit_literal_block(self, node: nodes.literal_block) -> None:
|
||||||
# type: (nodes.literal_block) -> None
|
|
||||||
setting = self.settings[-1]
|
setting = self.settings[-1]
|
||||||
if 'language' not in node:
|
if 'language' not in node:
|
||||||
node['language'] = setting.language
|
node['language'] = setting.language
|
||||||
@ -105,8 +92,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
|
|||||||
"""
|
"""
|
||||||
default_priority = HighlightLanguageTransform.default_priority + 1
|
default_priority = HighlightLanguageTransform.default_priority + 1
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
if not self.config.trim_doctest_flags:
|
if not self.config.trim_doctest_flags:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -118,8 +104,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
|
|||||||
self.strip_doctest_flags(dbnode)
|
self.strip_doctest_flags(dbnode)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def strip_doctest_flags(node):
|
def strip_doctest_flags(node: Union[nodes.literal_block, nodes.doctest_block]) -> None:
|
||||||
# type: (Union[nodes.literal_block, nodes.doctest_block]) -> None
|
|
||||||
source = node.rawsource
|
source = node.rawsource
|
||||||
source = doctest.blankline_re.sub('', source)
|
source = doctest.blankline_re.sub('', source)
|
||||||
source = doctest.doctestopt_re.sub('', source)
|
source = doctest.doctestopt_re.sub('', source)
|
||||||
@ -127,8 +112,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
|
|||||||
node[:] = [nodes.Text(source)]
|
node[:] = [nodes.Text(source)]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_pyconsole(node):
|
def is_pyconsole(node: nodes.literal_block) -> bool:
|
||||||
# type: (nodes.literal_block) -> bool
|
|
||||||
if node.rawsource != node.astext():
|
if node.rawsource != node.astext():
|
||||||
return False # skip parsed-literal node
|
return False # skip parsed-literal node
|
||||||
|
|
||||||
@ -147,8 +131,7 @@ class TrimDoctestFlagsTransform(SphinxTransform):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_post_transform(HighlightLanguageTransform)
|
app.add_post_transform(HighlightLanguageTransform)
|
||||||
app.add_post_transform(TrimDoctestFlagsTransform)
|
app.add_post_transform(TrimDoctestFlagsTransform)
|
||||||
|
|
||||||
|
@ -11,9 +11,11 @@
|
|||||||
import os
|
import os
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
from typing import Any, Dict, List, Tuple
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
|
|
||||||
|
from sphinx.application import Sphinx
|
||||||
from sphinx.locale import __
|
from sphinx.locale import __
|
||||||
from sphinx.transforms import SphinxTransform
|
from sphinx.transforms import SphinxTransform
|
||||||
from sphinx.util import epoch_to_rfc1123, rfc1123_to_epoch
|
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.images import guess_mimetype, get_image_extension, parse_data_uri
|
||||||
from sphinx.util.osutil import ensuredir, movefile
|
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__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -33,31 +30,26 @@ MAX_FILENAME_LEN = 32
|
|||||||
|
|
||||||
|
|
||||||
class BaseImageConverter(SphinxTransform):
|
class BaseImageConverter(SphinxTransform):
|
||||||
def apply(self, **kwargsj):
|
def apply(self, **kwargs: Any) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(nodes.image):
|
for node in self.document.traverse(nodes.image):
|
||||||
if self.match(node):
|
if self.match(node):
|
||||||
self.handle(node)
|
self.handle(node)
|
||||||
|
|
||||||
def match(self, node):
|
def match(self, node: nodes.image) -> bool:
|
||||||
# type: (nodes.image) -> bool
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle(self, node):
|
def handle(self, node: nodes.image) -> None:
|
||||||
# type: (nodes.image) -> None
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imagedir(self):
|
def imagedir(self) -> str:
|
||||||
# type: () -> str
|
|
||||||
return os.path.join(self.app.doctreedir, 'images')
|
return os.path.join(self.app.doctreedir, 'images')
|
||||||
|
|
||||||
|
|
||||||
class ImageDownloader(BaseImageConverter):
|
class ImageDownloader(BaseImageConverter):
|
||||||
default_priority = 100
|
default_priority = 100
|
||||||
|
|
||||||
def match(self, node):
|
def match(self, node: nodes.image) -> bool:
|
||||||
# type: (nodes.image) -> bool
|
|
||||||
if self.app.builder.supported_image_types == []:
|
if self.app.builder.supported_image_types == []:
|
||||||
return False
|
return False
|
||||||
elif self.app.builder.supported_remote_images:
|
elif self.app.builder.supported_remote_images:
|
||||||
@ -65,8 +57,7 @@ class ImageDownloader(BaseImageConverter):
|
|||||||
else:
|
else:
|
||||||
return '://' in node['uri']
|
return '://' in node['uri']
|
||||||
|
|
||||||
def handle(self, node):
|
def handle(self, node: nodes.image) -> None:
|
||||||
# type: (nodes.image) -> None
|
|
||||||
try:
|
try:
|
||||||
basename = os.path.basename(node['uri'])
|
basename = os.path.basename(node['uri'])
|
||||||
if '?' in basename:
|
if '?' in basename:
|
||||||
@ -123,17 +114,15 @@ class ImageDownloader(BaseImageConverter):
|
|||||||
class DataURIExtractor(BaseImageConverter):
|
class DataURIExtractor(BaseImageConverter):
|
||||||
default_priority = 150
|
default_priority = 150
|
||||||
|
|
||||||
def match(self, node):
|
def match(self, node: nodes.image) -> bool:
|
||||||
# type: (nodes.image) -> bool
|
|
||||||
if self.app.builder.supported_remote_images == []:
|
if self.app.builder.supported_remote_images == []:
|
||||||
return False
|
return False
|
||||||
elif self.app.builder.supported_data_uri_images is True:
|
elif self.app.builder.supported_data_uri_images is True:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return 'data:' in node['uri']
|
return node['uri'].startswith('data:')
|
||||||
|
|
||||||
def handle(self, node):
|
def handle(self, node: nodes.image) -> None:
|
||||||
# type: (nodes.image) -> None
|
|
||||||
image = parse_data_uri(node['uri'])
|
image = parse_data_uri(node['uri'])
|
||||||
ext = get_image_extension(image.mimetype)
|
ext = get_image_extension(image.mimetype)
|
||||||
if ext is None:
|
if ext is None:
|
||||||
@ -155,8 +144,7 @@ class DataURIExtractor(BaseImageConverter):
|
|||||||
self.app.env.images.add_file(self.env.docname, path)
|
self.app.env.images.add_file(self.env.docname, path)
|
||||||
|
|
||||||
|
|
||||||
def get_filename_for(filename, mimetype):
|
def get_filename_for(filename: str, mimetype: str) -> str:
|
||||||
# type: (str, str) -> str
|
|
||||||
basename = os.path.basename(filename)
|
basename = os.path.basename(filename)
|
||||||
return os.path.splitext(basename)[0] + get_image_extension(mimetype)
|
return os.path.splitext(basename)[0] + get_image_extension(mimetype)
|
||||||
|
|
||||||
@ -195,15 +183,13 @@ class ImageConverter(BaseImageConverter):
|
|||||||
#: ]
|
#: ]
|
||||||
conversion_rules = [] # type: List[Tuple[str, str]]
|
conversion_rules = [] # type: List[Tuple[str, str]]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
# type: (Any, Any) -> None
|
|
||||||
self.available = None # type: bool
|
self.available = None # type: bool
|
||||||
# the converter is available or not.
|
# the converter is available or not.
|
||||||
# Will be checked at first conversion
|
# Will be checked at first conversion
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def match(self, node):
|
def match(self, node: nodes.image) -> bool:
|
||||||
# type: (nodes.image) -> bool
|
|
||||||
if self.available is None:
|
if self.available is None:
|
||||||
self.available = self.is_available()
|
self.available = self.is_available()
|
||||||
|
|
||||||
@ -219,8 +205,7 @@ class ImageConverter(BaseImageConverter):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_conversion_rule(self, node):
|
def get_conversion_rule(self, node: nodes.image) -> Tuple[str, str]:
|
||||||
# type: (nodes.image) -> Tuple[str, str]
|
|
||||||
for candidate in self.guess_mimetypes(node):
|
for candidate in self.guess_mimetypes(node):
|
||||||
for supported in self.app.builder.supported_image_types:
|
for supported in self.app.builder.supported_image_types:
|
||||||
rule = (candidate, supported)
|
rule = (candidate, supported)
|
||||||
@ -229,13 +214,11 @@ class ImageConverter(BaseImageConverter):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self) -> bool:
|
||||||
# type: () -> bool
|
|
||||||
"""Return the image converter is available or not."""
|
"""Return the image converter is available or not."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def guess_mimetypes(self, node):
|
def guess_mimetypes(self, node: nodes.image) -> List[str]:
|
||||||
# type: (nodes.image) -> List[str]
|
|
||||||
if '?' in node['candidates']:
|
if '?' in node['candidates']:
|
||||||
return []
|
return []
|
||||||
elif '*' in node['candidates']:
|
elif '*' in node['candidates']:
|
||||||
@ -244,8 +227,7 @@ class ImageConverter(BaseImageConverter):
|
|||||||
else:
|
else:
|
||||||
return node['candidates'].keys()
|
return node['candidates'].keys()
|
||||||
|
|
||||||
def handle(self, node):
|
def handle(self, node: nodes.image) -> None:
|
||||||
# type: (nodes.image) -> None
|
|
||||||
_from, _to = self.get_conversion_rule(node)
|
_from, _to = self.get_conversion_rule(node)
|
||||||
|
|
||||||
if _from in node['candidates']:
|
if _from in node['candidates']:
|
||||||
@ -268,8 +250,7 @@ class ImageConverter(BaseImageConverter):
|
|||||||
self.env.original_image_uri[destpath] = srcpath
|
self.env.original_image_uri[destpath] = srcpath
|
||||||
self.env.images.add_file(self.env.docname, destpath)
|
self.env.images.add_file(self.env.docname, destpath)
|
||||||
|
|
||||||
def convert(self, _from, _to):
|
def convert(self, _from: str, _to: str) -> bool:
|
||||||
# type: (str, str) -> bool
|
|
||||||
"""Convert a image file to expected format.
|
"""Convert a image file to expected format.
|
||||||
|
|
||||||
*_from* is a path for source image file, and *_to* is a path for
|
*_from* is a path for source image file, and *_to* is a path for
|
||||||
@ -278,8 +259,7 @@ class ImageConverter(BaseImageConverter):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: Sphinx) -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_post_transform(ImageDownloader)
|
app.add_post_transform(ImageDownloader)
|
||||||
app.add_post_transform(DataURIExtractor)
|
app.add_post_transform(DataURIExtractor)
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
from docutils import nodes
|
from docutils import nodes
|
||||||
from docutils.transforms.references import DanglingReferences, Substitutions
|
from docutils.transforms.references import DanglingReferences, Substitutions
|
||||||
|
|
||||||
@ -15,8 +17,7 @@ from sphinx.transforms import SphinxTransform
|
|||||||
|
|
||||||
if False:
|
if False:
|
||||||
# For type annotation
|
# For type annotation
|
||||||
from typing import Any, Dict # NOQA
|
from sphinx.application import Sphinx
|
||||||
from sphinx.application import Sphinx # NOQA
|
|
||||||
|
|
||||||
|
|
||||||
class SubstitutionDefinitionsRemover(SphinxTransform):
|
class SubstitutionDefinitionsRemover(SphinxTransform):
|
||||||
@ -25,8 +26,7 @@ class SubstitutionDefinitionsRemover(SphinxTransform):
|
|||||||
# should be invoked after Substitutions process
|
# should be invoked after Substitutions process
|
||||||
default_priority = Substitutions.default_priority + 1
|
default_priority = Substitutions.default_priority + 1
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for node in self.document.traverse(nodes.substitution_definition):
|
for node in self.document.traverse(nodes.substitution_definition):
|
||||||
node.parent.remove(node)
|
node.parent.remove(node)
|
||||||
|
|
||||||
@ -34,8 +34,7 @@ class SubstitutionDefinitionsRemover(SphinxTransform):
|
|||||||
class SphinxDanglingReferences(DanglingReferences):
|
class SphinxDanglingReferences(DanglingReferences):
|
||||||
"""DanglingReferences transform which does not output info messages."""
|
"""DanglingReferences transform which does not output info messages."""
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
try:
|
try:
|
||||||
reporter = self.document.reporter
|
reporter = self.document.reporter
|
||||||
report_level = reporter.report_level
|
report_level = reporter.report_level
|
||||||
@ -51,14 +50,12 @@ class SphinxDomains(SphinxTransform):
|
|||||||
"""Collect objects to Sphinx domains for cross references."""
|
"""Collect objects to Sphinx domains for cross references."""
|
||||||
default_priority = 850
|
default_priority = 850
|
||||||
|
|
||||||
def apply(self, **kwargs):
|
def apply(self, **kwargs) -> None:
|
||||||
# type: (Any) -> None
|
|
||||||
for domain in self.env.domains.values():
|
for domain in self.env.domains.values():
|
||||||
domain.process_doc(self.env, self.env.docname, self.document)
|
domain.process_doc(self.env, self.env.docname, self.document)
|
||||||
|
|
||||||
|
|
||||||
def setup(app):
|
def setup(app: "Sphinx") -> Dict[str, Any]:
|
||||||
# type: (Sphinx) -> Dict[str, Any]
|
|
||||||
app.add_transform(SubstitutionDefinitionsRemover)
|
app.add_transform(SubstitutionDefinitionsRemover)
|
||||||
app.add_transform(SphinxDanglingReferences)
|
app.add_transform(SphinxDanglingReferences)
|
||||||
app.add_transform(SphinxDomains)
|
app.add_transform(SphinxDomains)
|
||||||
|
@ -98,7 +98,7 @@ def skip_if_stylefiles_notfound(testfunc):
|
|||||||
@pytest.mark.sphinx('latex')
|
@pytest.mark.sphinx('latex')
|
||||||
def test_build_latex_doc(app, status, warning, engine, docclass):
|
def test_build_latex_doc(app, status, warning, engine, docclass):
|
||||||
app.config.latex_engine = engine
|
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()
|
app.builder.init_context()
|
||||||
|
|
||||||
LaTeXTranslator.ignore_missing_images = True
|
LaTeXTranslator.ignore_missing_images = True
|
||||||
|
@ -334,6 +334,16 @@ def test_member_definitions():
|
|||||||
check('member', 'thread_local extern int myInt', {1: 'myInt__i', 2: '5myInt'},
|
check('member', 'thread_local extern int myInt', {1: 'myInt__i', 2: '5myInt'},
|
||||||
'extern thread_local int myInt')
|
'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():
|
def test_function_definitions():
|
||||||
check('function', 'void f(volatile int)', {1: "f__iV", 2: "1fVi"})
|
check('function', 'void f(volatile int)', {1: "f__iV", 2: "1fVi"})
|
||||||
|
Loading…
Reference in New Issue
Block a user