[Twisted-Python] Interface.adaptWith and Interface.__adapt__
Phillip J. Eby
pje at telecommunity.com
Thu Jun 5 07:00:25 MDT 2003
At 01:59 AM 6/5/03 -0400, Glyph Lefkowitz wrote:
>On Wednesday, June 4, 2003, at 06:10 PM, Phillip J. Eby wrote:
>
>>Anyway... I noticed that the only code in Twisted currently (that I
>>could find) that actually uses the current __adapt__ setup is the test
>>suite. Is there any way this might be changeable to something more
>>compatible with PEP 246?
>
>Thanks for bringing this to my attention. As I was perusing the
>implementation, I realized that the reason we committed this particular
>incompatibility was being invalidated a scant two lines away :-). I could
>have sworn it didn't used to have a try:except: block, but I've checked in
>a revised version now.
>
>As I understand it, PEP 246 cannot be implemented without raising
>exceptions in __adapt__.
Actually, no. __adapt__ is also allowed to return None to signal inability
to adapt. And, the consensus so far of people I've talked with (Jim Fulton
and Guido) is that PEP 246 should be revised in that area anyway, such that
it isn't even an *option* to raise TypeError to signal
failure. PyProtocols will only ignore TypeError if it looks like it came
from calling an unbound class method, not if it looks like it came from the
__conform__ or __adapt__ method body.
>>I mean, if I jump through enough hoops building adapters and
>>monkeypatching, I can probably make it so that this will work
>>transparently, and anybody who uses PyProtocols will then be able to mix
>>Twisted, Zope, and PyProtocols interfaces in their applications.
>>But it's pretty messy, and I'm wondering about the copyright status if I
>>have to copy a lot of code from MetaInterface.__call__ in order to
>>monkeypatch a replacement. (I'd like to release PyProtocols under the
>>PSF license.)
>
>PyProtocols looks like an interesting project, and I'd like to support
>such an effort at interoperability. Monkey-patching MetaInterface is
>almost certainly the wrong thing to do. Perhaps it would be best if we
>did not call our interface-aware adaptation mechanism "__adapt__", but
>something like "adaptWithDefault"?
That would work; at least, it makes the monkeypatch quite a bit simpler.
Are you actually using the __adapt__ method for anything yet? The only
code I found with an actual __adapt__ method was in the test suite.
>I am not sure exactly how you're doing compatibility, but perhaps then you
>could provide a subclass of Interface that provided an adaptWithDefault
>that called __adapt__ with the proper arguments?
PyProtocols does compatibility by:
1. defining adapters to adapt "foreign" interface types (Zope, Twisted) to
its own IOpenProtocol interface
2. monkeypatching the foreign interface type itself (Zope InterfaceClass,
Twisted MetaInterface) to add an __adapt__ method that implements PEP 246
by "calling down" to the foreign type's normal adaptation methods. E.g.
for Zope, the __adapt__ I patch in just does:
if self.isImplementedBy(obj):
return obj
And for Twisted, the __adapt__ I add does the equivalent of:
def __adapt__(self, obj):
if implements(obj, self):
return obj
# Get Twisted to try and adapt
return self(ob, None)
In other words, the __adapt__ I add checks whether Twisted says the object
already implements the interface, and if so, return it. Otherwise, adapt
it by calling the interface on the object, with a default of None.
If you were to switch from using __adapt__ to adaptWithDefault in your
__call__ method, and added the above as MetaInterface.__adapt__, your
interfaces would be PEP 246 compatible without any monkeypatching. For
compatibility with PyProtocols' declaration API, I would just supply an
adapter.
(From recent conversations with Jim Fulton, it sounds like he plans to
eventually add a PEP 246-compatible __adapt__ method to Zope interfaces as
well, so at that point I could drop the monkeypatching for Zope too.)
I've done a preliminary sketch of an adapter for Twisted interfaces, but
there are a few holes because I'm not 100% clear on the intended semantics
of Twisted interfaces in some areas. Actually, I get the impression that
that's because Twisted hasn't really defined those semantics either. For
example, Twisted doesn't appear to distinguish between "object implements"
and "class implements". If I call 'getInterfaces()' on a class, it will
tell me that the class implements the same interfaces that its instances
do. From my POV, that doesn't make any sense, but perhaps it is a
documented or at least intended limitation? Certainly, I will need to
document it in my "Compatibility" section (not yet written).
For right now, my Twisted adapter just pokes a new __implements__ onto
whatever object is having declarations made about it, whether it's a type
declaration or an instance declaration. This means that PyProtocols will
behave oddly if you pass a class to adapt(). Of course, Twisted will also
behave oddly if you pass a class to ISomething().
I'm also having trouble figuring out how to apply transitive adapter
semantics to Twisted. AFAICT, Twisted adapters are not normally
transitive. However, unlike PyProtocols, Twisted interfaces don't know
about all their adaptations, so there doesn't seem to be a way to issue
declarations to make them transitive. But I guess that's optional, since I
didn't really intend to make PyProtocols add any new functionality to Zope
or Twisted, just make it reasonably possible to interact with them.
It should be possible at this point to have a PyProtocols interface declare
that it extends both a Twisted and a Zope interface, without any metaclass
incompatibilities. Of course, Twisted and Zope still use mutually
incompatible definitions of '__implements__', so actually *using* an
interface that extended both a Twisted and a Zope interface would be
problematic. :)
More information about the Twisted-Python
mailing list