Implemented type args in config schema; added 'enum' and 'regex' types
Change-Id: I7ae8054aaca977ee4e74eace9ca4dce59834ec92
This commit is contained in:
parent
aae261e036
commit
e0c1b9d2aa
|
@ -132,7 +132,7 @@ class Configuration(object):
|
|||
if param_schema:
|
||||
type_validator = TypeValidatorRegistry.get_validator(
|
||||
param_schema.type)
|
||||
type_validation_result = type_validator.validate(value)
|
||||
type_validation_result = type_validator.validate(value, **param_schema.type_args)
|
||||
if not isinstance(type_validation_result, InvalidValueError):
|
||||
value = type_validation_result
|
||||
|
||||
|
@ -159,7 +159,7 @@ class Configuration(object):
|
|||
|
||||
type_validator = TypeValidatorRegistry.get_validator(
|
||||
param_schema.type)
|
||||
type_validation_result = type_validator.validate(value)
|
||||
type_validation_result = type_validator.validate(value, **param_schema.type_args)
|
||||
if not isinstance(type_validation_result, InvalidValueError):
|
||||
return None
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ class ConfigSchemaRegistry:
|
|||
|
||||
param = ConfigParameterSchema(
|
||||
name, param_data['type'], section=section,
|
||||
type_args=param_data.get('type_args', {}),
|
||||
default=param_data.get('default', None),
|
||||
description=param_data.get('help', None),
|
||||
required=param_data.get('required', False),
|
||||
|
@ -127,11 +128,12 @@ class ConfigSchema:
|
|||
|
||||
class ConfigParameterSchema:
|
||||
|
||||
def __init__(self, name, type, section=None, description=None,
|
||||
def __init__(self, name, type, type_args={}, section=None, description=None,
|
||||
default=None, required=False, deprecation_message=None):
|
||||
self.section = section
|
||||
self.section = section or 'DEFAULT'
|
||||
self.name = name
|
||||
self.type = type
|
||||
self.type_args = type_args
|
||||
self.fullname = param_fullname(name, section)
|
||||
self.description = description
|
||||
self.default = default
|
||||
|
@ -183,10 +185,10 @@ class TypeValidator(object):
|
|||
self.base_type = base_type
|
||||
self.f = f
|
||||
|
||||
def validate(self, value):
|
||||
def validate(self, value, **kwargs):
|
||||
if value is None:
|
||||
return value
|
||||
return getattr(self, 'f')(value)
|
||||
return getattr(self, 'f')(value, **kwargs)
|
||||
|
||||
|
||||
def type_validator(name, base_type=None, default=False, **kwargs):
|
||||
|
@ -194,8 +196,8 @@ def type_validator(name, base_type=None, default=False, **kwargs):
|
|||
base_type = name
|
||||
|
||||
def wrap(fn):
|
||||
def wrapped(s):
|
||||
return fn(s, **kwargs)
|
||||
def wrapped(s, **immediate_kwargs):
|
||||
return fn(s, **dict(kwargs, **immediate_kwargs))
|
||||
o = TypeValidator(base_type, wrapped)
|
||||
TypeValidatorRegistry.register_validator(name, o, default=default)
|
||||
return fn
|
||||
|
@ -221,16 +223,19 @@ def validate_boolean(s):
|
|||
return InvalidValueError('Value should be "true" or "false"')
|
||||
|
||||
|
||||
@type_validator('enum')
|
||||
def validate_enum(s, values=[]):
|
||||
if s in values:
|
||||
return None
|
||||
if len(values) == 0:
|
||||
message = 'There should be no value'
|
||||
message = 'There should be no value, but found %s' % repr(s)
|
||||
elif len(values) == 1:
|
||||
message = 'The only valid value is %s' % values[0]
|
||||
message = 'The only valid value is "%s", but found "%s"' % (
|
||||
repr(values[0]), repr(s))
|
||||
else:
|
||||
message = 'Valid values are %s and %s' % (
|
||||
', '.join(values[:-1]), values[-1])
|
||||
message = 'Valid values are %s and %s, but found %s' % (
|
||||
', '.join([repr(v) for v in values[:-1]]),
|
||||
repr(values[-1]), repr(s))
|
||||
return InvalidValueError('%s' % message)
|
||||
|
||||
|
||||
|
@ -390,12 +395,22 @@ def validate_host_and_port(s, default_port=None):
|
|||
@type_validator('multi', base_type='multi')
|
||||
@type_validator('file', base_type='string')
|
||||
@type_validator('directory', base_type='string')
|
||||
@type_validator('regex', base_type='string')
|
||||
@type_validator('host_v6', base_type='string')
|
||||
def validate_string(s):
|
||||
return s
|
||||
|
||||
|
||||
@type_validator('regex', base_type='string')
|
||||
@type_validator('regexp', base_type='string')
|
||||
def validate_regex(s):
|
||||
try:
|
||||
re.compile(s)
|
||||
except re.error as e:
|
||||
return InvalidValueError(str(e))
|
||||
|
||||
return s
|
||||
|
||||
|
||||
@type_validator('integer')
|
||||
def validate_integer(s, min=None, max=None):
|
||||
if isinstance(s, int):
|
||||
|
|
|
@ -118,7 +118,8 @@ def generate_project_schema(project):
|
|||
param['type'] = prev_param['type']
|
||||
|
||||
if param.get('default', None) is not None:
|
||||
value = validator.validate(param['default'])
|
||||
type_args = param.get('type_args', {})
|
||||
value = validator.validate(param['default'], **type_args)
|
||||
if not isinstance(value, Issue):
|
||||
param['default'] = value
|
||||
else:
|
||||
|
@ -217,7 +218,8 @@ def generate_project_schema(project):
|
|||
param['default'] = old_param['default']
|
||||
|
||||
if param.get('default', None) is not None:
|
||||
value = validator.validate(old_param['default'])
|
||||
type_args = old_param.get('type_args', {})
|
||||
value = validator.validate(old_param['default'], **type_args)
|
||||
if not isinstance(value, Issue):
|
||||
param['default'] = value
|
||||
else:
|
||||
|
|
|
@ -9,12 +9,13 @@ class TypeValidatorTestHelper(object):
|
|||
super(TypeValidatorTestHelper, self).setUp()
|
||||
self.validator = TypeValidatorRegistry.get_validator(self.type_name)
|
||||
|
||||
def assertValid(self, value):
|
||||
self.assertNotIsInstance(self.validator.validate(value), Issue)
|
||||
def assertValid(self, value, type_args={}):
|
||||
self.assertNotIsInstance(
|
||||
self.validator.validate(value, **type_args), Issue)
|
||||
|
||||
def assertInvalid(self, value):
|
||||
def assertInvalid(self, value, type_args={}):
|
||||
self.assertIsInstance(
|
||||
self.validator.validate(value), Issue)
|
||||
self.validator.validate(value, **type_args), Issue)
|
||||
|
||||
|
||||
class StringTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase):
|
||||
|
@ -31,6 +32,19 @@ class StringTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase):
|
|||
self.assertEqual(s, self.validator.validate(s))
|
||||
|
||||
|
||||
class EnumTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase):
|
||||
type_name = 'enum'
|
||||
|
||||
def test_listed_value(self):
|
||||
self.assertValid('foo', type_args={'values': ['foo', 'bar']})
|
||||
|
||||
def test_unlisted_value(self):
|
||||
self.assertInvalid('baz', type_args={'values': ['foo', 'bar']})
|
||||
|
||||
def test_with_no_values_returns_error(self):
|
||||
self.assertInvalid('foo')
|
||||
|
||||
|
||||
class BooleanTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase):
|
||||
type_name = 'boolean'
|
||||
|
||||
|
@ -250,6 +264,16 @@ class HostAndPortTypeValidatorTests(TypeValidatorTestHelper,
|
|||
self.assertInvalid('10.0.0.1:65536')
|
||||
|
||||
|
||||
class RegexTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase):
|
||||
type_name = 'regex'
|
||||
|
||||
def test_valid_regex(self):
|
||||
self.assertValid('\d+\.\d+\.\d+\.\d+')
|
||||
|
||||
def test_invalid_regex(self):
|
||||
self.assertInvalid('(\d+')
|
||||
|
||||
|
||||
class StringListTypeValidatorTests(TypeValidatorTestHelper, unittest.TestCase):
|
||||
type_name = 'string_list'
|
||||
|
||||
|
|
Loading…
Reference in New Issue