[Zope-dev] zope.component: calling an Interface and calling queryAdapter give differing results

8 views
Skip to first unread message

Chris Withers

unread,
Aug 19, 2008, 1:30:49 PM8/19/08
to zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk
_______________________________________________
Zope-Dev maillist - Zope...@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
** No cross posts or HTML encoding! **
(Related lists -
http://mail.zope.org/mailman/listinfo/zope-announce
http://mail.zope.org/mailman/listinfo/zope )

Shane Hathaway

unread,
Aug 19, 2008, 3:09:39 PM8/19/08
to Chris Withers, zope-dev
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

Philipp von Weitershausen

unread,
Aug 19, 2008, 3:48:48 PM8/19/08
to Shane Hathaway, Chris Withers, zope-dev
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.

Shane Hathaway

unread,
Aug 19, 2008, 4:24:29 PM8/19/08
to Philipp von Weitershausen, Chris Withers, zope-dev
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

Martin Aspeli

unread,
Aug 19, 2008, 5:23:05 PM8/19/08
to zope...@zope.org
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

--
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book

Jim Fulton

unread,
Aug 19, 2008, 5:57:53 PM8/19/08
to Shane Hathaway, Philipp von Weitershausen, Chris Withers, zope-dev

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

Chris Withers

unread,
Aug 19, 2008, 6:13:39 PM8/19/08
to Philipp von Weitershausen, Shane Hathaway, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Chris Withers

unread,
Aug 19, 2008, 6:19:12 PM8/19/08
to Jim Fulton, Philipp von Weitershausen, Shane Hathaway, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Shane Hathaway

unread,
Aug 19, 2008, 8:36:00 PM8/19/08
to Chris Withers, Philipp von Weitershausen, zope-dev
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

Marius Gedminas

unread,
Aug 20, 2008, 9:41:33 AM8/20/08
to zope...@zope.org
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
--
<Corsac> yeah, i'm reading the answers, currently
<Corsac> but what I see is that there is no real procedure to rebuild initfs
<Corsac> the common way seems to use a loop device with a jffs2 filesystem, put
original files there, and add other files, then umount, flash and pray
<dwd> Corsac: You forgot "ritual sacrifice of a medium sized rodent".
Without that, it'll never work.
<zuh> And if it doesn't work the first time, re-adjust towel ordering in the
restroom and try again
-- #maemo

signature.asc

Chris Withers

unread,
Aug 22, 2008, 10:07:43 AM8/22/08
to Shane Hathaway, Philipp von Weitershausen, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Chris Withers

unread,
Aug 22, 2008, 10:11:47 AM8/22/08
to zope...@zope.org
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 ;-)

Dieter Maurer

unread,
Aug 23, 2008, 7:15:52 AM8/23/08
to Chris Withers, zope-dev
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

Dieter Maurer

unread,
Aug 23, 2008, 7:23:15 AM8/23/08
to Jim Fulton, Philipp von Weitershausen, Chris Withers, Shane Hathaway, zope-dev
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

Chris Withers

unread,
Aug 29, 2008, 5:25:45 AM8/29/08
to Dieter Maurer, Philipp von Weitershausen, Shane Hathaway, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Chris Withers

unread,
Aug 29, 2008, 5:27:35 AM8/29/08
to Dieter Maurer, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Dieter Maurer

unread,
Aug 30, 2008, 1:50:17 AM8/30/08
to Chris Withers, Philipp von Weitershausen, Shane Hathaway, zope-dev
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.

--
Dieter

Philipp von Weitershausen

unread,
Sep 1, 2008, 8:07:57 AM9/1/08
to Dieter Maurer, Chris Withers, Shane Hathaway, zope-dev
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.

Chris Withers

unread,
Sep 1, 2008, 11:23:03 AM9/1/08
to Philipp von Weitershausen, Dieter Maurer, Shane Hathaway, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Philipp von Weitershausen

unread,
Sep 1, 2008, 12:33:22 PM9/1/08
to Chris Withers, Dieter Maurer, Shane Hathaway, zope-dev
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.

Dieter Maurer

unread,
Sep 1, 2008, 1:21:16 PM9/1/08
to Philipp von Weitershausen, Chris Withers, Shane Hathaway, zope-dev
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) :-)

--
Dieter

Dieter Maurer

unread,
Sep 1, 2008, 1:26:23 PM9/1/08
to Chris Withers, Philipp von Weitershausen, Shane Hathaway, zope-dev
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?

--
Dieter

Philipp von Weitershausen

unread,
Sep 1, 2008, 2:05:34 PM9/1/08
to Dieter Maurer, Chris Withers, Shane Hathaway, zope-dev
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.

Jim Fulton

