Move translators to SphinxFactory

This commit is contained in:
Takeshi KOMIYA 2017-03-12 13:42:12 +09:00
parent f346e7dc1d
commit 78ea36a787
17 changed files with 96 additions and 62 deletions

View File

@ -146,7 +146,6 @@ class Sphinx(object):
logging.setup(self, self._status, self._warning)
self.events = EventManager()
self._translators = {} # type: Dict[unicode, nodes.GenericNodeVisitor]
# keep last few messages for traceback
# This will be filled by sphinx.util.logging.LastMessagesWriter
@ -515,9 +514,9 @@ class Sphinx(object):
self.events.add(name)
def set_translator(self, name, translator_class):
# type: (unicode, Any) -> None
# type: (unicode, Type[nodes.NodeVisitor]) -> None
logger.info(bold(_('A Translator for the %s builder is changed.') % name))
self._translators[name] = translator_class
self.factory.add_translator(name, translator_class)
def add_node(self, node, **kwds):
# type: (nodes.Node, Any) -> None
@ -535,7 +534,7 @@ class Sphinx(object):
except ValueError:
raise ExtensionError(_('Value for key %r must be a '
'(visit, depart) function tuple') % key)
translator = self._translators.get(key)
translator = self.factory.translators.get(key)
translators = []
if translator is not None:
translators.append(translator)

View File

@ -11,6 +11,7 @@
import os
from os import path
import warnings
try:
import multiprocessing
@ -20,6 +21,7 @@ except ImportError:
from six import itervalues
from docutils import nodes
from sphinx.deprecation import RemovedInSphinx20Warning
from sphinx.util import i18n, path_stabilize, logging, status_iterator
from sphinx.util.osutil import SEP, relative_uri
from sphinx.util.i18n import find_catalog
@ -53,6 +55,9 @@ class Builder(object):
name = '' # type: unicode
#: The builder's output format, or '' if no document output is produced.
format = '' # type: unicode
# default translator class for the builder. This will be overrided by
# ``app.set_translator()``.
default_translator_class = None # type: nodes.NodeVisitor
# doctree versioning method
versioning_method = 'none' # type: unicode
versioning_compare = False
@ -101,9 +106,6 @@ class Builder(object):
self.parallel_ok = False
self.finish_tasks = None # type: Any
# load default translator class
self.translator_class = app._translators.get(self.name)
def set_environment(self, env):
# type: (BuildEnvironment) -> None
"""Store BuildEnvironment object."""
@ -111,6 +113,38 @@ class Builder(object):
self.env.set_versioning_method(self.versioning_method,
self.versioning_compare)
def get_translator_class(self, *args):
# type: (Any) -> nodes.NodeVisitor
"""Return a class of translator."""
return self.app.factory.get_translator_class(self)
def create_translator(self, *args):
# type: (Any) -> nodes.NodeVisitor
"""Return an instance of translator.
This method returns an instance of ``default_translator_class`` by default.
Users can replace the translator class with ``app.set_translator()`` API.
"""
translator_class = self.app.factory.get_translator_class(self)
assert translator_class, "translator not found for %s" % self.__class__.__name__
return translator_class(*args)
@property
def translator_class(self):
# type: () -> Callable[[Any], nodes.NodeVisitor]
"""Return a class of translator.
.. deprecated:: 1.6
"""
translator_class = self.app.factory.get_translator_class(self)
if translator_class is None and self.default_translator_class is None:
warnings.warn('builder.translator_class() is now deprecated. '
'Please use builder.create_translator() and '
'builder.default_translator_class instead.',
RemovedInSphinx20Warning)
return None
return self.create_translator
# helper methods
def init(self):
# type: () -> None

View File

@ -158,7 +158,6 @@ class StandaloneHTMLBuilder(Builder):
self.init_templates()
self.init_highlighter()
self.init_translator_class()
if self.config.html_file_suffix is not None:
self.out_suffix = self.config.html_file_suffix
@ -218,23 +217,18 @@ class StandaloneHTMLBuilder(Builder):
self.highlighter = PygmentsBridge('html', style,
self.config.trim_doctest_flags)
def init_translator_class(self):
# type: () -> None
if self.translator_class is None:
use_html5_writer = self.config.html_experimental_html5_writer
if use_html5_writer is None:
use_html5_writer = self.default_html5_translator and html5_ready
if use_html5_writer and html5_ready:
if self.config.html_use_smartypants:
self.translator_class = SmartyPantsHTML5Translator
else:
self.translator_class = HTML5Translator
@property
def default_translator_class(self):
if self.config.html_experimental_html5_writer and html5_ready:
if self.config.html_use_smartypants:
return SmartyPantsHTML5Translator
else:
if self.config.html_use_smartypants:
self.translator_class = SmartyPantsHTMLTranslator
else:
self.translator_class = HTMLTranslator
return HTML5Translator
else:
if self.config.html_use_smartypants:
return SmartyPantsHTMLTranslator
else:
return HTMLTranslator
def get_outdated_docs(self):
# type: () -> Iterator[unicode]
@ -1200,7 +1194,6 @@ class SerializingHTMLBuilder(StandaloneHTMLBuilder):
self.current_docname = None
self.theme = None # no theme necessary
self.templates = None # no template bridge necessary
self.init_translator_class()
self.init_templates()
self.init_highlighter()
self.use_index = self.get_builder_config('use_index', 'html')

