[Twisted-Python] Interface.adaptWith and Interface.__adapt__

Phillip J. Eby pje at telecommunity.com
Wed Jun 4 18:10:27 EDT 2003

Hi.  I'm working on a new interface adaptation package for Python, called 
PyProtocols.  It's an extension of PEP 246 to include a standardized API 
for declaring support for particular interfaces, and how to adapt 
instances, types, and other interfaces to an interface.  It includes its 
own interface library, but also has adapters and monkeypatching for Zope 
interfaces to make them usable with the API.  That is, since the API is 
itself defined with interfaces, it uses itself to adapt Zope interfaces to 
the interface for interfaces it uses.  :)

Anyway, I'd like to add support for Twisted interfaces as well.  I started 
today on trying to write adapters to map Twisted's interface/adapter API 
onto the PyProtocols API, and I ran into a bit of a snag.

I was about to write the code to add an __adapt__ method to Twisted 
interfaces, when I noticed there is already some code related to 
__adapt__.  But that code isn't at all compatible with the PEP 246 spec for 
__adapt__, as I understand it.  PEP 246 wants to be able to call an 
object's __adapt__ method with a single argument, while MetaInterface 
expects to yank out 'im_func' and pass two arguments into it.

The only way I can see to get this to work with PEP 246, is to monkeypatch 
MetaInterface.__call__ to find '__adapt__' by checking the interface's 
dictionary, rather than using __getattr__.  In this way, I can give 
MetaInterface an __adapt__ method that will be found whenever you refer to 
ISomething.__adapt__, but MetaInterface.__call__ will still find any 
__adapt__ that was put in by a 'def' in the interface body.

Essentially, I would be monkeypatching to change these two lines:

         if hasattr(self, '__adapt__'):
             adapter = self.__adapt__.im_func(adaptable, default)

         if '__adapt__' in self.__dict__:
             adapter = self.__dict__['__adapt__'](adaptable, default)

Because self.__adapt__ would no longer be the same value as 
self.__dict__['__adapt__'], due to my adding a MetaInterface.__adapt__ 
method.  I assume that no inheritance lookup would be required, because 
interface inheritance for adaptation purposes is reversed.  That is, a 
subclass of an interface would not want to inherit its base interface's 
__adapt__, because a subclass interface has more stringent requirements for 
its implementors.  Therefore, a superclass __adapt__ isn't guaranteed to 
work for a subclass.

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?  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.)

Anyway, if you'd like some background on PyProtocols, the reference manual 
is at:


I don't know if you guys have previously looked at PEP 246 or thought about 
any of the adapter precedence/implication/declaration issues that 
PyProtocols tries to address.  It may be that some of what I've done may be 
useful to you.  OTOH, you may have already looked at this sort of thing and 
have different requirements for your component architecture.  My goal is 
merely compatibility among Python frameworks, so that people who use more 
than one framework's "Interface" types (e.g. Zope, Twisted, PEAK, etc.) can 
have some common ground rules, similar to the DBAPI or the way most Python 
numeric types can be used in an expression together.

More information about the Twisted-Python mailing list