Add OnlyNodeTransform as a tranform

This commit is contained in:
Takeshi KOMIYA 2017-03-06 16:21:13 +09:00
parent eb40a36aa4
commit f6f6eac20c
5 changed files with 70 additions and 11 deletions

View File

@ -35,7 +35,7 @@ from sphinx import addnodes
from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput from sphinx.io import SphinxStandaloneReader, SphinxDummyWriter, SphinxFileInput
from sphinx.util import logging from sphinx.util import logging
from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator from sphinx.util import get_matching_docs, FilenameUniqDict, status_iterator
from sphinx.util.nodes import WarningStream, is_translatable, process_only_nodes from sphinx.util.nodes import WarningStream, is_translatable
from sphinx.util.osutil import SEP, ensuredir from sphinx.util.osutil import SEP, ensuredir
from sphinx.util.i18n import find_catalog_files from sphinx.util.i18n import find_catalog_files
from sphinx.util.console import bold # type: ignore from sphinx.util.console import bold # type: ignore
@ -46,7 +46,7 @@ from sphinx.util.websupport import is_commentable
from sphinx.errors import SphinxError, ExtensionError from sphinx.errors import SphinxError, ExtensionError
from sphinx.transforms import SphinxTransformer from sphinx.transforms import SphinxTransformer
from sphinx.versioning import add_uids, merge_doctrees from sphinx.versioning import add_uids, merge_doctrees
from sphinx.deprecation import RemovedInSphinx20Warning from sphinx.deprecation import RemovedInSphinx17Warning, RemovedInSphinx20Warning
from sphinx.environment.adapters.indexentries import IndexEntries from sphinx.environment.adapters.indexentries import IndexEntries
from sphinx.environment.adapters.toctree import TocTree from sphinx.environment.adapters.toctree import TocTree
@ -921,10 +921,18 @@ class BuildEnvironment(object):
def resolve_references(self, doctree, fromdocname, builder): def resolve_references(self, doctree, fromdocname, builder):
# type: (nodes.Node, unicode, Builder) -> None # type: (nodes.Node, unicode, Builder) -> None
# apply all post-transforms warnings.warn('env.resolve_references() is deprecated. '
'Use apply_post_transforms() instead.',
RemovedInSphinx17Warning)
self.apply_post_transforms(doctree, fromdocname)
def apply_post_transforms(self, doctree, docname):
# type: (nodes.Node, unicode) -> None
"""Apply all post-transforms."""
try: try:
# set env.docname during applying post-transforms # set env.docname during applying post-transforms
self.temp_data['docname'] = fromdocname self.temp_data['docname'] = docname
transformer = SphinxTransformer(doctree) transformer = SphinxTransformer(doctree)
transformer.add_transforms(self.app.post_transforms) transformer.add_transforms(self.app.post_transforms)
@ -932,11 +940,8 @@ class BuildEnvironment(object):
finally: finally:
self.temp_data.clear() self.temp_data.clear()
# remove only-nodes that do not belong to our builder
process_only_nodes(doctree, builder.tags)
# allow custom references to be resolved # allow custom references to be resolved
builder.app.emit('doctree-resolved', doctree, fromdocname) self.app.emit('doctree-resolved', doctree, docname)
def _warn_missing_reference(self, refdoc, typ, target, node, domain): def _warn_missing_reference(self, refdoc, typ, target, node, domain):
# type: (unicode, unicode, unicode, nodes.Node, Domain) -> None # type: (unicode, unicode, unicode, nodes.Node, Domain) -> None

View File

