Posted by Eduardo Padoan on Mon 18 Feb 02:44
report abuse | download | new post
- import unittest
- from copy import copy
- class Proto(object):
- """ A prototype object.
- """
- def __init__(self, wrapped=None, proto=None):
- self._wrapped = wrapped
- self.proto = proto
- self._protos = [proto] # +/- like __mro__
- try:
- # instantialize the state of the clone
- self.init(self)
- except AttributeError:
- pass
- def __getattr__(self, name):
- #### diferential inheritance ####
- # __getattr__ is only called
- # when the attribute is not found
- try:
- value = getattr(self._wrapped, name)
- except AttributeError:
- for proto in self._protos:
- try:
- value = getattr(proto, name)
- break
- except AttributeError:
- continue
- else:
- raise AttributeError('Object %r have no %s attribute.'
- % (self, name))
- return value
- def __repr__(self):
- return '<object %r>' % self._wrapped
- @property
- def protos(self):
- for proto in self._protos:
- if proto is not None:
- yield proto
- # ask the protos for its protos...
- for super_proto in proto.protos:
- if super_proto is not None:
- yield super_proto
- def clone(self):
- """ Create a new object, based on this one.
- """
- wrapped = self._wrapped
- try:
- # if the object is immutable,
- # no problem sharing it
- hash(wrapped)
- return Proto(wrapped, self)
- except TypeError:
- return Proto(copy(wrapped), self)
- def append_proto(self, proto):
- self._protos.append(proto)
- def prepend_proto(self, proto):
- self._protos.insert(0, proto)
- def remove_proto(self, proto):
- self._protos.remove(proto)
- class TestProto(unittest.TestCase):
- def test_wraps(self):
- obj = Proto('hello')
- self.assertFalse(obj.isupper())
- self.assertTrue(obj.islower())
- self.assertTrue(obj.isalpha())
- c1 = obj.clone()
- self.assertFalse(c1.isdigit())
- self.assertFalse(c1.isspace())
- self.assertEqual(c1.title(), 'Hello')
- self.assertRaises(AttributeError, getattr, c1, 'append')
- def test_clone_and_protos(self):
- obj = Proto(42)
- self.assertEqual(repr(obj), '<object 42>')
- self.assertEqual(None, obj.proto)
- clone = obj.clone()
- proto_a = clone.proto
- proto_b = list(clone.protos).pop()
- self.assertEqual(proto_a, proto_b)
- self.assertNotEqual(obj.proto, proto_a)
- self.assertNotEqual(obj.proto, proto_b)
- self.assertEqual(list(clone.protos), [obj])
- c2 = clone.clone()
- c3 = c2.clone()
- c4 = c3.clone()
- self.assertEqual(list(c2.protos), [clone, obj])
- self.assertEqual(list(c3.protos), [c2, clone, obj])
- self.assertEqual(list(c4.protos), [c3, c2, clone, obj])
- def test_init(self):
- Movie = Proto("Movie")
- def init(self):
- self.cast = []
- Movie.init = init
- some_movie = Movie.clone()
- self.assertEqual(some_movie.cast, [])
- some_movie.cast.append('Some Actor')
- another_movie = Movie.clone()
- self.assertEqual(another_movie.cast, [])
- self.assertNotEqual(another_movie.cast, some_movie.cast)
- def test_inheritance(self):
- obj = Proto('foo')
- obj.bar = 'baz'
- c1 = obj.clone()
- self.assertEqual(obj.bar, c1.bar)
- self.assertEqual(c1.bar, 'baz')
- obj.baz = 'foo'
- self.assertEqual(obj.baz, c1.baz)
- self.assertEqual(c1.baz, 'foo')
- obj.quux = 'foobar'
- self.assertEqual(obj.quux, c1.quux)
- self.assertEqual(c1.quux, 'foobar')
- c2 = c1.clone()
- c3 = c2.clone()
- self.assertEqual(obj.bar, c2.bar)
- self.assertEqual(c2.bar, 'baz')
- self.assertEqual(obj.quux, c2.quux)
- self.assertEqual(c2.quux, 'foobar')
- self.assertEqual(obj.bar, c3.bar)
- self.assertEqual(c3.bar, 'baz')
- self.assertEqual(obj.quux, c3.quux)
- self.assertEqual(c3.quux, 'foobar')
- self.assertEqual(c2.bar, c3.bar)
- self.assertEqual(c1.bar, c2.bar)
- self.assertEqual(c1.bar, c3.bar)
- self.assertEqual(c2.quux, c3.quux)
- self.assertEqual(c1.quux, c2.quux)
- self.assertEqual(c1.quux, c3.quux)
- obj.bar = 42
- self.assertEqual(obj.bar, c3.bar)
- self.assertEqual(c3.bar, 42)
- obj2 = Proto('bar')
- c3.prepend_proto(obj2)
- obj2.baz = 'hello'
- self.assertEqual(c3.bar, 42)
- self.assertEqual(c3.baz, 'hello')
- obj3 = Proto('baz')
- c3.append_proto(obj3)
- obj3.quuuux = 'quuuux'
- obj3.bar = 'quuuux'
- self.assertEqual(c3.bar, 42)
- self.assertEqual(c3.baz, 'hello')
- self.assertEqual(c3.quuuux, 'quuuux')
- c3.remove_proto(obj3)
- self.assertRaises(AttributeError, getattr, obj3, 'quuux')
- if __name__ == '__main__':
- unittest.main()
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.