diff options
Diffstat (limited to 'sphinx/util/nodes.py')
-rw-r--r-- | sphinx/util/nodes.py | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index f87a7afd0..5c444fb56 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -11,21 +11,35 @@ from __future__ import absolute_import import re +import warnings from six import text_type + from docutils import nodes from sphinx import addnodes +from sphinx.deprecation import RemovedInSphinx17Warning from sphinx.locale import pairindextypes +from sphinx.util import logging + +if False: + # For type annotation + from typing import Any, Callable, Iterable, List, Set, Tuple, Union # NOQA + from sphinx.builders import Builder # NOQA + from sphinx.utils.tags import Tags # NOQA + +logger = logging.getLogger(__name__) class WarningStream(object): def __init__(self, warnfunc): + # type: (Callable) -> None self.warnfunc = warnfunc self._re = re.compile(r'\((DEBUG|INFO|WARNING|ERROR|SEVERE)/[0-4]\)') def write(self, text): + # type: (str) -> None text = text.strip() if text: self.warnfunc(self._re.sub(r'\1:', text), None, '') @@ -37,6 +51,7 @@ caption_ref_re = explicit_title_re # b/w compat alias def apply_source_workaround(node): + # type: (nodes.Node) -> None # workaround: nodes.term have wrong rawsource if classifier is specified. # The behavior of docutils-0.11, 0.12 is: # * when ``term text : classifier1 : classifier2`` is specified, @@ -52,8 +67,8 @@ def apply_source_workaround(node): if isinstance(node, nodes.term): # strip classifier from rawsource of term for classifier in reversed(node.parent.traverse(nodes.classifier)): - node.rawsource = re.sub( - '\s*:\s*%s' % re.escape(classifier.astext()), '', node.rawsource) + node.rawsource = re.sub(r'\s*:\s*%s' % re.escape(classifier.astext()), + '', node.rawsource) # workaround: recommonmark-0.2.0 doesn't set rawsource attribute if not node.rawsource: @@ -85,6 +100,7 @@ IGNORED_NODES = ( def is_pending_meta(node): + # type: (nodes.Node) -> bool if (isinstance(node, nodes.pending) and isinstance(node.details.get('nodes', [None])[0], addnodes.meta)): return True @@ -93,6 +109,7 @@ def is_pending_meta(node): def is_translatable(node): + # type: (nodes.Node) -> bool if isinstance(node, addnodes.translatable): return True @@ -135,6 +152,7 @@ META_TYPE_NODES = ( def extract_messages(doctree): + # type: (nodes.Node) -> Iterable[Tuple[nodes.Node, unicode]] """Extract translatable messages from a document tree.""" for node in doctree.traverse(is_translatable): if isinstance(node, addnodes.translatable): @@ -162,12 +180,15 @@ def extract_messages(doctree): def find_source_node(node): + # type: (nodes.Node) -> unicode for pnode in traverse_parent(node): if pnode.source: return pnode.source + return None def traverse_parent(node, cls=None): + # type: (nodes.Node, Any) -> Iterable[nodes.Node] while node: if cls is None or isinstance(node, cls): yield node @@ -175,8 +196,10 @@ def traverse_parent(node, cls=None): def traverse_translatable_index(doctree): + # type: (nodes.Node) -> Iterable[Tuple[nodes.Node, List[unicode]]] """Traverse translatable index node from a document tree.""" def is_block_index(node): + # type: (nodes.Node) -> bool return isinstance(node, addnodes.index) and \ node.get('inline') is False for node in doctree.traverse(is_block_index): @@ -188,6 +211,7 @@ def traverse_translatable_index(doctree): def nested_parse_with_titles(state, content, node): + # type: (Any, List[unicode], nodes.Node) -> unicode """Version of state.nested_parse() that allows titles and does not require titles to have the same decoration as the calling document. @@ -207,6 +231,7 @@ def nested_parse_with_titles(state, content, node): def clean_astext(node): + # type: (nodes.Node) -> unicode """Like node.astext(), but ignore images.""" node = node.deepcopy() for img in node.traverse(nodes.image): @@ -217,8 +242,9 @@ def clean_astext(node): def split_explicit_title(text): + # type: (unicode) -> Tuple[bool, unicode, unicode] """Split role content into title and target, if given.""" - match = explicit_title_re.match(text) + match = explicit_title_re.match(text) # type: ignore if match: return True, match.group(1), match.group(2) return False, text, text @@ -230,7 +256,8 @@ indextypes = [ def process_index_entry(entry, targetid): - indexentries = [] + # type: (unicode, unicode) -> List[Tuple[unicode, unicode, unicode, unicode, unicode]] + indexentries = [] # type: List[Tuple[unicode, unicode, unicode, unicode, unicode]] entry = entry.strip() oentry = entry main = '' @@ -266,6 +293,7 @@ def process_index_entry(entry, targetid): def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed): + # type: (Builder, Set[unicode], unicode, nodes.Node, Callable, nodes.Node) -> nodes.Node """Inline all toctrees in the *tree*. Record all docnames in *docnameset*, and output docnames with *colorfunc*. @@ -278,15 +306,14 @@ def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed if includefile not in traversed: try: traversed.append(includefile) - builder.info(colorfunc(includefile) + " ", nonl=1) + logger.info(colorfunc(includefile) + " ", nonl=1) subtree = inline_all_toctrees(builder, docnameset, includefile, builder.env.get_doctree(includefile), colorfunc, traversed) docnameset.add(includefile) except Exception: - builder.warn('toctree contains ref to nonexisting ' - 'file %r' % includefile, - builder.env.doc2path(docname)) + logger.warning('toctree contains ref to nonexisting file %r', + includefile, location=docname) else: sof = addnodes.start_of_file(docname=includefile) sof.children = subtree.children @@ -299,13 +326,17 @@ def inline_all_toctrees(builder, docnameset, docname, tree, colorfunc, traversed def make_refnode(builder, fromdocname, todocname, targetid, child, title=None): + # type: (Builder, unicode, unicode, unicode, nodes.Node, unicode) -> nodes.reference """Shortcut to create a reference node.""" node = nodes.reference('', '', internal=True) - if fromdocname == todocname: + if fromdocname == todocname and targetid: node['refid'] = targetid else: - node['refuri'] = (builder.get_relative_uri(fromdocname, todocname) + - '#' + targetid) + if targetid: + node['refuri'] = (builder.get_relative_uri(fromdocname, todocname) + + '#' + targetid) + else: + node['refuri'] = builder.get_relative_uri(fromdocname, todocname) if title: node['reftitle'] = title node.append(child) @@ -313,27 +344,32 @@ def make_refnode(builder, fromdocname, todocname, targetid, child, title=None): def set_source_info(directive, node): + # type: (Any, nodes.Node) -> None node.source, node.line = \ directive.state_machine.get_source_and_line(directive.lineno) def set_role_source_info(inliner, lineno, node): + # type: (Any, unicode, nodes.Node) -> None node.source, node.line = inliner.reporter.get_source_and_line(lineno) -def process_only_nodes(doctree, tags, warn_node=None): +def process_only_nodes(doctree, tags): + # type: (nodes.Node, Tags) -> 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 # something, even if it's just a comment and will lose the id anyway... + warnings.warn('process_only_nodes() is deprecated. ' + 'Use sphinx.environment.apply_post_transforms() instead.', + RemovedInSphinx17Warning) + for node in doctree.traverse(addnodes.only): try: ret = tags.eval_condition(node['expr']) except Exception as err: - if warn_node is None: - raise err - warn_node('exception while evaluating only ' - 'directive expression: %s' % err, node) + logger.warning('exception while evaluating only directive expression: %s', err, + location=node) node.replace_self(node.children or nodes.comment()) else: if ret: @@ -345,6 +381,7 @@ def process_only_nodes(doctree, tags, warn_node=None): # monkey-patch Element.copy to copy the rawsource and line def _new_copy(self): + # type: (nodes.Node) -> nodes.Node newnode = self.__class__(self.rawsource, **self.attributes) if isinstance(self, nodes.Element): newnode.source = self.source |