Merge lp:~allenap/lazr.delegates/multiple-interfaces into lp:~launchpad-pqm/lazr.delegates/devel

Proposed by Gavin Panella
Status: Merged
Merged at revision: not available
Proposed branch: lp:~allenap/lazr.delegates/multiple-interfaces
Merge into: lp:~launchpad-pqm/lazr.delegates/devel
Diff against target: None lines
To merge this branch: bzr merge lp:~allenap/lazr.delegates/multiple-interfaces
Reviewer Review Type Date Requested Status
Gary Poster Approve
Review via email: mp+5525@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

This branch allows delegates() to accept multiple interfaces. I think
the tests explain it quite well, so I won't repeat all of that here.

I also changed the use of hasattr() to getattr() to prevent swallowing
errors.

Revision history for this message
Gary Poster (gary) wrote :

I thought I had reviewed this a long time ago! Sorry that this got lost in the cracks. It looks good to me.

review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :

> I thought I had reviewed this a long time ago! Sorry that this got lost in
> the cracks. It looks good to me.

Woohoo, thanks Gary!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lazr/delegates/README.txt'
2--- src/lazr/delegates/README.txt 2009-03-24 19:51:29 +0000
3+++ src/lazr/delegates/README.txt 2009-04-14 16:07:52 +0000
4@@ -25,11 +25,12 @@
5 Usage
6 =====
7
8-The ``delegates`` function makes a class implement an interface by
9-delegating the implementation to another object. In the case of a class
10-providing an adapter, that object will be the 'context', but it can
11-really be any object stored in an attribute. So while the interfaces use
12-an inheritance mechanism, the classes use a composition mechanism.
13+The ``delegates`` function makes a class implement zero or more
14+interfaces by delegating the implementation to another object. In the
15+case of a class providing an adapter, that object will be the 'context',
16+but it can really be any object stored in an attribute. So while the
17+interfaces use an inheritance mechanism, the classes use a composition
18+mechanism.
19
20 For example we can define two interfaces IFoo0 <- IFoo...
21
22@@ -126,6 +127,66 @@
23 ...
24 TypeError: delegates() can be used only from a class definition.
25
26+Multiple interfaces can be specified by passing an iterable to
27+delegates().
28+
29+ >>> class IOther(Interface):
30+ ... another = Attribute("another attribute")
31+
32+ >>> class BaseOtherFoo(BaseFoo):
33+ ... another = 'yes, another'
34+
35+ >>> class SomeOtherClass(object):
36+ ... delegates([IFoo, IOther])
37+
38+ >>> s = SomeOtherClass()
39+ >>> s.context = BaseOtherFoo()
40+ >>> s.another
41+ 'yes, another'
42+
43+ >>> s.baz
44+ 'hi baz!'
45+
46+ >>> s.spoo
47+ 'some spoo'
48+
49+ >>> IFoo.providedBy(s)
50+ True
51+
52+ >>> IOther.providedBy(s)
53+ True
54+
55+This can be convenient when decorating an existing object.
56+
57+ >>> from zope.interface import implements
58+ >>> class MoreFoo(BaseFoo, BaseOtherFoo):
59+ ... implements(IFoo, IOther)
60+
61+ >>> foo = MoreFoo()
62+
63+ >>> from zope.interface import providedBy
64+ >>> class WithExtraTeapot(object):
65+ ... delegates(providedBy(foo))
66+ ... teapot = 'i am a teapot'
67+
68+ >>> foo_with_teapot = WithExtraTeapot()
69+ >>> foo_with_teapot.context = foo
70+
71+ >>> foo_with_teapot.baz
72+ 'hi baz!'
73+
74+ >>> foo_with_teapot.another
75+ 'yes, another'
76+
77+ >>> foo_with_teapot.teapot
78+ 'i am a teapot'
79+
80+ >>> IFoo.providedBy(foo_with_teapot)
81+ True
82+
83+ >>> IOther.providedBy(foo_with_teapot)
84+ True
85+
86 ==============
87 Implementation
88 ==============
89
90=== modified file 'src/lazr/delegates/_delegates.py'
91--- src/lazr/delegates/_delegates.py 2009-03-24 19:51:29 +0000
92+++ src/lazr/delegates/_delegates.py 2009-04-14 16:07:52 +0000
93@@ -28,9 +28,10 @@
94
95 from zope.interface.advice import addClassAdvisor
96 from zope.interface import classImplements
97-
98-
99-def delegates(interface, context='context'):
100+from zope.interface.interfaces import IInterface
101+
102+
103+def delegates(interface_spec, context='context'):
104 """Make an adapter into a decorator.
105
106 Use like:
107@@ -78,7 +79,7 @@
108 raise TypeError(
109 "delegates() can be used only from a class definition.")
110
111- locals['__delegates_advice_data__'] = interface, context
112+ locals['__delegates_advice_data__'] = interface_spec, context
113 addClassAdvisor(_delegates_advice, depth=2)
114
115
116@@ -88,15 +89,21 @@
117 This function connects the decorator class to the delegate class.
118 Only new-style classes are supported.
119 """
120- interface, contextvar = cls.__dict__['__delegates_advice_data__']
121+ interface_spec, contextvar = cls.__dict__['__delegates_advice_data__']
122 del cls.__delegates_advice_data__
123 if type(cls) is ClassType:
124 raise TypeError(
125 'Cannot use delegates() on a classic class: %s.' % cls)
126- classImplements(cls, interface)
127- for name in interface:
128- if not hasattr(cls, name):
129- setattr(cls, name, Passthrough(name, contextvar))
130+ if IInterface.providedBy(interface_spec):
131+ interfaces = [interface_spec]
132+ else:
133+ interfaces = interface_spec
134+ not_found = object()
135+ for interface in interfaces:
136+ classImplements(cls, interface)
137+ for name in interface:
138+ if getattr(cls, name, not_found) is not_found:
139+ setattr(cls, name, Passthrough(name, contextvar))
140 return cls
141
142

Subscribers

People subscribed via source and target branches