config: Rename convert to deserialize

This commit is contained in:
Thomas Adamcik 2013-04-15 19:50:51 +02:00
parent e4873c4516
commit f5cd806dc5
4 changed files with 62 additions and 53 deletions

View File

@ -105,10 +105,11 @@ def _validate(raw_config, schemas):
errors = {}
for schema in schemas:
values = raw_config.get(schema.name, {})
result, error = schema.convert(values)
result, error = schema.deserialize(values)
if error:
errors[schema.name] = error
config[schema.name] = result
if result:
config[schema.name] = result
return config, errors

View File

@ -40,9 +40,11 @@ class ConfigSchema(object):
"""Logical group of config values that correspond to a config section.
Schemas are set up by assigning config keys with config values to
instances. Once setup :meth:`convert` can be called with a list of
``(key, value)`` tuples to process. For convienience we also support
:meth:`format` method that can used for printing out the converted values.
instances. Once setup :meth:`deserialize` can be called with a dict of
values to process. For convienience we also support :meth:`format` method
that can used for converting the values to a dict that can be printed and
:meth:`serialize` for converting the values to a form suitable for
persistence.
"""
# TODO: Use collections.OrderedDict once 2.6 support is gone (#344)
def __init__(self, name):
@ -58,20 +60,7 @@ class ConfigSchema(object):
def __getitem__(self, key):
return self._schema[key]
def format(self, values):
"""Returns the schema as a config section with the given ``values``
filled in"""
# TODO: should the output be encoded utf-8 since we use that in
# serialize for strings?
lines = ['[%s]' % self.name]
for key in self._order:
value = values.get(key)
if value is not None:
lines.append('%s = %s' % (
key, self._schema[key].format(value)))
return '\n'.join(lines)
def convert(self, values):
def deserialize(self, values):
"""Validates the given ``values`` using the config schema.
Returns a tuple with cleaned values and errors."""
@ -95,6 +84,23 @@ class ConfigSchema(object):
return result, errors
def serialize(self, values):
pass
def format(self, values):
"""Returns the schema as a config section with the given ``values``
filled in"""
# TODO: should the output be encoded utf-8 since we use that in
# serialize for strings?
lines = ['[%s]' % self.name]
for key in self._order:
value = values.get(key)
if value is not None:
lines.append('%s = %s' % (
key, self._schema[key].format(value)))
return '\n'.join(lines)
class ExtensionConfigSchema(ConfigSchema):
"""Sub-classed :class:`ConfigSchema` for use in extensions.
@ -105,7 +111,7 @@ class ExtensionConfigSchema(ConfigSchema):
super(ExtensionConfigSchema, self).__init__(name)
self['enabled'] = types.Boolean()
# TODO: override convert to gate on enabled=true?
# TODO: override serialize to gate on enabled=true?
class LogLevelConfigSchema(object):
@ -119,15 +125,7 @@ class LogLevelConfigSchema(object):
self.name = name
self._config_value = types.LogLevel()
def format(self, values):
lines = ['[%s]' % self.name]
for key, value in sorted(values.items()):
if value is not None:
lines.append('%s = %s' % (
key, self._config_value.format(value)))
return '\n'.join(lines)
def convert(self, values):
def deserialize(self, values):
errors = {}
result = {}
@ -137,3 +135,14 @@ class LogLevelConfigSchema(object):
except ValueError as e: # deserialization failed
errors[key] = str(e)
return result, errors
def serialize(self, values):
pass
def format(self, values):
lines = ['[%s]' % self.name]
for key, value in sorted(values.items()):
if value is not None:
lines.append('%s = %s' % (
key, self._config_value.format(value)))
return '\n'.join(lines)

View File

@ -53,38 +53,38 @@ class LoadConfigTest(unittest.TestCase):
class ValidateTest(unittest.TestCase):
def setUp(self):
self.schema = mock.Mock()
self.schema.name = 'foo'
self.schema = config.ConfigSchema('foo')
self.schema['bar'] = config.ConfigValue()
def test_empty_config_no_schemas(self):
conf, errors = config._validate({}, [])
self.assertEqual({}, conf)
self.assertEqual([], errors)
self.assertEqual({}, errors)
def test_config_no_schemas(self):
raw_config = {'foo': {'bar': 'baz'}}
conf, errors = config._validate(raw_config, [])
self.assertEqual({}, conf)
self.assertEqual([], errors)
self.assertEqual({}, errors)
def test_empty_config_single_schema(self):
conf, errors = config._validate({}, [self.schema])
self.assertEqual({}, conf)
self.assertEqual(['foo: section not found.'], errors)
self.assertEqual({'foo': {'bar': 'config key not found.'}}, errors)
def test_config_single_schema(self):
raw_config = {'foo': {'bar': 'baz'}}
self.schema.convert.return_value = {'baz': 'bar'}
conf, errors = config._validate(raw_config, [self.schema])
self.assertEqual({'foo': {'baz': 'bar'}}, conf)
self.assertEqual([], errors)
self.assertEqual({'foo': {'bar': 'baz'}}, conf)
self.assertEqual({}, errors)
def test_config_single_schema_config_error(self):
raw_config = {'foo': {'bar': 'baz'}}
self.schema.convert.side_effect = exceptions.ConfigError({'bar': 'bad'})
self.schema['bar'] = mock.Mock()
self.schema['bar'].deserialize.side_effect = ValueError('bad')
conf, errors = config._validate(raw_config, [self.schema])
self.assertEqual(['foo/bar: bad'], errors)
self.assertEqual({}, conf)
self.assertEqual({'foo': {'bar': 'bad'}}, errors)
# TODO: add more tests

View File

@ -35,45 +35,44 @@ class ConfigSchemaTest(unittest.TestCase):
result = self.schema.format(self.values)
self.assertNotIn('unknown = rty', result)
def test_convert(self):
self.schema.convert(self.values)
def test_deserialize(self):
self.schema.deserialize(self.values)
def test_convert_with_missing_value(self):
def test_deserialize_with_missing_value(self):
del self.values['foo']
result, errors = self.schema.convert(self.values)
result, errors = self.schema.deserialize(self.values)
self.assertIn('not found', errors['foo'])
self.assertItemsEqual(['bar', 'baz'], result.keys())
def test_convert_with_extra_value(self):
def test_deserialize_with_extra_value(self):
self.values['extra'] = '123'
result, errors = self.schema.convert(self.values)
result, errors = self.schema.deserialize(self.values)
self.assertIn('unknown', errors['extra'])
self.assertItemsEqual(['foo', 'bar', 'baz'], result.keys())
def test_convert_with_deserialization_error(self):
def test_deserialize_with_deserialization_error(self):
self.schema['foo'].deserialize.side_effect = ValueError('failure')
result, errors = self.schema.convert(self.values)
result, errors = self.schema.deserialize(self.values)
self.assertIn('failure', errors['foo'])
self.assertItemsEqual(['bar', 'baz'], result.keys())
def test_convert_with_multiple_deserialization_errors(self):
def test_deserialize_with_multiple_deserialization_errors(self):
self.schema['foo'].deserialize.side_effect = ValueError('failure')
self.schema['bar'].deserialize.side_effect = ValueError('other')
result, errors = self.schema.convert(self.values)
result, errors = self.schema.deserialize(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):
def test_deserialize_deserialization_unknown_and_missing_errors(self):
self.values['extra'] = '123'
self.schema['bar'].deserialize.side_effect = ValueError('failure')
del self.values['baz']
result, errors = self.schema.convert(self.values)
result, errors = self.schema.deserialize(self.values)
self.assertIn('unknown', errors['extra'])
self.assertNotIn('foo', errors)
self.assertIn('failure', errors['bar'])
@ -90,7 +89,7 @@ class ExtensionConfigSchemaTest(unittest.TestCase):
class LogLevelConfigSchemaTest(unittest.TestCase):
def test_conversion(self):
schema = schemas.LogLevelConfigSchema('test')
result, errors = schema.convert({'foo.bar': 'DEBUG', 'baz': 'INFO'})
result, errors = schema.deserialize({'foo.bar': 'DEBUG', 'baz': 'INFO'})
self.assertEqual(logging.DEBUG, result['foo.bar'])
self.assertEqual(logging.INFO, result['baz'])