Move our ObjectListBase to subclass from the Oslo one
This lets us drop a lot of the stuff in our object list base class in favor of what is provided by oslo. Note that a couple of methods have to be added in there temporarily because they are on the oslo base object class, which we don't yet inherit from. Related to blueprint use-oslo-objects Change-Id: If5514804f6cd2f54eb103e887575f036edebfcee
This commit is contained in:
parent
2a5b1db132
commit
d5faff1ff2
|
@ -675,78 +675,21 @@ class NovaPersistentObject(object):
|
|||
}
|
||||
|
||||
|
||||
class ObjectListBase(object):
|
||||
"""Mixin class for lists of objects.
|
||||
class ObjectListBase(ovoo_base.ObjectListBase):
|
||||
# NOTE(danms): These are for transition to using the oslo
|
||||
# base object and can be removed when we move to it.
|
||||
@classmethod
|
||||
def _obj_primitive_key(cls, field):
|
||||
return 'nova_object.%s' % field
|
||||
|
||||
This mixin class can be added as a base class for an object that
|
||||
is implementing a list of objects. It adds a single field of 'objects',
|
||||
which is the list store, and behaves like a list itself. It supports
|
||||
serialization of the list of objects automatically.
|
||||
"""
|
||||
fields = {
|
||||
'objects': obj_fields.ListOfObjectsField('NovaObject'),
|
||||
}
|
||||
|
||||
# This is a dictionary of my_version:child_version mappings so that
|
||||
# we can support backleveling our contents based on the version
|
||||
# requested of the list object.
|
||||
child_versions = {}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ObjectListBase, self).__init__(*args, **kwargs)
|
||||
if 'objects' not in kwargs:
|
||||
self.objects = []
|
||||
self._changed_fields.discard('objects')
|
||||
|
||||
def __iter__(self):
|
||||
"""List iterator interface."""
|
||||
return iter(self.objects)
|
||||
|
||||
def __len__(self):
|
||||
"""List length."""
|
||||
return len(self.objects)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""List index access."""
|
||||
if isinstance(index, slice):
|
||||
new_obj = self.__class__()
|
||||
new_obj.objects = self.objects[index]
|
||||
# NOTE(danms): We must be mixed in with a NovaObject!
|
||||
new_obj.obj_reset_changes()
|
||||
new_obj._context = self._context
|
||||
return new_obj
|
||||
return self.objects[index]
|
||||
|
||||
def __contains__(self, value):
|
||||
"""List membership test."""
|
||||
return value in self.objects
|
||||
|
||||
def count(self, value):
|
||||
"""List count of value occurrences."""
|
||||
return self.objects.count(value)
|
||||
|
||||
def index(self, value):
|
||||
"""List index of value."""
|
||||
return self.objects.index(value)
|
||||
|
||||
def sort(self, cmp=None, key=None, reverse=False):
|
||||
self.objects.sort(cmp=cmp, key=key, reverse=reverse)
|
||||
|
||||
def obj_make_compatible(self, primitive, target_version):
|
||||
primitives = primitive['objects']
|
||||
child_target_version = self.child_versions.get(target_version, '1.0')
|
||||
for index, item in enumerate(self.objects):
|
||||
self.objects[index].obj_make_compatible(
|
||||
primitives[index]['nova_object.data'],
|
||||
child_target_version)
|
||||
primitives[index]['nova_object.version'] = child_target_version
|
||||
|
||||
def obj_what_changed(self):
|
||||
changes = set(self._changed_fields)
|
||||
for child in self.objects:
|
||||
if child.obj_what_changed():
|
||||
changes.add('objects')
|
||||
return changes
|
||||
@classmethod
|
||||
def _obj_primitive_field(cls, primitive, field,
|
||||
default=obj_fields.UnspecifiedDefault):
|
||||
key = cls._obj_primitive_key(field)
|
||||
if default == obj_fields.UnspecifiedDefault:
|
||||
return primitive[key]
|
||||
else:
|
||||
return primitive.get(key, default)
|
||||
|
||||
|
||||
class NovaObjectSerializer(messaging.NoOpSerializer):
|
||||
|
|
|
@ -253,7 +253,9 @@ class TestObjMakeList(test.NoDBTestCase):
|
|||
|
||||
def test_obj_make_list(self):
|
||||
class MyList(base.ObjectListBase, base.NovaObject):
|
||||
pass
|
||||
fields = {
|
||||
'objects': fields.ListOfObjectsField('MyObj'),
|
||||
}
|
||||
|
||||
db_objs = [{'foo': 1, 'bar': 'baz', 'missing': 'banana'},
|
||||
{'foo': 2, 'bar': 'bat', 'missing': 'apple'},
|
||||
|
@ -972,112 +974,6 @@ class TestRemoteObject(_RemoteTest, _TestObject):
|
|||
self.assertEqual('bar', obj.bar)
|
||||
|
||||
|
||||
class TestObjectListBase(test.NoDBTestCase):
|
||||
def test_list_like_operations(self):
|
||||
class MyElement(base.NovaObject):
|
||||
fields = {'foo': fields.IntegerField()}
|
||||
|
||||
def __init__(self, foo):
|
||||
super(MyElement, self).__init__()
|
||||
self.foo = foo
|
||||
|
||||
class Foo(base.ObjectListBase, base.NovaObject):
|
||||
fields = {'objects': fields.ListOfObjectsField('MyElement')}
|
||||
|
||||
objlist = Foo(context='foo',
|
||||
objects=[MyElement(1), MyElement(2), MyElement(3)])
|
||||
self.assertEqual(list(objlist), objlist.objects)
|
||||
self.assertEqual(len(objlist), 3)
|
||||
self.assertIn(objlist.objects[0], objlist)
|
||||
self.assertEqual(list(objlist[:1]), [objlist.objects[0]])
|
||||
self.assertEqual(objlist[:1]._context, 'foo')
|
||||
self.assertEqual(objlist[2], objlist.objects[2])
|
||||
self.assertEqual(objlist.count(objlist.objects[0]), 1)
|
||||
self.assertEqual(objlist.index(objlist.objects[1]), 1)
|
||||
objlist.sort(key=lambda x: x.foo, reverse=True)
|
||||
self.assertEqual([3, 2, 1],
|
||||
[x.foo for x in objlist])
|
||||
|
||||
def test_serialization(self):
|
||||
class Foo(base.ObjectListBase, base.NovaObject):
|
||||
fields = {'objects': fields.ListOfObjectsField('Bar')}
|
||||
|
||||
class Bar(base.NovaObject):
|
||||
fields = {'foo': fields.Field(fields.String())}
|
||||
|
||||
obj = Foo(objects=[])
|
||||
for i in 'abc':
|
||||
bar = Bar(foo=i)
|
||||
obj.objects.append(bar)
|
||||
|
||||
obj2 = base.NovaObject.obj_from_primitive(obj.obj_to_primitive())
|
||||
self.assertFalse(obj is obj2)
|
||||
self.assertEqual([x.foo for x in obj],
|
||||
[y.foo for y in obj2])
|
||||
|
||||
def _test_object_list_version_mappings(self, list_obj_class):
|
||||
# Figure out what sort of object this list is for
|
||||
list_field = list_obj_class.fields['objects']
|
||||
item_obj_field = list_field._type._element_type
|
||||
item_obj_name = item_obj_field._type._obj_name
|
||||
|
||||
# Look through all object classes of this type and make sure that
|
||||
# the versions we find are covered by the parent list class
|
||||
for item_class in base.NovaObject._obj_classes[item_obj_name]:
|
||||
self.assertIn(
|
||||
item_class.VERSION,
|
||||
list_obj_class.child_versions.values(),
|
||||
'Version mapping is incomplete for %s' % (
|
||||
list_obj_class.__name__))
|
||||
|
||||
def test_object_version_mappings(self):
|
||||
# Find all object list classes and make sure that they at least handle
|
||||
# all the current object versions
|
||||
for obj_classes in base.NovaObject._obj_classes.values():
|
||||
for obj_class in obj_classes:
|
||||
if issubclass(obj_class, base.ObjectListBase):
|
||||
self._test_object_list_version_mappings(obj_class)
|
||||
|
||||
def test_list_changes(self):
|
||||
class Foo(base.ObjectListBase, base.NovaObject):
|
||||
fields = {'objects': fields.ListOfObjectsField('Bar')}
|
||||
|
||||
class Bar(base.NovaObject):
|
||||
fields = {'foo': fields.StringField()}
|
||||
|
||||
obj = Foo(objects=[])
|
||||
self.assertEqual(set(['objects']), obj.obj_what_changed())
|
||||
obj.objects.append(Bar(foo='test'))
|
||||
self.assertEqual(set(['objects']), obj.obj_what_changed())
|
||||
obj.obj_reset_changes()
|
||||
# This should still look dirty because the child is dirty
|
||||
self.assertEqual(set(['objects']), obj.obj_what_changed())
|
||||
obj.objects[0].obj_reset_changes()
|
||||
# This should now look clean because the child is clean
|
||||
self.assertEqual(set(), obj.obj_what_changed())
|
||||
|
||||
def test_initialize_objects(self):
|
||||
class Foo(base.ObjectListBase, base.NovaObject):
|
||||
fields = {'objects': fields.ListOfObjectsField('Bar')}
|
||||
|
||||
class Bar(base.NovaObject):
|
||||
fields = {'foo': fields.StringField()}
|
||||
|
||||
obj = Foo()
|
||||
self.assertEqual([], obj.objects)
|
||||
self.assertEqual(set(), obj.obj_what_changed())
|
||||
|
||||
def test_obj_repr(self):
|
||||
class Foo(base.ObjectListBase, base.NovaObject):
|
||||
fields = {'objects': fields.ListOfObjectsField('Bar')}
|
||||
|
||||
class Bar(base.NovaObject):
|
||||
fields = {'uuid': fields.StringField()}
|
||||
|
||||
obj = Foo(objects=[Bar(uuid='fake-uuid')])
|
||||
self.assertEqual('Foo(objects=[Bar(fake-uuid)])', repr(obj))
|
||||
|
||||
|
||||
class TestObjectSerializer(_BaseTestCase):
|
||||
def test_serialize_entity_primitive(self):
|
||||
ser = base.NovaObjectSerializer()
|
||||
|
|
Loading…
Reference in New Issue