Merge pull request #7009 from tk0miya/refactor_SphinxTranslator2

SphinxTranslator calls visitor/departure method for super node class
This commit is contained in:
Takeshi KOMIYA 2020-01-11 21:42:20 +09:00 committed by GitHub
commit 4cecd700e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 2 deletions

View File

@ -35,6 +35,8 @@ Features added
images (imagesize-1.2.0 or above is required)
* #6994: imgconverter: Support illustrator file (.ai) to .png conversion
* autodoc: Support Positional-Only Argument separator (PEP-570 compliant)
* SphinxTranslator now calls visitor/departure method for super node class if
visitor/departure method for original node class not found
Bugs fixed
----------

View File

@ -452,7 +452,10 @@ class ReferenceRole(SphinxRole):
class SphinxTranslator(nodes.NodeVisitor):
"""A base class for Sphinx translators.
This class provides helper methods for Sphinx translators.
This class adds a support for visitor/departure method for super node class
if visitor/departure method for node class is not found.
It also provides helper methods for Sphinx translators.
.. note:: The subclasses of this class might not work with docutils.
This class is strongly coupled with Sphinx.
@ -464,6 +467,42 @@ class SphinxTranslator(nodes.NodeVisitor):
self.config = builder.config
self.settings = document.settings
def dispatch_visit(self, node):
"""
Dispatch node to appropriate visitor method.
The priority of visitor method is:
1. ``self.visit_{node_class}()``
2. ``self.visit_{supre_node_class}()``
3. ``self.unknown_visit()``
"""
for node_class in node.__class__.__mro__:
method = getattr(self, 'visit_%s' % (node_class.__name__), None)
if method:
logger.debug('SphinxTranslator.dispatch_visit calling %s for %s' %
(method.__name__, node))
return method(node)
else:
super().dispatch_visit(node)
def dispatch_departure(self, node):
"""
Dispatch node to appropriate departure method.
The priority of departure method is:
1. ``self.depart_{node_class}()``
2. ``self.depart_{super_node_class}()``
3. ``self.unknown_departure()``
"""
for node_class in node.__class__.__mro__:
method = getattr(self, 'depart_%s' % (node_class.__name__), None)
if method:
logger.debug('SphinxTranslator.dispatch_departure calling %s for %s' %
(method.__name__, node))
return method(node)
else:
super().dispatch_departure(node)
# cache a vanilla instance of nodes.document
# Used in new_document() function

View File

@ -12,7 +12,9 @@ import os
from docutils import nodes
from sphinx.util.docutils import SphinxFileOutput, docutils_namespace, register_node
from sphinx.util.docutils import (
SphinxFileOutput, SphinxTranslator, docutils_namespace, new_document, register_node
)
def test_register_node():
@ -61,3 +63,34 @@ def test_SphinxFileOutput(tmpdir):
# overrite it again (content changed)
output.write(content + "; content change")
assert os.stat(filename).st_mtime != 0 # updated
def test_SphinxTranslator(app):
class CustomNode(nodes.inline):
pass
class MyTranslator(SphinxTranslator):
def __init__(self, *args):
self.called = []
super().__init__(*args)
def visit_document(self, node):
pass
def depart_document(self, node):
pass
def visit_inline(self, node):
self.called.append('visit_inline')
def depart_inline(self, node):
self.called.append('depart_inline')
document = new_document('')
document += CustomNode()
translator = MyTranslator(document, app.builder)
document.walkabout(translator)
# MyTranslator does not have visit_CustomNode. But it calls visit_inline instead.
assert translator.called == ['visit_inline', 'depart_inline']