Palladion Software
user icon Guest

Bippity, Boppity, Boo! (On moving CMF to Z3 Interfaces)

I spent some time today working on a branch for converting CMF to use Zope3-style interfaces, rather than the ones defined by Zope2.

Created by tseaver. Last modified 2005-07-15 23:23:16.


CMF was an early pioneer[1] of the use of Interfaces (we had them before there was such a thing as the "Component Architecture" project, much less Zope3) but their use was primarily documentary: they spelled out the API of each of the core tools, and the required "plug-in" APIs for content, etc., with the promise that if you swapped implementations for a "plug-compatible" replacement, everything would Just Work (TM)).

For the most part, this use of interfaces was a smashing success: it is what makes the CMF properly a framework, rather than a big pile of more-or-less useful libraries, and is one of the reasons Plone, Zope Corp's products, CPS, etc. have been able to move forward incrementally atop the evolving platform.

However, because they are Zope2 interfaces, rather than the shiny new model promulgated by Zope3, the CMF's interfaces have been playing something in the role of Cinderslut: they sit in the fireplace, doing useful work, but nobody wants to take them to the ball.

So, I donned my Fairy Godfather hat today, whistled up some mice and a pumpkin, and decided to change all that.

Today's Effort

Most of the work today was fairly mechanical: changing imports of Interface.Interface to zope.interface.Interface was pretty trivial. Because the HEAD requires Zope 2.8.0 or later, I could avoid adding lots of nasty backward compatibility cruft; I did leave the Zope2 versions lying around like a discarded glass slipper (in modules / packages renamed z2interface) in case somebody comes looking for them.

I had to disable the "bridging" code recently added (which synthesized Z3 interfaces from the original Z2 versions). Perhaps I should look into using the "reverse bridge" code which yuppie added, once it lands in Zope 2.8.1, to handle the "BBB" interfaces.

I also cleaned up a lot of docstrings in the original interfaces. In many cases, the "style guide" for docstrings has changed over time. My preference has always been for docstrings which specify the contract in the "imperative mode": e.g, rather than:

    def foo(bar, baz):
        """ This method frobs 'baz' into the 'qux' method of 'bar'.  'baz'
        will implement IBaz, unless it is None.  The method raises SpamError
        if 'qux' returns an error string.

I prefer:

    def foo(bar, baz):
        """ Frob 'baz' into 'bar.qux'.

        o 'baz' implements IBaz, or is None.

        o Raise SpamError if 'qux' returns non-None (an error string).

as less chatty, and more clearly "contract".

Originally, the "tool" interfaces had the same names as the tool IDs (e.g., the interface for the portal_actions tool was named portal_actions). In keeping with current practice (and with import ... as aliases already in the code), I renamed a bunch of the interfaces: portal_actions -> IActionsTool, etc.

I checked the code in on a branch, to allow for further work without destabilizing the head:

    $ cvs -d \
      co -d CMF-z3_interfaces -r tseaver-z3_interfaces-branch CMF

Remaining Cleanup

[1] The initial checkin of CMFCore/interfaces/__init was on Friday, 2001/08/10

[2] Re: Moving CMF into SVN