Add sphinx.config.ENUM to check the config values is in candidates

This commit is contained in:
Takeshi KOMIYA 2016-07-03 23:55:15 +09:00
parent d984852908
commit 5991bbe4ac
4 changed files with 46 additions and 12 deletions

View File

@ -64,6 +64,7 @@ Features added
* latex, make the use of ``\small`` for code listings customizable (ref #2721)
* #2663: Add ``--warning-is-error`` option to setup.py command
* Show warnings if deprecated latex options are used
* Add sphinx.config.ENUM to check the config values is in candidates
Bugs fixed

View File

@ -28,10 +28,25 @@ if PY3:
CONFIG_SYNTAX_ERROR += "\nDid you change the syntax from 2.x to 3.x?"
CONFIG_EXIT_ERROR = "The configuration file (or one of the modules it imports) " \
"called sys.exit()"
CONFIG_ENUM_WARNING = "The config value `{name}` has to be a one of {candidates}, " \
"but `{current}` is given."
CONFIG_TYPE_WARNING = "The config value `{name}' has type `{current.__name__}', " \
"defaults to `{default.__name__}.'"
class ENUM:
"""represents the config value should be a one of candidates.
Example:
app.add_config_value('latex_show_urls', 'no', ENUM('no', 'footnote', 'inline'))
"""
def __init__(self, *candidates):
self.candidates = candidates
def match(self, value):
return value in self.candidates
string_classes = [text_type]
if PY2:
string_classes.append(binary_type) # => [str, unicode]
@ -150,19 +165,24 @@ class Config(object):
if default is None and not permitted:
continue # neither inferrable nor expliclitly permitted types
current = self[name]
if type(current) is type(default):
continue
if type(current) in permitted:
continue
if isinstance(permitted, ENUM):
if not permitted.match(current):
warn(CONFIG_ENUM_WARNING.format(
name=name, current=current, candidates=permitted.candidates))
else:
if type(current) is type(default):
continue
if type(current) in permitted:
continue
common_bases = (set(type(current).__bases__ + (type(current),)) &
set(type(default).__bases__))
common_bases.discard(object)
if common_bases:
continue # at least we share a non-trivial base class
common_bases = (set(type(current).__bases__ + (type(current),)) &
set(type(default).__bases__))
common_bases.discard(object)
if common_bases:
continue # at least we share a non-trivial base class
warn(CONFIG_TYPE_WARNING.format(
name=name, current=type(current), default=type(default)))
warn(CONFIG_TYPE_WARNING.format(
name=name, current=type(current), default=type(default)))
def check_unicode(self, warn):
# check all string values for non-ASCII characters in bytestrings,

View File

@ -1,4 +1,4 @@
from sphinx.config import string_classes
from sphinx.config import string_classes, ENUM
value1 = 123 # wrong type
value2 = 123 # lambda with wrong type
@ -45,3 +45,4 @@ def setup(app):
app.add_config_value('value14', None, False, string_classes)
app.add_config_value('value15', u'unicode', False)
app.add_config_value('value16', u'unicode', False)
app.add_config_value('value17', 'default', False, ENUM('default', 'one', 'two'))

View File

@ -206,3 +206,15 @@ def test_gen_check_types(app, status, warning):
'override on "%s" should%s raise a type warning' %
(key, '' if should else ' NOT')
)
@with_app(testroot='config')
def test_check_enum(app, status, warning):
assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \
not in warning.getvalue()
@with_app(testroot='config', confoverrides={'value17': 'invalid'})
def test_check_enum_failed(app, status, warning):
assert "The config value `value17` has to be a one of ('default', 'one', 'two'), " \
"but `invalid` is given." in warning.getvalue()