Add DictionaryField class to resource base

Add `DictionaryField` class capable of handling dictionaries in
resource body JSON.
This is necessary to be able to parse resources like Message
Registry:
"Messages": {
        "Success": {
            "Message": "Completed successfully",
            "Severity": "OK",
            [...]
        },
        "Failure": {
            "Message": "Failed",
            "Severity": "Critical",
            [...]
        }
}

Story: 2001791
Task: 23226
Change-Id: I8a0b6fe2dda4c244be4b7a0abaf601f533dd30f9
This commit is contained in:
Aija Jaunteva 2018-07-26 11:38:47 +03:00
parent 8f952f874b
commit 893ccec796
2 changed files with 49 additions and 1 deletions

View File

@ -187,6 +187,39 @@ class ListField(Field):
return instances
class DictionaryField(Field):
"""Base class for fields consisting of dictionary of several sub-fields."""
def __init__(self, *args, **kwargs):
super(DictionaryField, self).__init__(*args, **kwargs)
self._subfields = dict(_collect_fields(self))
def _load(self, body, resource, nested_in=None):
"""Load the dictionary.
:param body: parent JSON body.
:param resource: parent resource.
:param nested_in: parent resource name (for error reporting only).
:returns: a new dictionary object containing subfields.
"""
nested_in = (nested_in or []) + self._path
values = super(DictionaryField, self)._load(body, resource)
if values is None:
return None
instances = {}
for key, value in values.items():
instance_value = copy.copy(self)
for attr, field in self._subfields.items():
# Hide the Field object behind the real value
setattr(instance_value, attr, field._load(value,
resource,
nested_in))
instances[key] = instance_value
return instances
class MappedField(Field):
"""Field taking real value from a mapping."""

View File

@ -165,7 +165,11 @@ TEST_JSON = {
'String': 'a fourth string',
'Integer': 2
}
]
],
'Dictionary': {
'key1': {'property_a': 'value1', 'property_b': 'value2'},
'key2': {'property_a': 'value3', 'property_b': 'value4'}
}
}
@ -187,11 +191,17 @@ class TestListField(resource_base.ListField):
integer = resource_base.Field('Integer', adapter=int)
class TestDictionaryField(resource_base.DictionaryField):
property_a = resource_base.Field('property_a')
property_b = resource_base.Field('property_b')
class ComplexResource(resource_base.ResourceBase):
string = resource_base.Field('String', required=True)
integer = resource_base.Field('Integer', adapter=int)
nested = NestedTestField('Nested')
field_list = TestListField('ListField')
dictionary = TestDictionaryField('Dictionary')
non_existing_nested = NestedTestField('NonExistingNested')
non_existing_mapped = resource_base.MappedField('NonExistingMapped',
MAPPING)
@ -217,6 +227,11 @@ class FieldTestCase(base.TestCase):
self.assertEqual('a third string',
self.test_resource.field_list[0].string)
self.assertEqual(2, self.test_resource.field_list[1].integer)
self.assertEqual(2, len(self.test_resource.dictionary))
self.assertEqual('value1',
self.test_resource.dictionary['key1'].property_a)
self.assertEqual('value4',
self.test_resource.dictionary['key2'].property_b)
self.assertIsNone(self.test_resource.non_existing_nested)
self.assertIsNone(self.test_resource.non_existing_mapped)