diff options
author | Robert Lehmann <mail@robertlehmann.de> | 2014-10-30 15:46:02 +0100 |
---|---|---|
committer | Robert Lehmann <mail@robertlehmann.de> | 2014-10-30 15:46:02 +0100 |
commit | cfe0b5cc6dcf0484ca75d08671d3be706e122c89 (patch) | |
tree | 7a9baff241c3c59d7c25c310829fa5760f502f45 | |
parent | 1017e6815c5a199afcbe239c91818c5ff48b94eb (diff) | |
download | sphinx-cfe0b5cc6dcf0484ca75d08671d3be706e122c89.tar.gz |
Checked configuration values for their types. Fixes #1150.
-rw-r--r-- | sphinx/application.py | 3 | ||||
-rw-r--r-- | sphinx/config.py | 27 | ||||
-rw-r--r-- | sphinx/errors.py | 10 | ||||
-rw-r--r-- | tests/test_config.py | 8 |
4 files changed, 44 insertions, 4 deletions
diff --git a/sphinx/application.py b/sphinx/application.py index 630bff36..5f6b92f5 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -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 diff --git a/sphinx/config.py b/sphinx/config.py index cf6bed08..be30d1ea 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -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('_'): diff --git a/sphinx/errors.py b/sphinx/errors.py index 3d7a5eb4..4e9828dc 100644 --- a/sphinx/errors.py +++ b/sphinx/errors.py @@ -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 diff --git a/tests/test_config.py b/tests/test_config.py index 0dcf3fa3..c11c0721 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -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) |