def test_adaptation(self): # Passthrough's third argument (adaptation) is optional and, when # provided, should be a zope.interface.Interface subclass (although in # practice any callable will do) to which the instance is adapted # before getting/setting the delegated attribute. class HasNoFoo(object): _foo = 1 no_foo = HasNoFoo() # ... but IHasFooAdapter uses HasNoFoo._foo to provide its own .foo, # so it works like an adapter for HasNoFoo into some interface that # provides a 'foo' attribute. class IHasFooAdapter(object): def __init__(self, inst): self.inst = inst @property def foo(self): return self.inst._foo @foo.setter def foo(self, value): self.inst._foo = value class Example(object): context = no_foo p = Passthrough('foo', 'context', adaptation=IHasFooAdapter) e = Example() self.assertEqual(p.__get__(e), 1) p.__set__(e, 2) self.assertEqual(p.__get__(e), 2)
def setUp(self): self.p = Passthrough('foo', 'mycontext') self.p2 = Passthrough('clsmethod', 'mycontext') self.base = Base() class Adapter: mycontext = self.base self.Adapter = Adapter self.adapter = Adapter()
class TestPassthrough(unittest.TestCase): def setUp(self): self.p = Passthrough('foo', 'mycontext') self.p2 = Passthrough('clsmethod', 'mycontext') self.base = Base() class Adapter: mycontext = self.base self.Adapter = Adapter self.adapter = Adapter() def test_get(self): self.assertEqual(self.p.__get__(self.adapter), 'foo from Base') self.assertTrue(self.p.__get__(None, self.Adapter) is self.p) self.assertEqual(self.p2.__get__(self.adapter)(), 'Base') def test_set(self): self.p.__set__(self.adapter, 'new value') self.assertEqual(self.base.foo, 'new value') def test_no_delete(self): self.assertRaises(NotImplementedError, self.p.__delete__, self.adapter) def test_adaptation(self): # Passthrough's third argument (adaptation) is optional and, when # provided, should be a zope.interface.Interface subclass (although in # practice any callable will do) to which the instance is adapted # before getting/setting the delegated attribute. class HasNoFoo(object): _foo = 1 no_foo = HasNoFoo() # ... but IHasFooAdapter uses HasNoFoo._foo to provide its own .foo, # so it works like an adapter for HasNoFoo into some interface that # provides a 'foo' attribute. class IHasFooAdapter(object): def __init__(self, inst): self.inst = inst @property def foo(self): return self.inst._foo @foo.setter def foo(self, value): self.inst._foo = value class Example(object): context = no_foo p = Passthrough('foo', 'context', adaptation=IHasFooAdapter) e = Example() self.assertEqual(p.__get__(e), 1) p.__set__(e, 2) self.assertEqual(p.__get__(e), 2)
def _decorator(cls): missing = object() for interface in interfaces: classImplements(cls, interface) for name in interface: if getattr(cls, name, missing) is missing: setattr(cls, name, Passthrough(name, context)) return cls
def _delegates_advice(cls): """Add a Passthrough class for each missing interface attribute. This function connects the decorator class to the delegate class. Only new-style classes are supported. """ interface_spec, contextvar = cls.__dict__['__delegates_advice_data__'] del cls.__delegates_advice_data__ if isinstance(cls, ClassType): raise TypeError('Cannot use delegates() on a classic class: %s.' % cls) if IInterface.providedBy(interface_spec): interfaces = [interface_spec] else: interfaces = interface_spec not_found = object() for interface in interfaces: classImplements(cls, interface) for name in interface: if getattr(cls, name, not_found) is not_found: setattr(cls, name, Passthrough(name, contextvar)) return cls