config: Return convereted values and errors

This commit is contained in:
Thomas Adamcik 2013-04-15 18:14:52 +02:00
parent a9a789aa8a
commit e4873c4516
3 changed files with 47 additions and 58 deletions

View File

@ -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

View File

@ -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

View File

@ -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'])