View File

@ -31,7 +31,7 @@ from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.fileutil import copy_asset_file
from sphinx.util.osutil import SEP, make_filename
from sphinx.util.console import bold, darkgreen # type: ignore
from sphinx.writers.latex import LaTeXWriter
from sphinx.writers.latex import LaTeXWriter, LaTeXTranslator
if False:
# For type annotation
@ -51,6 +51,7 @@ class LaTeXBuilder(Builder):
format = 'latex'
supported_image_types = ['application/pdf', 'image/png', 'image/jpeg']
supported_remote_images = False
default_translator_class = LaTeXTranslator
def init(self):
# type: () -> None

View File

@ -23,7 +23,7 @@ from sphinx.util import logging
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import make_filename
from sphinx.util.console import bold, darkgreen # type: ignore
from sphinx.writers.manpage import ManualPageWriter
from sphinx.writers.manpage import ManualPageWriter, ManualPageTranslator
if False:
# For type annotation
@ -40,6 +40,7 @@ class ManualPageBuilder(Builder):
"""
name = 'man'
format = 'man'
default_translator_class = ManualPageTranslator
supported_image_types = [] # type: List[unicode]
def init(self):

View File

@ -27,7 +27,7 @@ from sphinx.util.fileutil import copy_asset_file
from sphinx.util.nodes import inline_all_toctrees
from sphinx.util.osutil import SEP, make_filename
from sphinx.util.console import bold, darkgreen # type: ignore
from sphinx.writers.texinfo import TexinfoWriter
from sphinx.writers.texinfo import TexinfoWriter, TexinfoTranslator
if False:
# For type annotation
@ -99,6 +99,7 @@ class TexinfoBuilder(Builder):
format = 'texinfo'
supported_image_types = ['image/png', 'image/jpeg',
'image/gif']
default_translator_class = TexinfoTranslator
def init(self):
# type: () -> None

View File

@ -17,7 +17,7 @@ from docutils.io import StringOutput
from sphinx.builders import Builder
from sphinx.util import logging
from sphinx.util.osutil import ensuredir, os_path
from sphinx.writers.text import TextWriter
from sphinx.writers.text import TextWriter, TextTranslator
if False:
# For type annotation
@ -33,6 +33,7 @@ class TextBuilder(Builder):
format = 'text'
out_suffix = '.txt'
allow_parallel = True
default_translator_class = TextTranslator
current_docname = None # type: unicode

View File

@ -34,6 +34,7 @@ class WebSupportBuilder(PickleHTMLBuilder):
name = 'websupport'
versioning_method = 'commentable'
versioning_compare = True # for commentable node's uuid stability.
default_translator_class = WebSupportTranslator
def init(self):
# type: () -> None
@ -54,11 +55,6 @@ class WebSupportBuilder(PickleHTMLBuilder):
self.search = search
self.storage = storage
def init_translator_class(self):
# type: () -> None
if self.translator_class is None:
self.translator_class = WebSupportTranslator
def prepare_writing(self, docnames):
# type: (Iterable[unicode]) -> None
PickleHTMLBuilder.prepare_writing(self, docnames)

View File

@ -14,6 +14,7 @@ from os import path
from docutils import nodes
from docutils.io import StringOutput
from docutils.writers.docutils_xml import XMLTranslator
from sphinx.builders import Builder
from sphinx.util import logging
@ -38,6 +39,7 @@ class XMLBuilder(Builder):
allow_parallel = True
_writer_class = XMLWriter
default_translator_class = XMLTranslator
def init(self):
# type: () -> None

View File

@ -39,6 +39,7 @@ class SphinxFactory(object):
self.builders = {} # type: Dict[unicode, Type[Builder]]
self.domains = {} # type: Dict[unicode, Type[Domain]]
self.source_parsers = {} # type: Dict[unicode, Parser]
self.translators = {} # type: Dict[unicode, nodes.NodeVisitor]
def add_builder(self, builder):
# type: (Type[Builder]) -> None
@ -152,3 +153,17 @@ class SphinxFactory(object):
def get_source_parsers(self):
# type: () -> Dict[unicode, Parser]
return self.source_parsers
def add_translator(self, name, translator):
# type: (unicode, Type[nodes.NodeVisitor]) -> None
self.translators[name] = translator
def get_translator_class(self, builder):
# type: (Builder) -> Type[nodes.NodeVisitor]
return self.translators.get(builder.name,
builder.default_translator_class)
def create_translator(self, builder, document):
# type: (Builder, nodes.Node) -> nodes.NodeVisitor
translator_class = self.get_translator_class(builder)
return translator_class(builder, document)

View File

@ -52,8 +52,8 @@ class HTMLWriter(Writer):
def translate(self):
# type: () -> None
# sadly, this is mostly copied from parent class
self.visitor = visitor = self.builder.translator_class(self.builder,
self.document)
self.visitor = visitor = self.builder.create_translator(self.builder,
self.document)
self.document.walkabout(visitor)
self.output = visitor.astext()
for attr in ('head_prefix', 'stylesheet', 'head', 'body_prefix',

View File

@ -159,14 +159,12 @@ class LaTeXWriter(writers.Writer):
# type: (Builder) -> None
writers.Writer.__init__(self)
self.builder = builder
self.translator_class = (
self.builder.translator_class or LaTeXTranslator)
def translate(self):
# type: () -> None
transform = ShowUrlsTransform(self.document)
transform.apply()
visitor = self.translator_class(self.document, self.builder)
visitor = self.builder.create_translator(self.document, self.builder)
self.document.walkabout(visitor)
self.output = visitor.astext()

View File

@ -35,14 +35,12 @@ class ManualPageWriter(Writer):
# type: (Builder) -> None
Writer.__init__(self)
self.builder = builder
self.translator_class = (
self.builder.translator_class or ManualPageTranslator)
def translate(self):
# type: () -> None
transform = NestedInlineTransform(self.document)
transform.apply()
visitor = self.translator_class(self.builder, self.document)
visitor = self.builder.create_translator(self.builder, self.document)
self.visitor = visitor
self.document.walkabout(visitor)
self.output = visitor.astext()

View File

@ -133,13 +133,10 @@ class TexinfoWriter(writers.Writer):
# type: (TexinfoBuilder) -> None
writers.Writer.__init__(self)
self.builder = builder
self.translator_class = (
self.builder.translator_class or TexinfoTranslator)
def translate(self):
# type: () -> None
self.visitor = visitor = self.translator_class(
self.document, self.builder)
self.visitor = visitor = self.builder.create_translator(self.document, self.builder)
self.document.walkabout(visitor)
visitor.finish()
for attr in self.visitor_attributes:

View File

@ -159,11 +159,10 @@ class TextWriter(writers.Writer):
# type: (TextBuilder) -> None
writers.Writer.__init__(self)
self.builder = builder
self.translator_class = self.builder.translator_class or TextTranslator
def translate(self):
# type: () -> None
visitor = self.translator_class(self.document, self.builder)
visitor = self.builder.create_translator(self.document, self.builder)
self.document.walkabout(visitor)
self.output = visitor.body

View File

@ -24,8 +24,7 @@ class XMLWriter(BaseXMLWriter):
# type: (Builder) -> None
BaseXMLWriter.__init__(self)
self.builder = builder
if self.builder.translator_class:
self.translator_class = self.builder.translator_class
self.translator_class = self.builder.get_translator_class()
def translate(self, *args, **kwargs):
# type: (Any, Any) -> None

View File

@ -26,7 +26,7 @@ def teardown_module():
@pytest.mark.sphinx('html')
def test_html_translator(app, status, warning):
# no set_translator()
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'SmartyPantsHTMLTranslator'
@ -35,7 +35,7 @@ def test_html_translator(app, status, warning):
'html_use_smartypants': False})
def test_html_with_smartypants(app, status, warning):
# no set_translator(), html_use_smartypants=False
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'HTMLTranslator'
@ -43,7 +43,7 @@ def test_html_with_smartypants(app, status, warning):
@pytest.mark.sphinx('html', testroot='api-set-translator')
def test_html_with_set_translator_for_html_(app, status, warning):
# use set_translator()
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfHTMLTranslator'
@ -61,62 +61,62 @@ def test_html_with_set_translator_for_html_(app, status, warning):
@pytest.mark.sphinx('singlehtml', testroot='api-set-translator')
def test_singlehtml_set_translator_for_singlehtml(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfSingleHTMLTranslator'
@pytest.mark.sphinx('pickle', testroot='api-set-translator')
def test_pickle_set_translator_for_pickle(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfPickleTranslator'
@pytest.mark.sphinx('json', testroot='api-set-translator')
def test_json_set_translator_for_json(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfJsonTranslator'
@pytest.mark.sphinx('latex', testroot='api-set-translator')
def test_html_with_set_translator_for_latex(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfLaTeXTranslator'
@pytest.mark.sphinx('man', testroot='api-set-translator')
def test_html_with_set_translator_for_man(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfManualPageTranslator'
@pytest.mark.sphinx('texinfo', testroot='api-set-translator')
def test_html_with_set_translator_for_texinfo(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfTexinfoTranslator'
@pytest.mark.sphinx('text', testroot='api-set-translator')
def test_html_with_set_translator_for_text(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfTextTranslator'
@pytest.mark.sphinx('xml', testroot='api-set-translator')
def test_html_with_set_translator_for_xml(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfXMLTranslator'
@pytest.mark.sphinx('pseudoxml', testroot='api-set-translator')
def test_html_with_set_translator_for_pseudoxml(app, status, warning):
translator_class = app.builder.translator_class
translator_class = app.builder.get_translator_class()
assert translator_class
assert translator_class.__name__ == 'ConfPseudoXMLTranslator'