From a user's perspective, this makes no sense:
from zope.interface import implements,Interface from zope.component import queryAdapter class ISomething(Interface): pass
...
class MyClass: implements(ISomething)
...
m = MyClass()
Right, so this does make sense:
ISomething(m)
<__main__.MyClass instance at 0x00BED6E8>
This does not:
repr(queryAdapter(m,ISomething))
'None'
why the difference?
cheers,
Chris
Chris Withers wrote:
From a user's perspective, this makes no sense:
from zope.interface import implements,Interface from zope.component import queryAdapter class ISomething(Interface): pass
...
class MyClass: implements(ISomething)
...
m = MyClass()
Right, so this does make sense:
ISomething(m)
<__main__.MyClass instance at 0x00BED6E8>
This does not:
repr(queryAdapter(m,ISomething))
'None'
Looks like a bug to me. If the object passed as the first argument to queryAdapter() implements the interface passed as the second argument, I believe queryAdapter() should return the object, regardless of any component registrations.
Shane
Shane Hathaway wrote:
Chris Withers wrote:
From a user's perspective, this makes no sense:
from zope.interface import implements,Interface from zope.component import queryAdapter class ISomething(Interface): pass
...
class MyClass: implements(ISomething)
...
m = MyClass()
Right, so this does make sense:
ISomething(m)
<__main__.MyClass instance at 0x00BED6E8>
This does not:
repr(queryAdapter(m,ISomething))
'None'
Looks like a bug to me. If the object passed as the first argument to queryAdapter() implements the interface passed as the second argument, I believe queryAdapter() should return the object, regardless of any component registrations.
No, it's not a bug. This is in fact a feature (like it or not). {query|get}Adapter will always try to look up an adapter, whether or not the object provides the interface. So the behaviour Chris observed is indeed intended. I agree it could be documented better.
Philipp von Weitershausen wrote:
Shane Hathaway wrote:
Looks like a bug to me. If the object passed as the first argument to queryAdapter() implements the interface passed as the second argument, I believe queryAdapter() should return the object, regardless of any component registrations.
No, it's not a bug. This is in fact a feature (like it or not).
While I respect that this feature may have been chosen carefully, it nevertheless seems more like a misfeature. Chris' expectation was reasonable and ought not to be violated without a good cause. What code depends on it?
Shane
Shane Hathaway wrote:
Philipp von Weitershausen wrote:
Shane Hathaway wrote:
Looks like a bug to me. If the object passed as the first argument to queryAdapter() implements the interface passed as the second argument, I believe queryAdapter() should return the object, regardless of any component registrations.
No, it's not a bug. This is in fact a feature (like it or not).
While I respect that this feature may have been chosen carefully, it nevertheless seems more like a misfeature. Chris' expectation was reasonable and ought not to be violated without a good cause. What code depends on it?
I've been bitten by this in the past as well. I can't see a good reason why it should be that way. The only thing I can imagine needing this would be some code that checked whether an adapter was registered, but even then why should anyone care...
It'd be an easy thing to "fix", too.
Martin
On Aug 19, 2008, at 4:24 PM, Shane Hathaway wrote:
Philipp von Weitershausen wrote:
Shane Hathaway wrote:
Looks like a bug to me. If the object passed as the first argument to queryAdapter() implements the interface passed as the second argument, I believe queryAdapter() should return the object, regardless of any component registrations.
No, it's not a bug. This is in fact a feature (like it or not).
While I respect that this feature may have been chosen carefully, it nevertheless seems more like a misfeature. Chris' expectation was reasonable and ought not to be violated without a good cause.
queryAdapter is used to look up named adapters. It is also a simpler version of queryMultiAdapter, which looks up adapters for multiple objects. In neither of these cases does it make sense to consider the interfaces already provided by the object being adapted. It makes no sense to me for queryAdapter to have different semantics depending on whether the name argument is provided (and is non-blank).
Jim
-- Jim Fulton Zope Corporation
Jim Fulton wrote:
No, it's not a bug. This is in fact a feature (like it or not).
While I respect that this feature may have been chosen carefully, it nevertheless seems more like a misfeature. Chris' expectation was reasonable and ought not to be violated without a good cause.
queryAdapter is used to look up named adapters.
It sure would be nice if it had a docstring that at least indicated that was its only intended purpose.
However, how should I go about adapting an object to an interface where there may or may not be an adapter registered?
The natural way would seem to be:
obj = ISomething(otherobj,default=None)
...but I seem to remember people finding reasons why implementing that would never be possible.
It is also a simpler version of queryMultiAdapter, which looks up adapters for multiple objects. In neither of these cases does it make sense to consider the interfaces already provided by the object being adapted.
Why not? What if the name provided is None? (and why isn't the name provided None by default, rather thab being ''?)
It makes no sense to me for queryAdapter to have different semantics depending on whether the name argument is provided (and is non-blank).
Why would the semantics be different?
From a use point of view, I'd only expect queryAdapter to consider looking for a named adapter if I actually provide a name. If I provide no name, it would seem logical to look up a non-named adapter. If looking up a non-named adapter, it would make sense if the object already provides the desired interfaces to just return the object.
I'd love to see where this expectation is faulty...
Chris
Chris Withers wrote:
Jim Fulton wrote:
No, it's not a bug. This is in fact a feature (like it or not).
While I respect that this feature may have been chosen carefully, it nevertheless seems more like a misfeature. Chris' expectation was reasonable and ought not to be violated without a good cause.
queryAdapter is used to look up named adapters.
It sure would be nice if it had a docstring that at least indicated that was its only intended purpose.
Now would be a good time for you to add that docstring to the trunk. :-)
From a use point of view, I'd only expect queryAdapter to consider looking for a named adapter if I actually provide a name. If I provide no name, it would seem logical to look up a non-named adapter. If looking up a non-named adapter, it would make sense if the object already provides the desired interfaces to just return the object.
I'd love to see where this expectation is faulty...
I'm switching to Jim's side now. :-) The semantics you described are more magical. At this point it's probably better to just improve the docs.
Shane
Shane Hathaway wrote:
It sure would be nice if it had a docstring that at least indicated that was its only intended purpose.
Now would be a good time for you to add that docstring to the trunk. :-)
Yes well, I apparently don't have enough knowledge to do this correctly. Maybe someone with that knowledge could do so?
From a use point of view, I'd only expect queryAdapter to consider looking for a named adapter if I actually provide a name. If I provide no name, it would seem logical to look up a non-named adapter. If looking up a non-named adapter, it would make sense if the object already provides the desired interfaces to just return the object.
I'd love to see where this expectation is faulty...
I'm switching to Jim's side now. :-) The semantics you described are more magical.
How so? I've given a very concise explanation of *why* it's not surprising for users for it to work the way I describe. The yway it currently works makes people except those involved in the development of the package go "wait, that's not what I expected to have happen, huh?"
Chris
On Tue, Aug 19, 2008 at 11:19:12PM +0100, Chris Withers wrote:
However, how should I go about adapting an object to an interface where there may or may not be an adapter registered?
obj = ISomething(otherobj, None)
The natural way would seem to be:
obj = ISomething(otherobj,default=None)
I like this version. It's much clearer.
...but I seem to remember people finding reasons why implementing that would never be possible.
I think that was about making ISometing(foo, bar) do a multi-adapter lookup instead of the current semantics (using bar as the default).
From a use point of view, I'd only expect queryAdapter to consider looking for a named adapter if I actually provide a name. If I provide no name, it would seem logical to look up a non-named adapter. If looking up a non-named adapter, it would make sense if the object already provides the desired interfaces to just return the object.
I'd love to see where this expectation is faulty...
It's also what I expected, and Jim managed to convince me I was wrong. Well, almost. I still think there's a smell if something doesn't work the way people expect, even if it all seems very elegant after a long protracted explanation.
FWIW, there's another difference between ISomething(foo) and getAdapter(foo, ISomething):
class SampleObject(object): def __conform__(self, iface): if iface is ISomething: return self.something
obj = SampleObject() obj.something = SomethingElse()
ISomething(obj) will return obj.something.
getAdapter(obj, ISomething) will raise a ComponentLookupError.
Marius Gedminas
Marius Gedminas wrote:
On Tue, Aug 19, 2008 at 11:19:12PM +0100, Chris Withers wrote:
However, how should I go about adapting an object to an interface where there may or may not be an adapter registered?
obj = ISomething(otherobj, None)
Ah, okay. Now I remember. I've often wanted to be able to do:
obj = ISomething(obj1,0bj2,0-bj3) to get a multiadapter. Now that I can see the above, I know why that's not possible.
So what you describe above actually works currently?
The natural way would seem to be:
obj = ISomething(otherobj,default=None)
I like this version. It's much clearer.
What's the default parameter currently called then?
I think that was about making ISometing(foo, bar) do a multi-adapter lookup instead of the current semantics (using bar as the default).
indeed, correct you are :-)
It's also what I expected, and Jim managed to convince me I was wrong.
Fine, now try and convince me ;-)
Well, almost. I still think there's a smell if something doesn't work the way people expect, even if it all seems very elegant after a long protracted explanation.
Nothing that requires a protracted explanation is elegant.
FWIW, there's another difference between ISomething(foo) and getAdapter(foo, ISomething):
class SampleObject(object): def __conform__(self, iface): if iface is ISomething: return self.something obj = SampleObject() obj.something = SomethingElse()
ISomething(obj) will return obj.something.
getAdapter(obj, ISomething) will raise a ComponentLookupError.
I have no idea what __conform__ is, so I guess I don't mind too much ;-)
Chris
Jim Fulton wrote at 2008-8-19 17:57 -0400:
....
While I respect that this feature may have been chosen carefully, it nevertheless seems more like a misfeature. Chris' expectation was reasonable and ought not to be violated without a good cause.
queryAdapter is used to look up named adapters. It is also a simpler version of queryMultiAdapter, which looks up adapters for multiple objects. In neither of these cases does it make sense to consider the interfaces already provided by the object being adapted. It makes no sense to me for queryAdapter to have different semantics depending on whether the name argument is provided (and is non-blank).
As the "implements" directive does not specify a name, one could think that the default name is declared. Then, your naming argument would go away.
As the "I(obj, ...)" syntax is more comfortable and more natural than the "get[Multi]Adapter(obj, I, ...)", it may even be adequate to give "I(...)" an optional "name" parameter.
Then, we could get rid of the "{get|query}[Multi]Adapter" altogether and consistently use "I(....)" with appropriate optional parameters -- what a simplification and homogenization :-)
Dieter Maurer wrote:
Then, we could get rid of the "{get|query}[Multi]Adapter" altogether and consistently use "I(....)" with appropriate optional parameters -- what a simplification and homogenization :-)
Yeah, but since when has simplification or homogenisation been a goal of Zope 3? ;-)
Chris
Chris Withers wrote at 2008-8-29 10:25 +0100:
Dieter Maurer wrote:
Then, we could get rid of the "{get|query}[Multi]Adapter" altogether and consistently use "I(....)" with appropriate optional parameters -- what a simplification and homogenization :-)
Yeah, but since when has simplification or homogenisation been a goal of Zope 3? ;-)
It was with the "Service" geddon: make "Service" and "Utility" homgogenous.
El 30 Aug 2008, a las 07:50 , Dieter Maurer escribió:
Chris Withers wrote at 2008-8-29 10:25 +0100:
Dieter Maurer wrote:
Then, we could get rid of the "{get|query}[Multi]Adapter" altogether and consistently use "I(....)" with appropriate optional parameters -- what a simplification and homogenization :-)
Yeah, but since when has simplification or homogenisation been a goal of Zope 3? ;-)
It was with the "Service" geddon: make "Service" and "Utility" homgogenous.
Indeed.
I've personally thought for some time that it would be quite nice if all you had to do was call an interface to look up a utility (which is sort of a multi-adapter of order 0) or to do some kind of adaption, no matter how many objects you wanted to adapt. E.g.:
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
etc.
Personally I would favour such consistency higher than the current behaviour, which may have been invented intentionally but still causes confusion once in a while.
Philipp von Weitershausen wrote:
I've personally thought for some time that it would be quite nice if all you had to do was call an interface to look up a utility (which is sort of a multi-adapter of order 0) or to do some kind of adaption, no matter how many objects you wanted to adapt. E.g.:
+sys.maxint. This is nice.
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
cheers,
Chris
El 1 Sep 2008, a las 17:23 , Chris Withers escribió:
Philipp von Weitershausen wrote:
I've personally thought for some time that it would be quite nice if all you had to do was call an interface to look up a utility (which is sort of a multi-adapter of order 0) or to do some kind of adaption, no matter how many objects you wanted to adapt. E.g.:
+sys.maxint. This is nice.
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
You don't, I guess. I'd say that multi-adaption is *defined* as the adaption of a tuple.
On Sep 1, 2008, at 12:33 PM, Philipp von Weitershausen wrote:
El 1 Sep 2008, a las 17:23 , Chris Withers escribió:
Philipp von Weitershausen wrote:
I've personally thought for some time that it would be quite nice if all you had to do was call an interface to look up a utility (which is sort of a multi-adapter of order 0) or to do some kind of adaption, no matter how many objects you wanted to adapt. E.g.:
+sys.maxint. This is nice.
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
You don't, I guess. I'd say that multi-adaption is *defined* as the adaption of a tuple.
Some people who use zope.interface reply on being able to singly adapt tuples
Jim
-- Jim Fulton Zope Corporation
Jim Fulton wrote:
Some people who use zope.interface reply on being able to singly adapt tuples
I've heard this before, but I've always been curious: why? when is this a pattern you'd want to use?
Martin
On Tuesday 02 September 2008, Martin Aspeli wrote:
Some people who use zope.interface reply on being able to singly adapt  tuples
I've heard this before, but I've always been curious: why? when is this a pattern you'd want to use?
Ask the twisted guys. :-)
Regards, Stephan
Philipp von Weitershausen wrote:
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
You don't, I guess. I'd say that multi-adaption is *defined* as the adaption of a tuple.
Well no, I think Dieter suggested the correct solution here in making the Interface's __call__ method like this:
def __call__(self,*adapted,default=None,name=None)
I can't see any problems with this, can anyone else?
If so, what blockers are there to implementing it and releasing a new version of zope.interface? If the gods smile nicely, I might even be able to do this work myself if people are willing :-)
cheers,
Chris
On Sun, Sep 7, 2008 at 3:29 PM, Chris Withers chris@simplistix.co.uk wrote:
I can't see any problems with this, can anyone else?
There's the backward-compatibility issue, which is a showstopper. There's plenty of code that does this:
adapter = package.interfaces.IFoo(object, None)
Changing the signature as you describe would break all code that does this.
-Fred
Fred Drake wrote:
On Sun, Sep 7, 2008 at 3:29 PM, Chris Withers chris@simplistix.co.uk wrote:
I can't see any problems with this, can anyone else?
There's the backward-compatibility issue, which is a showstopper. There's plenty of code that does this:
adapter = package.interfaces.IFoo(object, None)
Changing the signature as you describe would break all code that does this.
How about a new major revision of zope.interface then?
I thought the pointless yoke of backwards compatability was something only Microsoft yearned for? ;-)
cheers,
Chris
Chris Withers wrote at 2008-9-8 18:34 +0100:
...
There's the backward-compatibility issue, which is a showstopper. There's plenty of code that does this:
adapter = package.interfaces.IFoo(object, None)
Changing the signature as you describe would break all code that does this.
How about a new major revision of zope.interface then?
I fear that would be a bit drastic -- for a mostly cosmetic change.
But interfaces might grow an additional method, e.g. "adapt", which could get the new signature.
The syntax would be a bit more cumbersome -- but on the other hand, it would be more explicit :-)
On Tue, Sep 9, 2008 at 2:37 PM, Dieter Maurer dieter@handshake.de wrote:
The syntax would be a bit more cumbersome -- but on the other hand, it would be more explicit :-)
Seems to me zope.component.getMultiAdapter(...) is sufficient as-is, and shares the benefit of explicitness.
That's sufficient for me.
-Fred
El 9 Sep 2008, a las 20:37 , Dieter Maurer escribió:
Chris Withers wrote at 2008-9-8 18:34 +0100:
...
There's the backward-compatibility issue, which is a showstopper. There's plenty of code that does this:
adapter = package.interfaces.IFoo(object, None)
Changing the signature as you describe would break all code that does this.
How about a new major revision of zope.interface then?
I fear that would be a bit drastic -- for a mostly cosmetic change.
I agree.
But interfaces might grow an additional method, e.g. "adapt", which could get the new signature.
The syntax would be a bit more cumbersome -- but on the other hand, it would be more explicit :-)
I don't think it would be too cumbersome. While IMHO elegant, the current syntax of calling an interface to adapt isn't actually self- explanatory. I've frequently observed people tripping over this, specially when you have an IFoo interface and a Foo class -- which is quite common --, then IFoo(obj) and Foo(obj) differ only by one character. With your suggestion, it would be IFoo.adapt(obj) vs. Foo(obj), making the difference quite obvious.
So overall I'm +1
Philipp von Weitershausen wrote:
El 9 Sep 2008, a las 20:37 , Dieter Maurer escribió:
But interfaces might grow an additional method, e.g. "adapt", which could get the new signature.
The syntax would be a bit more cumbersome -- but on the other hand, it would be more explicit :-)
I don't think it would be too cumbersome. While IMHO elegant, the current syntax of calling an interface to adapt isn't actually self- explanatory. I've frequently observed people tripping over this, specially when you have an IFoo interface and a Foo class -- which is quite common --, then IFoo(obj) and Foo(obj) differ only by one character. With your suggestion, it would be IFoo.adapt(obj) vs. Foo(obj), making the difference quite obvious.
So overall I'm +1
+1 from me as well on IFoo.adapt() with the signature Chris suggested. "zope.component.getMultiAdapter()" is only easy to remember if you're a die-hard Zope coder, while IFoo.adapt() seems more useful to the larger Python community.
Shane
Shane Hathaway wrote:
+1 from me as well on IFoo.adapt() with the signature Chris suggested. "zope.component.getMultiAdapter()" is only easy to remember if you're a die-hard Zope coder, while IFoo.adapt() seems more useful to the larger Python community.
So if we're all in agreement, what happens next?
cheers,
Chris
Chris Withers wrote at 2008-9-22 19:41 +0100:
Shane Hathaway wrote:
+1 from me as well on IFoo.adapt() with the signature Chris suggested. "zope.component.getMultiAdapter()" is only easy to remember if you're a die-hard Zope coder, while IFoo.adapt() seems more useful to the larger Python community.
So if we're all in agreement, what happens next?
We find a volunteer to work on this.
For some time still, I will be very busy with gardening and have not much time for programming. Thus, I will not be a volunteer (in the near future). But, I have seen that you started work already :-)
Shane Hathaway shane@hathawaymix.org writes:
Philipp von Weitershausen wrote:
So overall I'm +1
+1 from me as well on IFoo.adapt() with the signature Chris suggested. "zope.component.getMultiAdapter()" is only easy to remember if you're a die-hard Zope coder, while IFoo.adapt() seems more useful to the larger Python community.
A similar suggestion was hammered out last September; I guess September is the official month for the annual reconsideration of adaptation syntax? :-)
http://mail.zope.org/pipermail/zope3-dev/2007-September/023824.html http://mail.zope.org/pipermail/zope3-dev/2007-September/023904.html http://mail.zope.org/pipermail/zope3-dev/2007-September/023907.html
I'm encouraged by the fact that this time it looks like people with time are interested enough to actually begin producing code? At the time that I made the 2007 proposal I was still very new to the code base and never got the courage up (or time available) to start making changes...
Brandon Craig Rhodes wrote:
I'm encouraged by the fact that this time it looks like people with time are interested enough to actually begin producing code? At the time that I made the 2007 proposal I was still very new to the code base and never got the courage up (or time available) to start making changes...
The changes we're talking about are only really syntactic sugar so not really that scary.
I'm left wondering where to put the tests, since while I know zope.component relies on zope.interface, is the reverse true?
I guess it must be, since calling an interface already does some adaptation.
Can anyone else confirm this and give me a hint as to where the tests and code should go?
cheers,
Chris
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Chris Withers wrote:
Brandon Craig Rhodes wrote:
I'm encouraged by the fact that this time it looks like people with time are interested enough to actually begin producing code? At the time that I made the 2007 proposal I was still very new to the code base and never got the courage up (or time available) to start making changes...
The changes we're talking about are only really syntactic sugar so not really that scary.
I'm left wondering where to put the tests, since while I know zope.component relies on zope.interface, is the reverse true?
I guess it must be, since calling an interface already does some adaptation.
No, there is no dependency: zope.interface defines a hook point that zope.component uses. In the absence of zope.component, zope.interface uses a default implementation.
Can anyone else confirm this and give me a hint as to where the tests and code should go?
Tests likely belong in 'zope.interface.tests.test_adapter'.
Tres. - -- =================================================================== Tres Seaver +1 540-429-0999 tseaver@palladion.com Palladion Software "Excellence by Design" http://palladion.com
Tres Seaver wrote:
I guess it must be, since calling an interface already does some adaptation.
No, there is no dependency: zope.interface defines a hook point that zope.component uses. In the absence of zope.component, zope.interface uses a default implementation.
That sound pretty icky. What does this implementation do? Would a similar implementation be needed for the 'adapt' method or do we just raise a ComponentLookupError in the default implementation?
How do we test this different type of behaviour? How do we test that zope.component provides the right hooks and that they get called correctly?
Can anyone else confirm this and give me a hint as to where the tests and code should go?
Tests likely belong in 'zope.interface.tests.test_adapter'.
OK.
cheers,
Chris
Philipp von Weitershausen wrote:
So overall I'm +1
Me too!
Chris
Chris Withers wrote:
Philipp von Weitershausen wrote:
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
You don't, I guess. I'd say that multi-adaption is *defined* as the adaption of a tuple.
Well no, I think Dieter suggested the correct solution here in making the Interface's __call__ method like this:
def __call__(self,*adapted,default=None,name=None)
That's invalid Python syntax, unfortunately, but this will do what you want:
def __call__(self, *adapted, **kw): default = kw.pop('default', None) name = kw.pop('name', None) if kw: raise TypeError("__call__() got an unexpected keyword argument") # ...
This seems like a good idea to me.
Shane
Chris Withers wrote at 2008-9-1 16:23 +0100:
...
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
One way would be to use "*objs" in the "Interface.__call__" signature. Then, multi-adaptation could be "I(obj1, obj2, ...)" and tuple adaptation "I((obj1, obj2, ...)). Of course, all other parameters would need to be keyword parameters (a good thing).
Do you have a serious use case for tuple adaptation?
El 1 Sep 2008, a las 19:26 , Dieter Maurer escribió:
Chris Withers wrote at 2008-9-1 16:23 +0100:
...
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
Right, but how do you differentiate adapting a tuple to IBrowserPage versus adapting obj and request together to IBrowserPage?
One way would be to use "*objs" in the "Interface.__call__" signature. Then, multi-adaptation could be "I(obj1, obj2, ...)" and tuple adaptation "I((obj1, obj2, ...)). Of course, all other parameters would need to be keyword parameters (a good thing).
Do you have a serious use case for tuple adaptation?
IIRC, the twisted guys do.
Philipp von Weitershausen wrote at 2008-9-1 14:07 +0200:
... I've personally thought for some time that it would be quite nice if all you had to do was call an interface to look up a utility (which is sort of a multi-adapter of order 0) or to do some kind of adaption, no matter how many objects you wanted to adapt. E.g.:
auth = IAuthentication() # utility auth = IAuthentication(default=None) langs = IUserPreferredLanguages(request) # adapter langs = IUserPreferredLanguages(request, default=None) view = IBrowserPage((obj, request), name='index') # named multi-adapter
etc.
Personally I would favour such consistency higher than the current behaviour, which may have been invented intentionally but still causes confusion once in a while.
I am with you in this respect (as you probably already knew) :-)
Philipp von Weitershausen wrote:
No, it's not a bug. This is in fact a feature (like it or not).
Well, assuming enough people *don't* like it, and I think that's the case here, then it should probably change...
{query|get}Adapter will always try to look up an adapter, whether or not the object provides the interface. So the behaviour Chris observed is indeed intended. I agree it could be documented better.
I'd suggest thoroughly reading this book from a software design perspective:
http://www.amazon.com/gp/product/0465067107
cheers,
Chris
Chris Withers wrote at 2008-8-19 18:30 +0100:
...
class ISomething(Interface): pass
...
class MyClass: implements(ISomething)
...
m = MyClass()
Right, so this does make sense:
ISomething(m)
<__main__.MyClass instance at 0x00BED6E8>
This does not:
repr(queryAdapter(m,ISomething))
'None'
why the difference?
Jim is heavily defending this difference.
I am convinced that the difference should not be there but meanwhile have found a use case for it.
Suppose, you have a class "C" that implements "I".
If "queryAdapter" would behave like "I(...)", you would have no way to override the implementation of "I" by "C".
With the current behavior, you can use "queryAdapter(c, I)" to check whether some special requirements apply and in this case use the special purpose adapter.
Not that this use case had been able to convince me that the difference were justified.
Dieter Maurer wrote:
Jim is heavily defending this difference.
I am convinced that the difference should not be there
fork anyone? ;-)
but meanwhile have found a use case for it.
Suppose, you have a class "C" that implements "I".
If "queryAdapter" would behave like "I(...)", you would have no way to override the implementation of "I" by "C".
With the current behavior, you can use "queryAdapter(c, I)" to check whether some special requirements apply and in this case use the special purpose adapter.
Right, so every time you want these semantics you have to jump through these hoops. My understanding of the CA was that it was supposed to stop the need for this kind of copy'n'paste coding?
cheers,
Chris