config: Add ConfigValue base class and tests.

This commit is contained in:
Thomas Adamcik 2013-04-01 13:04:58 +02:00
parent ba425d8ccb
commit c22f0f5f9d
2 changed files with 88 additions and 0 deletions

View File

@ -17,3 +17,56 @@ def validate_maximum(value, maximum):
"""Maximum validation, normally called in config value's validate()."""
if maximum is not None and value > maximum:
raise ValueError('must be smaller than %s.' % maximum)
class ConfigValue(object):
"""Represents a config key's value and how to handle it.
Normally you will only be interacting with sub-classes for config values
that encode either deserialization behavior and/or validation.
Each config value should be used for the following actions:
1. Deserializing from a raw string and validating, raising ValueError on
failure.
2. Serializing a value back to a string that can be stored in a config.
3. Formatting a value to a printable form (useful for masking secrets).
:class:`None` values should not be deserialized, serialized or formatted,
the code interacting with the config should simply skip None config values.
"""
#: Collection of valid choices for converted value. Must be combined with
#: :function:`validate_choices` in :method:`validate` do any thing.
choices = None
#: Minimum of converted value. Must be combined with
#: :function:`validate_minimum` in :method:`validate` do any thing.
minimum = None
#: Maximum of converted value. Must be combined with
#: :function:`validate_maximum` in :method:`validate` do any thing.
maximum = None
#: Indicate if we should mask the when printing for human consumption.
secret = None
def __init__(self, choices=None, minimum=None, maximum=None, secret=None):
self.choices = choices
self.minimum = minimum
self.maximum = maximum
self.secret = secret
def deserialize(self, value):
"""Cast raw string to appropriate type."""
return value
def serialize(self, value):
"""Convert value back to string for saving."""
return str(value)
def format(self, value):
"""Format value for display."""
if self.secret:
return '********'
return self.serialize(value)

View File

@ -51,3 +51,38 @@ class ValidateMaximumTest(unittest.TestCase):
def test_to_large_value_fails_with_zero_as_maximum(self):
with self.assertRaises(ValueError):
config.validate_maximum(5, 0)
class ConfigValueTest(unittest.TestCase):
def test_init(self):
value = config.ConfigValue()
self.assertIsNone(value.choices)
self.assertIsNone(value.minimum)
self.assertIsNone(value.maximum)
self.assertIsNone(value.secret)
def test_init_with_params(self):
value = config.ConfigValue(
choices=['foo'], minimum=0, maximum=10, secret=True)
self.assertEqual(['foo'], value.choices)
self.assertEqual(0, value.minimum)
self.assertEqual(10, value.maximum)
self.assertEqual(True, value.secret)
def test_deserialize_passes_through(self):
value = config.ConfigValue()
obj = object()
self.assertEqual(obj, value.deserialize(obj))
def test_serialize_converts_to_string(self):
value = config.ConfigValue()
self.assertIsInstance(value.serialize(object()), basestring)
def test_format_uses_serialize(self):
value = config.ConfigValue()
obj = object()
self.assertEqual(value.serialize(obj), value.format(obj))
def test_format_masks_secrets(self):
value = config.ConfigValue(secret=True)
self.assertEqual('********', value.format(object()))