config: Return convereted values and errors
This commit is contained in:
parent
a9a789aa8a
commit
e4873c4516
@ -90,8 +90,9 @@ def validate(raw_config, schemas, extensions=None):
|
||||
if errors:
|
||||
# TODO: raise error instead.
|
||||
#raise exceptions.ConfigError(errors)
|
||||
for error in errors:
|
||||
logger.error(error)
|
||||
for section in errors:
|
||||
for key, error in errors[section].items():
|
||||
logger.error('Config value %s/%s %s', section, key, error)
|
||||
sys.exit(1)
|
||||
|
||||
return config
|
||||
@ -101,17 +102,13 @@ def validate(raw_config, schemas, extensions=None):
|
||||
def _validate(raw_config, schemas):
|
||||
# Get validated config
|
||||
config = {}
|
||||
errors = []
|
||||
errors = {}
|
||||
for schema in schemas:
|
||||
try:
|
||||
items = raw_config[schema.name].items()
|
||||
config[schema.name] = schema.convert(items)
|
||||
except KeyError:
|
||||
errors.append('%s: section not found.' % schema.name)
|
||||
except exceptions.ConfigError as error:
|
||||
for key in error:
|
||||
errors.append('%s/%s: %s' % (schema.name, key, error[key]))
|
||||
# TODO: raise errors instead of return
|
||||
values = raw_config.get(schema.name, {})
|
||||
result, error = schema.convert(values)
|
||||
if error:
|
||||
errors[schema.name] = error
|
||||
config[schema.name] = result
|
||||
return config, errors
|
||||
|
||||
|
||||
|
||||
@ -71,15 +71,16 @@ class ConfigSchema(object):
|
||||
key, self._schema[key].format(value)))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def convert(self, items):
|
||||
"""Validates the given ``items`` using the config schema and returns
|
||||
clean values"""
|
||||
errors = {}
|
||||
values = {}
|
||||
def convert(self, values):
|
||||
"""Validates the given ``values`` using the config schema.
|
||||
|
||||
for key, value in items:
|
||||
Returns a tuple with cleaned values and errors."""
|
||||
errors = {}
|
||||
result = {}
|
||||
|
||||
for key, value in values.items():
|
||||
try:
|
||||
values[key] = self._schema[key].deserialize(value)
|
||||
result[key] = self._schema[key].deserialize(value)
|
||||
except KeyError: # not in our schema
|
||||
errors[key] = 'unknown config key.'
|
||||
suggestion = _did_you_mean(key, self._schema.keys())
|
||||
@ -89,12 +90,10 @@ class ConfigSchema(object):
|
||||
errors[key] = str(e)
|
||||
|
||||
for key in self._schema:
|
||||
if key not in values and key not in errors:
|
||||
if key not in result and key not in errors:
|
||||
errors[key] = 'config key not found.'
|
||||
|
||||
if errors:
|
||||
raise exceptions.ConfigError(errors)
|
||||
return values
|
||||
return result, errors
|
||||
|
||||
|
||||
class ExtensionConfigSchema(ConfigSchema):
|
||||
@ -106,6 +105,8 @@ class ExtensionConfigSchema(ConfigSchema):
|
||||
super(ExtensionConfigSchema, self).__init__(name)
|
||||
self['enabled'] = types.Boolean()
|
||||
|
||||
# TODO: override convert to gate on enabled=true?
|
||||
|
||||
|
||||
class LogLevelConfigSchema(object):
|
||||
"""Special cased schema for handling a config section with loglevels.
|
||||
@ -126,17 +127,13 @@ class LogLevelConfigSchema(object):
|
||||
key, self._config_value.format(value)))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def convert(self, items):
|
||||
def convert(self, values):
|
||||
errors = {}
|
||||
values = {}
|
||||
result = {}
|
||||
|
||||
for key, value in items:
|
||||
for key, value in values.items():
|
||||
try:
|
||||
if value.strip():
|
||||
values[key] = self._config_value.deserialize(value)
|
||||
result[key] = self._config_value.deserialize(value)
|
||||
except ValueError as e: # deserialization failed
|
||||
errors[key] = str(e)
|
||||
|
||||
if errors:
|
||||
raise exceptions.ConfigError(errors)
|
||||
return values
|
||||
return result, errors
|
||||
|
||||
@ -36,54 +36,49 @@ class ConfigSchemaTest(unittest.TestCase):
|
||||
self.assertNotIn('unknown = rty', result)
|
||||
|
||||
def test_convert(self):
|
||||
self.schema.convert(self.values.items())
|
||||
self.schema.convert(self.values)
|
||||
|
||||
def test_convert_with_missing_value(self):
|
||||
del self.values['foo']
|
||||
|
||||
with self.assertRaises(exceptions.ConfigError) as cm:
|
||||
self.schema.convert(self.values.items())
|
||||
|
||||
self.assertIn('not found', cm.exception['foo'])
|
||||
result, errors = self.schema.convert(self.values)
|
||||
self.assertIn('not found', errors['foo'])
|
||||
self.assertItemsEqual(['bar', 'baz'], result.keys())
|
||||
|
||||
def test_convert_with_extra_value(self):
|
||||
self.values['extra'] = '123'
|
||||
|
||||
with self.assertRaises(exceptions.ConfigError) as cm:
|
||||
self.schema.convert(self.values.items())
|
||||
|
||||
self.assertIn('unknown', cm.exception['extra'])
|
||||
result, errors = self.schema.convert(self.values)
|
||||
self.assertIn('unknown', errors['extra'])
|
||||
self.assertItemsEqual(['foo', 'bar', 'baz'], result.keys())
|
||||
|
||||
def test_convert_with_deserialization_error(self):
|
||||
self.schema['foo'].deserialize.side_effect = ValueError('failure')
|
||||
|
||||
with self.assertRaises(exceptions.ConfigError) as cm:
|
||||
self.schema.convert(self.values.items())
|
||||
|
||||
self.assertIn('failure', cm.exception['foo'])
|
||||
result, errors = self.schema.convert(self.values)
|
||||
self.assertIn('failure', errors['foo'])
|
||||
self.assertItemsEqual(['bar', 'baz'], result.keys())
|
||||
|
||||
def test_convert_with_multiple_deserialization_errors(self):
|
||||
self.schema['foo'].deserialize.side_effect = ValueError('failure')
|
||||
self.schema['bar'].deserialize.side_effect = ValueError('other')
|
||||
|
||||
with self.assertRaises(exceptions.ConfigError) as cm:
|
||||
self.schema.convert(self.values.items())
|
||||
|
||||
self.assertIn('failure', cm.exception['foo'])
|
||||
self.assertIn('other', cm.exception['bar'])
|
||||
result, errors = self.schema.convert(self.values)
|
||||
self.assertIn('failure', errors['foo'])
|
||||
self.assertIn('other', errors['bar'])
|
||||
self.assertItemsEqual(['baz'], result.keys())
|
||||
|
||||
def test_convert_deserialization_unknown_and_missing_errors(self):
|
||||
self.values['extra'] = '123'
|
||||
self.schema['bar'].deserialize.side_effect = ValueError('failure')
|
||||
del self.values['baz']
|
||||
|
||||
with self.assertRaises(exceptions.ConfigError) as cm:
|
||||
self.schema.convert(self.values.items())
|
||||
|
||||
self.assertIn('unknown', cm.exception['extra'])
|
||||
self.assertNotIn('foo', cm.exception)
|
||||
self.assertIn('failure', cm.exception['bar'])
|
||||
self.assertIn('not found', cm.exception['baz'])
|
||||
result, errors = self.schema.convert(self.values)
|
||||
self.assertIn('unknown', errors['extra'])
|
||||
self.assertNotIn('foo', errors)
|
||||
self.assertIn('failure', errors['bar'])
|
||||
self.assertIn('not found', errors['baz'])
|
||||
self.assertItemsEqual(['foo'], result.keys())
|
||||
|
||||
|
||||
class ExtensionConfigSchemaTest(unittest.TestCase):
|
||||
@ -95,7 +90,7 @@ class ExtensionConfigSchemaTest(unittest.TestCase):
|
||||
class LogLevelConfigSchemaTest(unittest.TestCase):
|
||||
def test_conversion(self):
|
||||
schema = schemas.LogLevelConfigSchema('test')
|
||||
result = schema.convert([('foo.bar', 'DEBUG'), ('baz', 'INFO')])
|
||||
result, errors = schema.convert({'foo.bar': 'DEBUG', 'baz': 'INFO'})
|
||||
|
||||
self.assertEqual(logging.DEBUG, result['foo.bar'])
|
||||
self.assertEqual(logging.INFO, result['baz'])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user