Merge "Add MappedListField"

This commit is contained in:
Zuul
2019-08-02 09:35:13 +00:00
committed by Gerrit Code Review
5 changed files with 67 additions and 8 deletions

View File

@@ -0,0 +1,5 @@
---
features:
- |
Adds a new field called ``MappedListField`` which supports a list of
mapped instances.

View File

@@ -258,6 +258,52 @@ class MappedField(Field):
adapter=mapping.get) adapter=mapping.get)
class MappedListField(Field):
"""Field taking a list of values with a mapping for the values
Given JSON {'field':['xxx', 'yyy']}, a sushy resource definition and
mapping {'xxx':'a', 'yyy':'b'}, the sushy object to come out will be like
resource.field = ['a', 'b']
"""
def __init__(self, field, mapping, required=False, default=None):
"""Create a mapped list field definition.
:param field: JSON field to fetch the list of values from.
:param mapping: a mapping for the list elements.
:param required: whether this field is required. Missing required
fields result in MissingAttributeError.
:param default: the default value to use when the field is missing.
Only has effect when the field is not required.
"""
if not isinstance(mapping, collectionsAbc.Mapping):
raise TypeError("The mapping argument must be a mapping")
self._mapping_adapter = mapping.get
super(MappedListField, self).__init__(
field, required=required, default=default,
adapter=lambda x: x)
def _load(self, body, resource, nested_in=None):
"""Load the mapped list.
:param body: parent JSON body.
:param resource: parent resource.
:param nested_in: parent resource name (for error reporting only).
:returns: a new list object containing the mapped values.
"""
nested_in = (nested_in or []) + self._path
values = super(MappedListField, self)._load(body, resource)
if values is None:
return
instances = [self._mapping_adapter(value) for value in values
if self._mapping_adapter(value) is not None]
return instances
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class AbstractJsonReader(object): class AbstractJsonReader(object):

View File

@@ -17,6 +17,7 @@ import logging
from sushy.resources import base from sushy.resources import base
from sushy.resources import common from sushy.resources import common
from sushy.resources import mappings as res_maps
from sushy.resources.system.storage import drive from sushy.resources.system.storage import drive
from sushy.resources.system.storage import volume from sushy.resources.system.storage import volume
from sushy import utils from sushy import utils
@@ -43,12 +44,12 @@ class StorageControllersListField(base.ListField):
speed_gbps = base.Field('SpeedGbps') speed_gbps = base.Field('SpeedGbps')
"""The maximum speed of the storage controller's device interface.""" """The maximum speed of the storage controller's device interface."""
controller_protocols = base.Field('SupportedControllerProtocols', controller_protocols = base.MappedListField(
adapter=list) 'SupportedControllerProtocols', res_maps.PROTOCOL_TYPE_VALUE_MAP)
"""The protocols by which this storage controller can be communicated to""" """The protocols by which this storage controller can be communicated to"""
device_protocols = base.Field('SupportedDeviceProtocols', device_protocols = base.MappedListField('SupportedDeviceProtocols',
adapter=list) res_maps.PROTOCOL_TYPE_VALUE_MAP)
"""The protocols which the controller can use tocommunicate with devices""" """The protocols which the controller can use tocommunicate with devices"""

View File

@@ -122,8 +122,10 @@ class StorageTestCase(base.TestCase):
identifier.durable_name_format) identifier.durable_name_format)
self.assertEqual('345C59DBD970859C', identifier.durable_name) self.assertEqual('345C59DBD970859C', identifier.durable_name)
self.assertEqual(12, controller.speed_gbps) self.assertEqual(12, controller.speed_gbps)
self.assertEqual(["PCIe"], controller.controller_protocols) self.assertEqual([sushy.PROTOCOL_TYPE_PCIe],
self.assertEqual(["SAS", "SATA"], controller.device_protocols) controller.controller_protocols)
self.assertEqual([sushy.PROTOCOL_TYPE_SAS, sushy.PROTOCOL_TYPE_SATA],
controller.device_protocols)
def test_drives_after_refresh(self): def test_drives_after_refresh(self):
self.storage.refresh() self.storage.refresh()

View File

@@ -294,7 +294,7 @@ class ResourceCollectionBaseTestCase(base.TestCase):
TEST_JSON = { TEST_JSON = {
'String': 'a string', 'String': 'a string',
'Integer': '42', 'Integer': '42',
'List': ['a string', 42], 'MappedList': ['raw1', 'raw2', 'raw'],
'Nested': { 'Nested': {
'String': 'another string', 'String': 'another string',
'Integer': 0, 'Integer': 0,
@@ -321,7 +321,9 @@ TEST_JSON = {
MAPPING = { MAPPING = {
'raw': 'real' 'raw': 'real',
'raw1': 'real1',
'raw2': 'real2'
} }
@@ -347,6 +349,7 @@ class ComplexResource(resource_base.ResourceBase):
string = resource_base.Field('String', required=True) string = resource_base.Field('String', required=True)
integer = resource_base.Field('Integer', adapter=int) integer = resource_base.Field('Integer', adapter=int)
nested = NestedTestField('Nested') nested = NestedTestField('Nested')
mapped_list = resource_base.MappedListField('MappedList', MAPPING)
field_list = TestListField('ListField') field_list = TestListField('ListField')
dictionary = TestDictionaryField('Dictionary') dictionary = TestDictionaryField('Dictionary')
non_existing_nested = NestedTestField('NonExistingNested') non_existing_nested = NestedTestField('NonExistingNested')
@@ -371,6 +374,8 @@ class FieldTestCase(base.TestCase):
self.assertEqual('field value', self.test_resource.nested.nested_field) self.assertEqual('field value', self.test_resource.nested.nested_field)
self.assertEqual('real', self.test_resource.nested.mapped) self.assertEqual('real', self.test_resource.nested.mapped)
self.assertEqual(3.14, self.test_resource.nested.non_existing) self.assertEqual(3.14, self.test_resource.nested.non_existing)
self.assertEqual(['real1', 'real2', 'real'],
self.test_resource.mapped_list)
self.assertEqual('a third string', self.assertEqual('a third string',
self.test_resource.field_list[0].string) self.test_resource.field_list[0].string)
self.assertEqual(2, self.test_resource.field_list[1].integer) self.assertEqual(2, self.test_resource.field_list[1].integer)