Enable conversion for composite attribute items
Bug 1207881 Enable 'dict validators' to convert composite attributes' items using a 'convert_to' specification in a way similar to first-level API attributes. This is needed in order to ensure boolean sub-attributes are properly handled. Change-Id: I7f466befaa88112cf7e9b77d854ac292b2af638f
This commit is contained in:
parent
256f9743a3
commit
b8b28bd679
@ -320,6 +320,29 @@ def _validate_uuid_list(data, valid_values=None):
|
||||
return msg
|
||||
|
||||
|
||||
def _validate_dict_item(key, key_validator, data):
|
||||
# Find conversion function, if any, and apply it
|
||||
conv_func = key_validator.get('convert_to')
|
||||
if conv_func:
|
||||
data[key] = conv_func(data.get(key))
|
||||
# Find validator function
|
||||
# TODO(salv-orlando): Structure of dict attributes should be improved
|
||||
# to avoid iterating over items
|
||||
val_func = val_params = None
|
||||
for (k, v) in key_validator.iteritems():
|
||||
if k.startswith('type:'):
|
||||
# ask forgiveness, not permission
|
||||
try:
|
||||
val_func = validators[k]
|
||||
except KeyError:
|
||||
return _("Validator '%s' does not exist.") % k
|
||||
val_params = v
|
||||
break
|
||||
# Process validation
|
||||
if val_func:
|
||||
return val_func(data.get(key), val_params)
|
||||
|
||||
|
||||
def _validate_dict(data, key_specs=None):
|
||||
if not isinstance(data, dict):
|
||||
msg = _("'%s' is not a dictionary") % data
|
||||
@ -339,25 +362,14 @@ def _validate_dict(data, key_specs=None):
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
# Perform validation of all values according to the specifications.
|
||||
# Perform validation and conversion of all values
|
||||
# according to the specifications.
|
||||
for key, key_validator in [(k, v) for k, v in key_specs.iteritems()
|
||||
if k in data]:
|
||||
|
||||
for val_name in [n for n in key_validator.iterkeys()
|
||||
if n.startswith('type:')]:
|
||||
# Check whether specified validator exists.
|
||||
if val_name not in validators:
|
||||
msg = _("Validator '%s' does not exist.") % val_name
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
val_func = validators[val_name]
|
||||
val_params = key_validator[val_name]
|
||||
|
||||
msg = val_func(data.get(key), val_params)
|
||||
if msg:
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
msg = _validate_dict_item(key, key_validator, data)
|
||||
if msg:
|
||||
LOG.debug(msg)
|
||||
return msg
|
||||
|
||||
|
||||
def _validate_dict_or_none(data, key_specs=None):
|
||||
|
@ -19,6 +19,7 @@
|
||||
#
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.api.v2 import attributes as attrs
|
||||
from neutron.common import exceptions as qexception
|
||||
from neutron.extensions import l3
|
||||
|
||||
@ -37,7 +38,8 @@ EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'validate':
|
||||
{'type:dict_or_nodata':
|
||||
{'network_id': {'type:uuid': None, 'required': True},
|
||||
'enable_snat': {'type:boolean': None, 'required': False}}
|
||||
'enable_snat': {'type:boolean': None, 'required': False,
|
||||
'convert_to': attrs.convert_to_boolean}}
|
||||
}}}}
|
||||
|
||||
|
||||
|
@ -537,6 +537,20 @@ class TestAttributes(base.BaseTestCase):
|
||||
msg = attributes._validate_dict(dictionary, constraints)
|
||||
self.assertIsNotNone(msg)
|
||||
|
||||
def test_validate_dict_convert_boolean(self):
|
||||
dictionary, constraints = self._construct_dict_and_constraints()
|
||||
|
||||
constraints['key_bool'] = {
|
||||
'type:boolean': None,
|
||||
'required': False,
|
||||
'convert_to': attributes.convert_to_boolean}
|
||||
dictionary['key_bool'] = 'true'
|
||||
msg = attributes._validate_dict(dictionary, constraints)
|
||||
self.assertIsNone(msg)
|
||||
# Explicitly comparing with literal 'True' as assertTrue
|
||||
# succeeds also for 'true'
|
||||
self.assertIs(True, dictionary['key_bool'])
|
||||
|
||||
def test_subdictionary(self):
|
||||
dictionary, constraints = self._construct_dict_and_constraints()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user