diff options
-rw-r--r-- | nova/objects/base.py | 52 | ||||
-rw-r--r-- | nova/tests/objects/test_objects.py | 37 |
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]) |