Merge pull request #5400 from tk0miya/5399_find_catalog_crashes

Fix #5399: Sphinx crashes if unknown po file exists
This commit is contained in:
Takeshi KOMIYA 2018-09-09 18:38:21 +09:00 committed by GitHub
commit 578adb887f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 18 additions and 12 deletions

View File

@ -17,6 +17,8 @@ Deprecated
* ``sphinx.io.SphinxI18nReader.set_lineno_for_reporter()`` is deprecated * ``sphinx.io.SphinxI18nReader.set_lineno_for_reporter()`` is deprecated
* ``sphinx.io.SphinxI18nReader.line`` is deprecated * ``sphinx.io.SphinxI18nReader.line`` is deprecated
* ``sphinx.util.i18n.find_catalog_source_file()`` has changed; the
*gettext_compact* argument has been deprecated
Features added Features added
-------------- --------------
@ -41,6 +43,7 @@ Bugs fixed
* #2720, #4034: Incorrect links with ``:download:``, duplicate names, and * #2720, #4034: Incorrect links with ``:download:``, duplicate names, and
parallel builds parallel builds
* #5290: autodoc: failed to analyze source code in egg package * #5290: autodoc: failed to analyze source code in egg package
* #5399: Sphinx crashes if unknown po file exists
Testing Testing
-------- --------

View File

@ -136,6 +136,12 @@ The following is a list of deprecated interface.
- 4.0 - 4.0
- :confval:`autodoc_default_options` - :confval:`autodoc_default_options`
* - ``gettext_compact`` arguments of
``sphinx.util.i18n.find_catalog_source_files()``
- 1.8
- 3.0
- N/A
* - ``sphinx.io.SphinxI18nReader.set_lineno_for_reporter()`` * - ``sphinx.io.SphinxI18nReader.set_lineno_for_reporter()``
- 1.8 - 1.8
- 3.0 - 3.0

View File

@ -261,7 +261,6 @@ class Builder(object):
[path.join(self.srcdir, x) for x in self.config.locale_dirs], [path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language, self.config.language,
charset=self.config.source_encoding, charset=self.config.source_encoding,
gettext_compact=self.config.gettext_compact,
force_all=True, force_all=True,
excluded=Matcher(['**/.?**'])) excluded=Matcher(['**/.?**']))
message = __('all of %d po files') % len(catalogs) message = __('all of %d po files') % len(catalogs)
@ -284,7 +283,6 @@ class Builder(object):
self.config.language, self.config.language,
domains=list(specified_domains), domains=list(specified_domains),
charset=self.config.source_encoding, charset=self.config.source_encoding,
gettext_compact=self.config.gettext_compact,
excluded=Matcher(['**/.?**'])) excluded=Matcher(['**/.?**']))
message = __('targets for %d po files that are specified') % len(catalogs) message = __('targets for %d po files that are specified') % len(catalogs)
self.compile_catalogs(catalogs, message) self.compile_catalogs(catalogs, message)
@ -295,7 +293,6 @@ class Builder(object):
[path.join(self.srcdir, x) for x in self.config.locale_dirs], [path.join(self.srcdir, x) for x in self.config.locale_dirs],
self.config.language, self.config.language,
charset=self.config.source_encoding, charset=self.config.source_encoding,
gettext_compact=self.config.gettext_compact,
excluded=Matcher(['**/.?**'])) excluded=Matcher(['**/.?**']))
message = __('targets for %d po files that are out of date') % len(catalogs) message = __('targets for %d po files that are out of date') % len(catalogs)
self.compile_catalogs(catalogs, message) self.compile_catalogs(catalogs, message)

View File

@ -12,6 +12,7 @@ import gettext
import io import io
import os import os
import re import re
import warnings
from collections import namedtuple from collections import namedtuple
from datetime import datetime from datetime import datetime
from os import path from os import path
@ -20,6 +21,7 @@ import babel.dates
from babel.messages.mofile import write_mo from babel.messages.mofile import write_mo
from babel.messages.pofile import read_po from babel.messages.pofile import read_po
from sphinx.deprecation import RemovedInSphinx30Warning
from sphinx.errors import SphinxError from sphinx.errors import SphinxError
from sphinx.locale import __ from sphinx.locale import __
from sphinx.util import logging from sphinx.util import logging
@ -103,7 +105,7 @@ def find_catalog_files(docname, srcdir, locale_dirs, lang, compaction):
return files # type: ignore return files # type: ignore
def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact=False, def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact=None,
charset='utf-8', force_all=False, charset='utf-8', force_all=False,
excluded=Matcher([])): excluded=Matcher([])):
# type: (List[unicode], unicode, List[unicode], bool, unicode, bool, Matcher) -> Set[CatalogInfo] # NOQA # type: (List[unicode], unicode, List[unicode], bool, unicode, bool, Matcher) -> Set[CatalogInfo] # NOQA
@ -115,14 +117,15 @@ def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact
:param str locale: a language as `'en'` :param str locale: a language as `'en'`
:param list domains: list of domain names to get. If empty list or None :param list domains: list of domain names to get. If empty list or None
is specified, get all domain names. default is None. is specified, get all domain names. default is None.
:param boolean gettext_compact:
* False: keep domains directory structure (default).
* True: domains in the sub directory will be merged into 1 file.
:param boolean force_all: :param boolean force_all:
Set True if you want to get all catalogs rather than updated catalogs. Set True if you want to get all catalogs rather than updated catalogs.
default is False. default is False.
:return: [CatalogInfo(), ...] :return: [CatalogInfo(), ...]
""" """
if gettext_compact is not None:
warnings.warn('gettext_compact argument for find_catalog_source_files() '
'is deprecated.', RemovedInSphinx30Warning)
catalogs = set() # type: Set[CatalogInfo] catalogs = set() # type: Set[CatalogInfo]
if not locale: if not locale:
@ -143,10 +146,7 @@ def find_catalog_source_files(locale_dirs, locale, domains=None, gettext_compact
if excluded(path.join(relpath(dirpath, base_dir), filename)): if excluded(path.join(relpath(dirpath, base_dir), filename)):
continue continue
base = path.splitext(filename)[0] base = path.splitext(filename)[0]
domain = relpath(path.join(dirpath, base), base_dir) domain = relpath(path.join(dirpath, base), base_dir).replace(path.sep, SEP)
if gettext_compact and path.sep in domain:
domain = path.split(domain)[0]
domain = domain.replace(path.sep, SEP)
if domains and domain not in domains: if domains and domain not in domains:
continue continue
cat = CatalogInfo(base_dir, domain, charset) cat = CatalogInfo(base_dir, domain, charset)

View File

@ -154,7 +154,7 @@ def test_get_catalogs_with_compact(tempdir):
catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', gettext_compact=True) catalogs = i18n.find_catalog_source_files([tempdir / 'loc1'], 'xx', gettext_compact=True)
domains = set(c.domain for c in catalogs) domains = set(c.domain for c in catalogs)
assert domains == set(['test1', 'test2', 'sub']) assert domains == set(['test1', 'test2', 'sub/test3', 'sub/test4'])
def test_get_catalogs_excluded(tempdir): def test_get_catalogs_excluded(tempdir):