config: Rename convert to deserialize
This commit is contained in:
parent
e4873c4516
commit
f5cd806dc5
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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'])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user