mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Checked configuration values for their types. Fixes #1150.
This commit is contained in:
parent
2710f705a1
commit
5cc72ca52b
@ -124,6 +124,7 @@ class Sphinx(object):
|
||||
self.config = Config(confdir, CONFIG_FILENAME,
|
||||
confoverrides or {}, self.tags)
|
||||
self.config.check_unicode(self.warn)
|
||||
# defer checking types until i18n has been initialized
|
||||
|
||||
# set confdir to srcdir if -C given (!= no confdir); a few pieces
|
||||
# of code expect a confdir to be set
|
||||
@ -172,6 +173,8 @@ class Sphinx(object):
|
||||
|
||||
# set up translation infrastructure
|
||||
self._init_i18n()
|
||||
# check all configuration values for permissible types
|
||||
self.config.check_types(self.warn)
|
||||
# set up the build environment
|
||||
self._init_env(freshenv)
|
||||
# set up the builder
|
||||
|
@ -14,7 +14,7 @@ from os import path
|
||||
|
||||
from six import PY3, iteritems, string_types, binary_type, integer_types
|
||||
|
||||
from sphinx.errors import ConfigError
|
||||
from sphinx.errors import ConfigError, ConfigWarning
|
||||
from sphinx.locale import l_
|
||||
from sphinx.util.osutil import make_filename, cd
|
||||
from sphinx.util.pycompat import execfile_
|
||||
@ -249,6 +249,30 @@ class Config(object):
|
||||
self.setup = config.get('setup', None)
|
||||
self.extensions = config.get('extensions', [])
|
||||
|
||||
def check_types(self, warn):
|
||||
# check all values for deviation from the default value's type, since
|
||||
# that can result in TypeErrors all over the place
|
||||
# NB. since config values might use l_() we have to wait with calling
|
||||
# this method until i18n is initialized
|
||||
for name in self._raw_config:
|
||||
if name not in Config.config_values:
|
||||
continue # we don't know a default value
|
||||
default, dummy_rebuild = Config.config_values[name]
|
||||
if hasattr(default, '__call__'):
|
||||
default = default(self) # could invoke l_()
|
||||
if default is None:
|
||||
continue
|
||||
current = self[name]
|
||||
if type(current) is type(default):
|
||||
continue
|
||||
common_bases = (
|
||||
set(type(current).__bases__) & set(type(default).__bases__))
|
||||
common_bases.discard(object)
|
||||
if common_bases:
|
||||
continue # at least we share a non-trivial base class
|
||||
warn("the config value %r has type `%s', defaults to `%s.'"
|
||||
% (name, type(current).__name__, type(default).__name__))
|
||||
|
||||
def check_unicode(self, warn):
|
||||
# check all string values for non-ASCII characters in bytestrings,
|
||||
# since that can result in UnicodeErrors all over the place
|
||||
@ -296,7 +320,6 @@ class Config(object):
|
||||
for name in config:
|
||||
if name in self.values:
|
||||
self.__dict__[name] = config[name]
|
||||
del self._raw_config
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith('_'):
|
||||
|
@ -3,8 +3,8 @@
|
||||
sphinx.errors
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Contains SphinxError and a few subclasses (in an extra module to avoid
|
||||
circular import problems).
|
||||
Contains SphinxError, a few subclasses (in an extra module to avoid
|
||||
circular import problems), and related classes.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
@ -75,3 +75,9 @@ class SphinxParallelError(Exception):
|
||||
def __str__(self):
|
||||
return traceback.format_exception_only(
|
||||
self.orig_exc.__class__, self.orig_exc)[0].strip()
|
||||
|
||||
class ConfigWarning(UserWarning):
|
||||
"""
|
||||
Base category for warnings about dubious configuration values.
|
||||
"""
|
||||
pass
|
||||
|
@ -133,3 +133,11 @@ def test_config_eol(tmpdir):
|
||||
cfg = Config(tmpdir, 'conf.py', {}, None)
|
||||
cfg.init_values(lambda warning: 1/0)
|
||||
assert cfg.project == u'spam'
|
||||
|
||||
|
||||
@with_app(confoverrides={'master_doc': 123})
|
||||
def test_check_types(app, status, warning):
|
||||
# WARNING: the config value 'master_doc' has type `int', defaults to `str.'
|
||||
assert any(buf.startswith('WARNING:')
|
||||
and 'master_doc' in buf and 'int' in buf and 'str' in buf
|
||||
for buf in warning.buflist)
|
||||
|
Loading…
Reference in New Issue
Block a user