@ -15,7 +15,7 @@ from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.util import url_re, logging from sphinx.util import url_re, logging
from sphinx.util.nodes import clean_astext, process_only_nodes from sphinx.util.nodes import clean_astext
if False: if False:
# For type annotation # For type annotation
@ -158,7 +158,7 @@ class TocTree(object):
maxdepth = self.env.metadata[ref].get('tocdepth', 0) maxdepth = self.env.metadata[ref].get('tocdepth', 0)
if ref not in toctree_ancestors or (prune and maxdepth > 0): if ref not in toctree_ancestors or (prune and maxdepth > 0):
self._toctree_prune(toc, 2, maxdepth, collapse) self._toctree_prune(toc, 2, maxdepth, collapse)
process_only_nodes(toc, builder.tags) self.process_only_nodes(toc)
if title and toc.children and len(toc.children) == 1: if title and toc.children and len(toc.children) == 1:
child = toc.children[0] child = toc.children[0]
for refnode in child.traverse(nodes.reference): for refnode in child.traverse(nodes.reference):
@ -298,7 +298,7 @@ class TocTree(object):
# the document does not exist anymore: return a dummy node that # the document does not exist anymore: return a dummy node that
# renders to nothing # renders to nothing
return nodes.paragraph() return nodes.paragraph()
process_only_nodes(toc, builder.tags) self.process_only_nodes(toc)
for node in toc.traverse(nodes.reference): for node in toc.traverse(nodes.reference):
node['refuri'] = node['anchorname'] or '#' node['refuri'] = node['anchorname'] or '#'
return toc return toc
@ -323,3 +323,14 @@ class TocTree(object):
for toctree in toctrees[1:]: for toctree in toctrees[1:]:
result.extend(toctree.children) result.extend(toctree.children)
return result return result
def process_only_nodes(self, doctree):
# type: (nodes.Node) -> None
# Lazy loading
from sphinx.transforms import SphinxTransformer
from sphinx.transforms.post_transforms import OnlyNodeTransform
transformer = SphinxTransformer(doctree)
transformer.set_environment(self.env)
transformer.add_transform(OnlyNodeTransform)
transformer.apply_transforms()

View File

@ -76,6 +76,11 @@ class SphinxTransformer(Transformer):
""" """
document = None # type: nodes.Node document = None # type: nodes.Node
env = None # type: BuildEnvironment
def set_environment(self, env):
# type: (BuildEnvironment) -> None
self.env = env
def apply_transforms(self): def apply_transforms(self):
# type: () -> None # type: () -> None
@ -85,6 +90,8 @@ class SphinxTransformer(Transformer):
# wrap the target node by document node during transforming # wrap the target node by document node during transforming
try: try:
document = new_document('') document = new_document('')
if self.env:
document.settings.env = self.env
document += self.document document += self.document
self.document = document self.document = document
Transformer.apply_transforms(self) Transformer.apply_transforms(self)

View File

@ -9,9 +9,12 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.environment import NoUri from sphinx.environment import NoUri
from sphinx.transforms import SphinxTransform from sphinx.transforms import SphinxTransform
from sphinx.util import logging
if False: if False:
# For type annotation # For type annotation
@ -19,6 +22,9 @@ if False:
from sphinx.application import Sphinx # NOQA from sphinx.application import Sphinx # NOQA
logger = logging.getLogger(__name__)
class ReferencesResolver(SphinxTransform): class ReferencesResolver(SphinxTransform):
""" """
Resolves cross-references on doctrees. Resolves cross-references on doctrees.
@ -63,9 +69,33 @@ class ReferencesResolver(SphinxTransform):
node.replace_self(newnode or contnode) node.replace_self(newnode or contnode)
class OnlyNodeTransform(SphinxTransform):
default_priority = 50
def apply(self):
# type: () -> 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...
for node in self.document.traverse(addnodes.only):
try:
ret = self.app.builder.tags.eval_condition(node['expr'])
except Exception as err:
logger.warning('exception while evaluating only directive expression: %s', err,
location=node)
node.replace_self(node.children or nodes.comment())
else:
if ret:
node.replace_self(node.children or nodes.comment())
else:
node.replace_self(nodes.comment())
def setup(app): def setup(app):
# type: (Sphinx) -> Dict[unicode, Any] # type: (Sphinx) -> Dict[unicode, Any]
app.add_post_transform(ReferencesResolver) app.add_post_transform(ReferencesResolver)
app.add_post_transform(OnlyNodeTransform)
return { return {
'version': 'builtin', 'version': 'builtin',

View File

@ -11,12 +11,14 @@
from __future__ import absolute_import from __future__ import absolute_import
import re import re
import warnings
from six import text_type from six import text_type
from docutils import nodes from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.deprecation import RemovedInSphinx17Warning
from sphinx.locale import pairindextypes from sphinx.locale import pairindextypes
from sphinx.util import logging from sphinx.util import logging
@ -358,6 +360,10 @@ def process_only_nodes(doctree, tags):
# 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
# something, even if it's just a comment and will lose the id anyway... # 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): for node in doctree.traverse(addnodes.only):
try: try:
ret = tags.eval_condition(node['expr']) ret = tags.eval_condition(node['expr'])