Tangled in the Threads

Jon Udell, August 20 1999

Exploring Zope

The subject of Zope came up again this week, courtesy of Bjørn Borud:

Zope being Python (and Python making my aestheticle hurt) I haven't looked much at Zope. (It's funny how the unappealing look of the code has made me stay away from Python.) Could you sum up Zope in a few lines? Exactly what does it do?

In (msg) I laid out some of Zope's salient features.

There was a lot of discussion about Zope in the previous incarnation of the newsgroups. I'll summarize that here, and invite you to direct new Zope discussion to the programming newsgroup.

As I worked through my first Zope project, my first concern was a practical matter having to do with its object database. Does all content end up in there, I asked, or are there ways to reference file-system content that is transcluded into Zope and made available to Zope's DTML (document template markup language) and other mechanisms?

When you end up with lots of content chunks and templates, I'd rather have those things in a file system where I have 100 ways to get at them (including a text editor) than have them locked up in any kind of database (relation, object, or whatever).

This problem is as old as the hills, really. I remember when FoxPro was a hot thing, and its interface tried to convince you to stick snippets of code into all sorts of nooks and crannies that you could get at only through that interface. I always ended up putting references in those places to files that I could separately edit and manage.

Jeffrey Shell, whose Python insights have informed the newsgroups for years, and who works at Digital Creations, the maker of Zope, set me straight:

Everything, and we mean everything, lives in the object database.

Zope 2 supports FTP and WebDAV as alternate access mechanisms (through ZServer). There are a few folks here who prefer to edit in EMacs/XEmacs and use ange-ftp to work inside of a Zope site. We've used WebDAV as a way of putting huge amounts of HTML and Images (like HTML Generated from a UML Model) into Zope easily. Zope 2 also supports XML-RPC.

Zope 2 also uses ZODB3 which supports object storage in various mechanisms. I believe that there are new sample storages that show how to do an entirely-in-memory example (mainly to show how to implement a fully transactional/undoable storage mechanism) and a DBM one (which doesn't pick up the transactional/versioning mechanisms). It's conceivable that a purely file-based mechanism could be written. But you'd lose all of the advantages of ZODB (versioning, transactions, undo, security).

Fair enough. I've explored the idea of keeping node placeholders in Zope's object database, to enable its object magic, while sourcing content from the filesystem. This wouldn't be ideal, though, you'd lose a lot of the clean manageability of Zope. Ultimately to use it, I think you have to buy all the way in to the object database, and trust it, and see what happens.

HTML tabbed indexes in Zope

For my first mini-project I decided to reimplement the HTML tabbed-index feature that I often use to tie sets of pages together.

Typically I generate sets of pages containing this feature, using Perl to vary the treatment applied to active (clickable) tabs vs the current (not clickable) tab.

Here is the Zope solution I came up with. First, a pair of folder properties called tabnames and tabvals containing the names (HTML link labels) and values (filenames) of the pages controlled by this tabbed index. Then, an external method bound to the folder, which receives the name of the current document (doc_id) and constructs the right tabbed index for that page:

def TabbedIndex(self,doc_id):
  ret = "<center><font face=\"Arial, Helvetica\" color=\"#663333\">\n"
  for i in range(len(self.tabvals)):
    if ( doc_id == self.tabvals[i]):
      ret = ret + "<font size=\"+1\">" + self.tabnames[i] + "</font>"
      ret = ret + "<a href=\"" + self.tabvals[i] + "\">" + self.tabnames[i] + "</a>"
    if ( i < len(self.tabvals)-1 ):
      ret = ret + "  •  "
  return ret + "\n</center>\n"

Finally, a DTML construct that is standardly included in every page belonging to the index set:

<!--#var expr="TabbedIndex(document_id())"-->

Robert Carey suggested some improvements to my (beginner) Python coding:

I have a tendency to write things the way you have here, probably because I have a Unix background. However, in Python you can use either single or double quotes interchangeably, and the one quotes the other. So it may be more readable to do:

ret = ret + '<font size="+1">' + self.tabnames[i] + '</font>' 

than to use backslashes to quote the individual quotes:

ret = ret + "<font size=\"+1\">" + self.tabnames[i] + "</font>" 

but obviously this is up to your personal taste.

Additionally, Python has a C-printf-like formatting operator. So you could say:

ret  =  ret + '<font size="+1"> %s </font>' % (self.tabnames[i]) 

Lastly, and this I particularly like, Python has multiline strings. So you can say:

template = """<font size="+1"> 
  ret = ret + template % (self.tabnames[i])

making the DTML block somewhat more readable.

Thanks Robert!

As an aside, note that in Perl you'd just say:

$ret = "<font size=\"+1\">$self->{tabnames}->[$i]</font>";

The chief difference being that you can always interpolate a variable anywhere in a string. The nonreadability of \"+1\" is, however, an issue.

Zope's intoxicating technology

I have a feeling I'll be doing more with Zope. I'm particularly interested to hear from people who are using it for substantial projects. As Cameron Laird has said in an article on Zope, its technology is "intoxicating." Said Jeffrey Shell:

Zope, I believe, can really carry over something I believed was significant about Python: ease-of-graduating-into-bigger-better-things. When I first picked up Python, I was amazed at how easily I went from using the interpreter as a calculator to writing small scripts to writing bigger scripts with functions to writing classes.

DTML Scripting offers a fair amount of power while retaining the through-the-web security and flexibility of being able to update your site anywhere, anytime. External Methods bring full Python programmability into the mix in a still (relatively) easy manner.

Zope's packaged Products are really powerful, exploiting Python's strengths within a framework that takes care of persistence, security, and web management. These Products include, for example, an IMAP Adapter (written by our own Michel Pelletier) which connects to an IMAP Server and can make the folders/messages act like Zope objects. Another is the LDAP Connector that does a similar thing with LDAP Servers - turns them into a hierarchical tree navigable in the Zope management screens with the ability to update attributes, create new subobjects, all through Zope.

Last but not least is the fascinating story of how Zope came to be an Open Source project. As Jeffrey reported in our newsgroups last year, it was Digital Creations' venture capitalist who convinced the company this would be a smart move!

Toto, I don't think we're in Kansas anymore.

PS: If anyone's figured out how to attach IE5, WebDAV-style, to Zope 2, please let me know.

Jon Udell (http://udell.roninhouse.com/) was BYTE Magazine's executive editor for new media, the architect of the original www.byte.com, and author of BYTE's Web Project column. He's now an independent Web/Internet consultant, and is the author of Practical Internet Groupware, forthcoming from O'Reilly and Associates.

Creative Commons License
This work is licensed under a Creative Commons License.