Bippity, Boppity, Boo! (On moving CMF to Z3 Interfaces)
tl;dr
I spent some time today working on a branch for converting CMF to use Zope3-style interfaces, rather than the ones defined by Zope2.
Overview
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 Cinderella: 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:
Remaining Cleanup
Address the
XXX
comments I scattered through the docstrings, in particular.Figure out whether we need to leave
webdav.WriteLockInterface
as a Zope2 interface BBB wart.-
Decide what to do with the
z2interfaces
modules / packages to which I moved the discards:"Bring outcher dead!"? (Just scrag them, that is)?
"None shall pass!" (Reverse bridge them using the new Five directive in Zope 2.8.1)?
"Bring us ... a shrubbery!" (never mind, I forgot what that was going to be)?
Merge the branch to the HEAD (or, more likely, to the Subversion trunk, because Jens is planning[2] to migrate CMF's CVS repository this weekend.
- [1] The "initial checkin of CMFCore/interfaces/__init",
-
http://cvs.zope.org/CMF/CMFCore/interfaces/__init__.py was on Friday, 2001/08/10
- [2] "Re: Moving CMF into SVN",
-
http://mail.zope.org/pipermail/zope-cmf/2005-July/022629.html