unread,
Sep 2, 2008, 11:51:22 AM9/2/08
to Philipp von Weitershausen, Dieter Maurer, Chris Withers, Shane Hathaway, zope-dev

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

Martin Aspeli

unread,
Sep 2, 2008, 5:25:56 PM9/2/08
to zope...@zope.org
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

--
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book

_______________________________________________

Stephan Richter

unread,
Sep 2, 2008, 6:05:11 PM9/2/08
to zope...@zope.org, Martin Aspeli
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
--
Stephan Richter
Web Software Design, Development and Training
Google me. "Zope Stephan Richter"

Chris Withers

unread,
Sep 7, 2008, 3:29:59 PM9/7/08
to Philipp von Weitershausen, Dieter Maurer, Shane Hathaway, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

_______________________________________________

Fred Drake

unread,
Sep 8, 2008, 1:30:13 PM9/8/08
to Chris Withers, Philipp von Weitershausen, Dieter Maurer, Shane Hathaway, zope-dev
On Sun, Sep 7, 2008 at 3:29 PM, Chris Withers <ch...@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 L. Drake, Jr. <fdrake at gmail.com>
"Chaos is the score upon which reality is written." --Henry Miller

Shane Hathaway

unread,
Sep 8, 2008, 1:31:19 PM9/8/08
to Chris Withers, Philipp von Weitershausen, Dieter Maurer, zope-dev
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

unread,
Sep 8, 2008, 1:34:33 PM9/8/08
to Fred Drake, Philipp von Weitershausen, Dieter Maurer, Shane Hathaway, zope-dev
Fred Drake wrote:
> On Sun, Sep 7, 2008 at 3:29 PM, Chris Withers <ch...@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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Dieter Maurer

unread,
Sep 9, 2008, 2:37:58 PM9/9/08
to Chris Withers, Philipp von Weitershausen, Shane Hathaway, Fred Drake, zope-dev
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 :-)

--
Dieter

Fred Drake

unread,
Sep 9, 2008, 2:44:56 PM9/9/08
to Dieter Maurer, Philipp von Weitershausen, Chris Withers, Shane Hathaway, zope-dev
On Tue, Sep 9, 2008 at 2:37 PM, Dieter Maurer <die...@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

--
Fred L. Drake, Jr. <fdrake at gmail.com>
"Chaos is the score upon which reality is written." --Henry Miller

Philipp von Weitershausen

unread,
Sep 9, 2008, 3:08:33 PM9/9/08
to Dieter Maurer, Shane Hathaway, Chris Withers, Fred Drake, zope-dev
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

Shane Hathaway

unread,
Sep 9, 2008, 3:44:11 PM9/9/08
to Philipp von Weitershausen, Dieter Maurer, Chris Withers, Fred Drake, zope-dev
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

Chris Withers

unread,
Sep 22, 2008, 2:41:05 PM9/22/08
to Philipp von Weitershausen, Dieter Maurer, Shane Hathaway, Fred Drake, zope-dev
Philipp von Weitershausen wrote:
> So overall I'm +1

Me too!

Chris

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Chris Withers

unread,
Sep 22, 2008, 2:41:40 PM9/22/08
to Shane Hathaway, Philipp von Weitershausen, Dieter Maurer, Fred Drake, zope-dev
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Brandon Craig Rhodes

unread,
Sep 26, 2008, 11:55:55 AM9/26/08
to zope...@zope.org
Shane Hathaway <sh...@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 bra...@rhodesmill.org http://rhodesmill.org/brandon

Chris Withers

unread,
Sep 30, 2008, 7:06:50 AM9/30/08
to Brandon Craig Rhodes, zope...@zope.org
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

_______________________________________________

Tres Seaver

unread,
Sep 30, 2008, 10:56:38 AM9/30/08
to zope...@zope.org, Brandon Craig Rhodes
-----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 tse...@palladion.com
Palladion Software "Excellence by Design" http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFI4j4l+gerLs4ltQ4RAiiEAJ0Vp4RP1HeEdwu7YUyaY+Vsa6DAjwCdGeuO
eHQbGlp8geoKGPoC4IKniYc=
=amZR
-----END PGP SIGNATURE-----

Dieter Maurer

unread,
Sep 30, 2008, 2:58:23 PM9/30/08
to Chris Withers, Philipp von Weitershausen, Shane Hathaway, Fred Drake, zope-dev
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 :-)

--
Dieter

Chris Withers

unread,
Oct 3, 2008, 10:18:34 AM10/3/08
to Tres Seaver, Brandon Craig Rhodes, zope...@zope.org
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

--
Simplistix - Content Management, Zope & Python Consulting
- http://www.simplistix.co.uk

Reply all
Reply to author
Forward
0 new messages