summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/objects/base.py52
-rw-r--r--nova/tests/objects/test_objects.py37
2 files changed, 89 insertions, 0 deletions
diff --git a/nova/objects/base.py b/nova/objects/base.py
index b263b14e4..625dd48d1 100644
--- a/nova/objects/base.py
+++ b/nova/objects/base.py
@@ -357,6 +357,58 @@ class NovaObject(object):
return self[key]
+class ObjectListBase(object):
+ """Mixin class for lists of objects.
+
+ 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': list,
+ }
+
+ 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 _attr_objects_to_primitive(self):
+ """Serialization of object list."""
+ return [x.obj_to_primitive() for x in self.objects]
+
+ def _attr_objects_from_primitive(self, value):
+ """Deserialization of object list."""
+ return [NovaObject.obj_from_primitive(x) for x in value]
+
+
class NovaObjectSerializer(nova.openstack.common.rpc.serializer.Serializer):
"""A NovaObject-aware Serializer.
diff --git a/nova/tests/objects/test_objects.py b/nova/tests/objects/test_objects.py
index e1c5f2c11..9c92230eb 100644
--- a/nova/tests/objects/test_objects.py
+++ b/nova/tests/objects/test_objects.py
@@ -452,3 +452,40 @@ class TestRemoteObject(_RemoteTest, _TestObject):
obj = MyObj2.get(ctxt)
self.assertEqual(obj.bar, 'bar')
self.assertRemotes()
+
+
+class TestObjectListBase(test.TestCase):
+ def test_list_like_operations(self):
+ class Foo(base.ObjectListBase, base.NovaObject):
+ pass
+
+ objlist = Foo()
+ objlist._context = 'foo'
+ objlist.objects = [1, 2, 3]
+ self.assertTrue(list(objlist), objlist.objects)
+ self.assertEqual(len(objlist), 3)
+ self.assertIn(2, objlist)
+ self.assertEqual(list(objlist[:1]), [1])
+ self.assertEqual(objlist[:1]._context, 'foo')
+ self.assertEqual(objlist[2], 3)
+ self.assertEqual(objlist.count(1), 1)
+ self.assertEqual(objlist.index(2), 1)
+
+ def test_serialization(self):
+ class Foo(base.ObjectListBase, base.NovaObject):
+ pass
+
+ class Bar(base.NovaObject):
+ fields = {'foo': str}
+
+ obj = Foo()
+ obj.objects = []
+ for i in 'abc':
+ bar = 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])