Merge lp:~salgado/lazr.delegates/extend-passthrough into lp:lazr.delegates

Proposed by Guilherme Salgado
Status: Merged
Approved by: Gary Poster
Approved revision: 6
Merged at revision: 5
Proposed branch: lp:~salgado/lazr.delegates/extend-passthrough
Merge into: lp:lazr.delegates
Diff against target: 98 lines (+54/-7)
2 files modified
src/lazr/delegates/README.txt (+37/-3)
src/lazr/delegates/_delegates.py (+17/-4)
To merge this branch: bzr merge lp:~salgado/lazr.delegates/extend-passthrough
Reviewer Review Type Date Requested Status
Gary Poster Approve
Review via email: mp+30084@code.launchpad.net

Description of the change

Extend Passthrough so that it takes an extra argument to which the context is adapted before getting/setting the attribute

This is going to be used in https://code.edge.launchpad.net/~salgado/lazr.restful/extension-interfaces

To post a comment you must log in.
6. By Guilherme Salgado

A few tweaks suggested by Gary

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

merge-conditional

Looks great. A few remaining trivial cleanups.

orig_interface -> adaptation in "Passthrough's third argument (orig_interface) is optional..." (src/lazr/delegates/README.txt)

"...(although in practice anything that provides a __call__() method will do)..." -> "...(although in practice any callable will do)..." (src/lazr/delegates/README.txt)

"If adaptation is not None, the context is adapted into it before getting/setting the attribute." -> "If the ``adaptation`` argument is not None, it should be a callable. It will be called with the context, and should return an object that will have the delegated attribute. The ``adaptation`` argument is expected to be used with an interface, to adapt the context." (src/lazr/delegates/_delegates.py)

Thank you!

Gary

review: Approve
7. By Guilherme Salgado

A couple other changes suggested by 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-04-14 16:07:52 +0000
3+++ src/lazr/delegates/README.txt 2010-07-16 13:16:40 +0000
4@@ -193,9 +193,9 @@
5
6 The Passthrough class is the implementation machinery of ``delegates()``. It
7 uses the descriptor protocol to implement the delegation behaviour provided by
8-``delegates()``. It takes two arguments: the name of the attribute that is
9-delegated, and the name of the attribute containing the object to which to
10-delegate.
11+``delegates()``. It takes at least two arguments: the name of the attribute
12+that is delegated, and the name of the attribute containing the object to
13+which to delegate.
14
15 To illustrate, p and p2 are two Passthrough instances that use the
16 instance assigned to 'mycontext' to call the 'foo' attribute and
17@@ -247,6 +247,40 @@
18 ...
19 NotImplementedError
20
21+Passthrough's third argument (adaptation) is optional and, when provided,
22+should be a zope.interface.Interface subclass (although in practice any
23+callable will do) to which the instance is adapted before getting/setting the
24+delegated attribute.
25+
26+ # HasNoFoo does not have a .foo attribute...
27+ >>> class HasNoFoo(object):
28+ ... _foo = 1
29+ >>> no_foo = HasNoFoo()
30+
31+ # ... but IHasFooAdapter uses HasNoFoo._foo to provide its own .foo, so it
32+ # works like an adapter for HasNoFoo into some interface that provides
33+ # a 'foo' attribute.
34+ >>> class IHasFooAdapter(object):
35+ ... def __init__(self, inst):
36+ ... self.inst = inst
37+ ... def _get_foo(self):
38+ ... return self.inst._foo
39+ ... def _set_foo(self, value):
40+ ... self.inst._foo = value
41+ ... foo = property(_get_foo, _set_foo)
42+
43+ >>> class Example(object):
44+ ... context = no_foo
45+
46+ >>> p = Passthrough('foo', 'context', adaptation=IHasFooAdapter)
47+ >>> e = Example()
48+ >>> p.__get__(e)
49+ 1
50+ >>> p.__set__(e, 2)
51+ >>> p.__get__(e)
52+ 2
53+
54+
55 ===============
56 Other Documents
57 ===============
58
59=== modified file 'src/lazr/delegates/_delegates.py'
60--- src/lazr/delegates/_delegates.py 2009-04-14 16:07:52 +0000
61+++ src/lazr/delegates/_delegates.py 2010-07-16 13:16:40 +0000
62@@ -108,19 +108,32 @@
63
64
65 class Passthrough:
66- """Call the delegated class for the decorator class."""
67- def __init__(self, name, contextvar):
68+ """Call the delegated class for the decorator class.
69+
70+ If the ``adaptation`` argument is not None, it should be a callable. It
71+ will be called with the context, and should return an object that will
72+ have the delegated attribute. The ``adaptation`` argument is expected to
73+ be used with an interface, to adapt the context.
74+ """
75+ def __init__(self, name, contextvar, adaptation=None):
76 self.name = name
77 self.contextvar = contextvar
78+ self.adaptation = adaptation
79
80 def __get__(self, inst, cls=None):
81 if inst is None:
82 return self
83 else:
84- return getattr(getattr(inst, self.contextvar), self.name)
85+ context = getattr(inst, self.contextvar)
86+ if self.adaptation is not None:
87+ context = self.adaptation(context)
88+ return getattr(context, self.name)
89
90 def __set__(self, inst, value):
91- setattr(getattr(inst, self.contextvar), self.name, value)
92+ context = getattr(inst, self.contextvar)
93+ if self.adaptation is not None:
94+ context = self.adaptation(context)
95+ setattr(context, self.name, value)
96
97 def __delete__(self, inst):
98 raise NotImplementedError

Subscribers

People subscribed via source and target branches