[Zope3-dev] Interface questions

Jeremy Hylton jeremy@zope.com
Mon, 04 Mar 2002 15:30:53 -0500 (EST)


I uncovered a small bug in the cPersistence implementation today.  It
doesn't currently have an __implements__ attribute.  This is
straightforward to fix, but I want to add a test for it first.
I've never used the Interface package before, but I thought it was a
great time to try.

I've hit a bunch of small obstacles, and I'm not sure where to direct
questions.  So here they are to the whole list.  I don't intend this
message to sound testy; I worry that it will come off as negative
because I'm reporting bugs.  :-)

The test I want to write is a test that Persistent implements
IPersistent.  So I read the section of README.txt titled "Testing
assertions."  It says:

    Similarly, you can test whether, by default, instances of a class
    implement an interface by calling the 'implementedByInstancesOf'
    method on the interface and passing the class::
  
      I1.implementedByInstancesOf(A)

I've loaded IPersistent:

>>> from Persistence.IPersistent import IPersistent
>>> IPersistent
<InterfaceFromClass Persistence.IPersistent.IPersistent at 81d0374>

but it doesn't have an "implementedByInstancesOf" attribute:

>>> IPersistent.implementedByInstancesOf
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: interface_loader instance has no attribute 'implementedByInstancesOf'

I don't understand where interface_loader comes from or why it's
showing up in the getattr?  (Okay.  After puzzling for a while, I did
conclude that IPersistent is an instance of something.)  I think the
interface name should be present in the error message.

I tried to find out what went wrong by looking at the source for
Interface, since IPersistent inherits from Interface.Interface.  The
source is a nest of imports with renames and import *.  It would be
*really* helpful if this could be refactored to make it easier to
read.

Interface.Interface is an alias for Interface.Standard.Base.
Interface.Standard uses import * three separate times.
It gets Based from Interface.Basic.
Interface.Basic.Base is an alias for Interface.iclass.Base.
Interface.iclass.Base is an instance of InterfaceFromClass,
    which is also defined in Interface.iclass.
InterfaceFromClass is a class that extends Interface.

    I thought I was looking for the definition of Interface,
    so I seem to have hit a circular reference!

Interface.iclass.Interface is a class, which is related only
   tangentially to the public Interface.Interface.

Interace.iclass.Interface defines as isImplementedByInstancesOf()
   method.

Either the code or the documentation is wrong, but I'm not sure
which.  If someone tells me which is right, I'll fix the one that is
wrong.

The "interface_loader" name that confused me in the AttributeError
seems to be a side-effect of the way Interfaces are made persistent.
In particular, this code: 

    class InterfaceLoader:

        __safe_for_unpickling__ = 1

        def __call__(self, module, name):
            __import__(module)
            mod = sys.modules[module]
            i = getattr(mod, name)
            return i

    interface_loader = InterfaceLoader()


    InterfaceFromClass.__name__ = 'interface_loader'  # Trick unpicklers.

    Base = InterfaceFromClass("Interface")

Wouldn't it be clearer to define a reduce function for
InterfaceFromClass that called an InterfaceLoader function?
Then we could leave the __name__ attribute alone.

Jeremy