Integrate source_suffix and source_parsers (refs: #4474)

This commit is contained in:
Takeshi KOMIYA 2018-01-24 00:48:02 +09:00
parent 69f69628ed
commit 0cdd9ee72a
5 changed files with 66 additions and 26 deletions

View File

@ -89,6 +89,7 @@ builtin_extensions = (
'sphinx.directives.patches',
'sphinx.io',
'sphinx.parsers',
'sphinx.registry',
'sphinx.roles',
'sphinx.transforms.post_transforms',
'sphinx.transforms.post_transforms.images',
@ -251,8 +252,6 @@ class Sphinx(object):
self.builder = self.create_builder(buildername)
# check all configuration values for permissible types
self.config.check_types()
# set up source_parsers
self._init_source_parsers()
# set up the build environment
self._init_env(freshenv)
# set up the builder
@ -286,12 +285,6 @@ class Sphinx(object):
else:
logger.info('not available for built-in messages')
def _init_source_parsers(self):
# type: () -> None
for suffix, parser in iteritems(self.registry.get_source_parsers()):
if suffix not in self.config.source_suffix and suffix != '*':
self.config.source_suffix[suffix] = suffix
def _init_env(self, freshenv):
# type: (bool) -> None
if freshenv:

View File

@ -91,7 +91,7 @@ class RSTParser(docutils.parsers.rst.Parser):
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.add_source_parser('*', RSTParser) # register as a special parser
app.add_source_parser('.rst', RSTParser)
return {
'version': 'builtin',

View File

@ -51,6 +51,10 @@ EXTENSION_BLACKLIST = {
} # type: Dict[unicode, unicode]
class FiletypeNotFoundError(Exception):
pass
class SphinxComponentRegistry(object):
def __init__(self):
self.autodoc_attrgettrs = {} # type: Dict[Type, Callable[[Any, unicode, Any], Any]]
@ -62,8 +66,9 @@ class SphinxComponentRegistry(object):
self.domain_object_types = {} # type: Dict[unicode, Dict[unicode, ObjType]]
self.domain_roles = {} # type: Dict[unicode, Dict[unicode, Union[RoleFunction, XRefRole]]] # NOQA
self.post_transforms = [] # type: List[Type[Transform]]
self.source_parsers = {} # type: Dict[unicode, Parser]
self.source_parsers = {} # type: Dict[unicode, Type[Parser]]
self.source_inputs = {} # type: Dict[unicode, Input]
self.source_suffix = {} # type: Dict[unicode, unicode]
self.translators = {} # type: Dict[unicode, nodes.NodeVisitor]
self.transforms = [] # type: List[Type[Transform]]
@ -201,27 +206,47 @@ class SphinxComponentRegistry(object):
def add_source_parser(self, suffix, parser):
# type: (unicode, Type[Parser]) -> None
logger.debug('[app] adding search source_parser: %r, %r', suffix, parser)
if suffix in self.source_parsers:
if suffix in self.source_suffix:
raise ExtensionError(__('source_parser for %r is already registered') % suffix)
else:
self.source_suffix[suffix] = suffix
if len(parser.supported) == 0:
warnings.warn('Old source_parser has been detected. Please fill Parser.supported '
'attribute: %s' % parser.__name__,
RemovedInSphinx30Warning)
# create a map from filetype to parser
for filetype in parser.supported:
if filetype in self.source_parsers:
raise ExtensionError(__('source_parser for %r is already registered') %
filetype)
else:
self.source_parsers[filetype] = parser
# also maps suffix to parser
#
# This allows parsers not having ``supported`` filetypes.
self.source_parsers[suffix] = parser
def get_filetype(self, filename):
# type: (unicode) -> unicode
for suffix, filetype in iteritems(self.source_suffix):
if filename.endswith(suffix):
return filetype
else:
raise FiletypeNotFoundError
def get_source_parser(self, filename):
# type: (unicode) -> Type[Parser]
for suffix, parser_class in iteritems(self.source_parsers):
if filename.endswith(suffix):
break
else:
# use special parser for unknown file-extension '*' (if exists)
parser_class = self.source_parsers.get('*')
try:
filetype = self.get_filetype(filename)
parser_class = self.source_parsers[filetype]
except FiletypeNotFoundError:
raise SphinxError(__('Source parser for %s not registered') % filename)
if parser_class is None:
raise SphinxError(__('Source parser for %s not registered') % filename)
raise SphinxError(__('Source parser for %s not registered') % filetype)
else:
return parser_class
@ -245,12 +270,10 @@ class SphinxComponentRegistry(object):
def get_source_input(self, filename):
# type: (unicode) -> Type[Input]
parser = self.get_source_parser(filename)
for filetype in parser.supported:
if filetype in self.source_inputs:
input_class = self.source_inputs[filetype]
break
else:
try:
filetype = self.get_filetype(filename)
input_class = self.source_inputs[filetype]
except FiletypeNotFoundError:
# use special source_input for unknown file-type '*' (if exists)
input_class = self.source_inputs.get('*')
@ -346,3 +369,25 @@ class SphinxComponentRegistry(object):
app.extensions[extname] = Extension(extname, mod, **metadata)
app._setting_up_extension.pop()
def merge_source_suffix(app):
# type: (Sphinx) -> None
"""Merge source_suffix which specified by user and added by extensions."""
for suffix in app.registry.source_suffix:
if suffix not in app.config.source_suffix:
app.config.source_suffix[suffix] = suffix
# copy config.source_suffix to registry
app.registry.source_suffix = app.config.source_suffix
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.connect('builder-inited', merge_source_suffix)
return {
'version': 'builtin',
'parallel_read_safe': True,
'parallel_write_safe': True,
}

View File

@ -52,7 +52,7 @@ def publish_msgstr(app, source, source_path, source_line, config, settings):
from sphinx.io import SphinxI18nReader
reader = SphinxI18nReader(app)
reader.set_lineno_for_reporter(source_line)
parser = app.registry.create_source_parser(app, '')
parser = app.registry.create_source_parser(app, '.rst')
doc = reader.read(
source=StringInput(source=source, source_path=source_path),
parser=parser,

View File

@ -84,7 +84,9 @@ def test_domain_override(app, status, warning):
@pytest.mark.sphinx(testroot='add_source_parser')
def test_add_source_parser(app, status, warning):
assert set(app.config.source_suffix) == set(['.rst', '.md', '.test'])
assert set(app.registry.get_source_parsers().keys()) == set(['*', '.md', '.test'])
assert '.rst' in app.registry.get_source_parsers()
assert '.md' in app.registry.get_source_parsers()
assert '.test' in app.registry.get_source_parsers()
assert app.registry.get_source_parsers()['.md'].__name__ == 'DummyMarkdownParser'
assert app.registry.get_source_parsers()['.test'].__name__ == 'TestSourceParser'