24.7.05. Maddening

Last year, ESPN NFL 2k5 sent some shock waves through the video game world by presenting a solid competitor to Madden 2005 that was priced for $20 US instead of Madden's $50 US. To this point, I had never been much of a football video game fan. But ESPN NFL 2k5 made a convert out of me - both on its price and due to many positive reviews that had it on par or slightly better than Madden. Before too long, EA dropped the price of Madden to $30 in order to compete. I, and I'm sure others, hoped that this would kick start a pricing war among such titles, amongst other competition. (Being a $20 football game would have been one thing, but being a top shelf quality game for $20? Awesome!).

Instead, EA locked up all rights to using NFL names / teams / etc, effectively shutting anybody else out of the market. And with the 2006 season approaching, I'm looking a bit forward to Madden. But now that it's back up to $50 and it's unlikely that there will be any competition, I just have to hope it turns out good. I'll probably buy it, but it will be with a sigh.

18.7.05. Sweet and Lowdown

How's that title for a clever Django reference? (I initially was going to go with "some gypsy in France", but I imagine there might actually be a crowd of people out there who haven't had the opportunity to enjoy this fine film.

In regards to my Python off the Rails post, I've gotten a couple of pieces of feedback. The first is that Django is a harvested framework that has been running production sites, including some particularly impressive ones, for a couple of years now. Django is not a Python-come-lately framework like I initially read it to be. Thank you to both Simon Willison and Adrian Holovaty for pointing that out.

Another piece of feedback I got, from Adrian Holovaty, covers the larger part of the model that I touched on but didn't show in full. Referring again to the comments example,

    ordering = (('submit_date', 'DESC'),)
    admin = meta.Admin(
        fields = (
            (None, {'fields': ('content_type_id', 'object_id', 'site_id')}),
            ('Content', {'fields': ('user_id', 'headline', 'comment')}),
            ('Ratings', {'fields': ('rating1', 'rating2', 'rating3', 'rating4', 
                                    'rating5', 'rating6', 'rating7', 'rating8', 
            ('Meta', {'fields': ('is_public', 'is_removed', 'ip_address')}),
        list_display = ('user_id', 'submit_date', 'content_type_id', 'get_content_object'),
        list_filter = ('submit_date',),
        date_hierarchy = 'submit_date',
        search_fields = ('comment', 'user__username'),
These are used to help build UIs and such for these items, including administrative interfaces. According to Adrian, that's part of the design decision.

To me, this still smells like the extremely overweight Zope 2 objects, or at least of many Zope 2 based systems I've developed over the years because a path like this was the easiest path. These projects work. But they're not the greatest to maintain, to look at, or to have to go back and work on. Granted - it's better than doing a lot of this type of UI work manually. And I love having a decent coupling and reliability between validated data coming in from a form and what I have to store in a database.

In new projects, some built on our own in-house framework (a data management framework), some built in Zope 3, I'm preferring to off load as much of this stuff as possible from the core model object / model definition, and relating them all via a loose coupling.

It's the loose coupling that's not so easy, at least not on its own. Zope 3's component architecture is one way to solve this, usually by declaring a view or adapter as "provides(IFoo) for (IBar)" (not the actual code, but the intent). This is also where ZCML (Zope Configuration Markup Language) comes in. I used to wince at ZCML, and many people wince at XML based configuration. But it's nice to have the mechanism for loading up and registering components outside of the core language - or at least outside of the language's default code loading and execution procedures.

So in a Zope 3 application I'm working on, I have the following code. This is the model code for an article in a knowledge base. It needs no real logic - it's purely data. It subclasses from OrderedContainer because an article can contain comments. interfaces.IArticle describes the meaning of each of the properties shown here. There's no object-relational mapping going on. The ZODB provides pure persistence. Although, without too much effort, I could replace this implementation with a SQLObject based one via sqlos - a SQLObject support package for Zope 3.

class Article(OrderedContainer):
    title = u""
    description = u""
    content_type = u""
    content = u""
    tags = ()
I've already shown what a Zope 3 schema can look like, so I'm not going to cover that here. The IArticle interface and schema means that anyone can write their own implementation based on my schema, and things like what I'm about to show will still work. Zope 3 does just about everything based on interfaces, because - in theory - if all you care about is a duck's bill - does it matter if the animal is a duck or a platypus?

So, to create a simple edit form based on the schema for IArticle, the following ZCML is used. This is from a real application, with only the package names altered. I'll go over it line by line in a moment.

      label="Edit Article"
    <widget field="description" height="4"/>
    <widget field="content" height="18"/>
    <widget field="tags"
This declares an editform with the name 'edit.html' for implementations of the foo.interfaces.IArticle interface. An editform is a browser view. The 'schema' line tells the edit view what schema to use to render it, and the 'permission' line restricts access to site members with the zope.ManageContent permission. The 'label' gives the form its displayed title on the web page, while 'menu' and 'title' allow a view to be listed in a particular menu. 'zmi_views' render as tabs in the default Zope 3 user interface. Some things that could be done in this declaration which I did not do include providing a limited subset of schema fields to render, or providing a Python class that provides extended behavior for the editform view.

For many cases, that's all one might need to do with an editform. Maybe even less. Menu assignment is certainly nice in this situation, since it gives me a tab in the ZMI to edit an article from. But I wanted to customize some widget behavior without having to get too down and dirty with HTML or Python. That's what the widget directives offer. The first two let me have a shorter description widget and a tall content widget. Zope 3 will find the best view for these fields (which will turn out to be a textarea) and render them. The last widget for 'tags' is a custom widget that I implemented for doing tag style fields. It parses its input and turns it into a Python tuple of lowercase strings with extraneous whitespace and punctuation removed, as well as any duplicate 'tags'.

But that's it! The edit form collaborates with the named schema and its field definitions to validate and store the data into an instance of that very simple Article class I showcased above. It also fires off an ObjectModifiedEvent, which I can have subscribers listen for. This is used, for instance, to reindex a search catalog, and could be used to clear out caches.

The main point is that this admin is only loosely connected to that article object. As a developer, I could take the knowledge base article and its interface (if they were written by somebody else) and work them into my own CMS which might provide a very different UI and configuration than just a basic bare Zope 3 setup. Or I could adapt something that I had that was very similar to a knowledge base article and, through adaptation, provide an IArticle interface and have these views get bound to it.

Ultimately, a very nice thing about Zope 3's setup is that it's very well documented - all of the interfaces, the ZCML directives. When I write my IArticle interface, it gets indexed into Zope 3's increasingly useful api documentation tool, and if I wrote my own ZCML directives, they would also get scooped up. It's quite nice. In previous systems I've used and written myself, ones with a basic model implementation like Django's, there often ends up being a lot that the developer has to remember. This is a lot of what plagues Zope 2 developers. There are voodoo names one has to watch out for (there was a time when adding a DTML method named 'target' into a ZODB instance would cause the Zope Management Interface to do spectacularly funny things). The Zope 3 component architecture comes out of years of experience in these things, and I applaud the Zope 3 team for coming up with such a clean architecture (Zope 3.1 is cleaner than Zope 3.0!) that avoids getting bound to magic directory names, magic attribute names, and so on, as much as possible. In a Zope 2 properties screen, you're warned that "deleting the 'title' property is potentially dangerous". There's no such danger in Zope 3.

Python off the Rails

Django, the latest in the "we can be like Rails!" entries from the Python world, has been getting a lot of notice lately, while Subway is getting very little. And since Zope 3 and other such items aren't even mimicking Rails, they get zero notice, even though Zope 3 offers many similar benefits - extensively tested and testable, user interfaces easy to build off of introspection, separation of model code from views, controllers, as well as other site utilities (objects outside of the domain model that provide services such as authentication, database connection, object indexing and tracking, annotation, and so on).

I haven't run Subway. Or Rails. Or Django. On my desktop, I don't want to deal with an RDBMS if I don't have to, and most core setups and example applications for these apps seem geared towards requiring MySQL, despite whatever the frameworks authors may intend about where model objects come from. So this opinion is just from someone who likes to look at code and be impressed or disappointed.

Ruby on Rails impresses me, due to its extensive use of meta-programming to provide fairly natural language constructs when setting up ActiveRecord ORM objects. Subway impresses me because it provides a Rails inspired stack built on existing Python solutions - CherryPy (web/application server), SQLObject (object-relational mapper), Cheetah (templates). I think people have managed to get the ZODB object database and even an implementation Zope's Page Template system running with Subway, but I could be wrong. The nice thing is that they let these other systems do the so-called "heavy lifting" instead of writing yet-another-stack.

So things come down to how one describes their model objects, which is especially critical in an object-relational world (since you have to fit to the DBMS's constraints). It's equally applicable to the application itself though, as the constraints can be used for data storage / input form validation. Django seems stuck in the past. Maybe it's trying to be compatible with older versions of Python. To me, this is such an ugly "unpythonic" way of doing things. This comes from revision 28 of comments.py.

class Comment(meta.Model):
    db_table = 'comments'
    fields = (
        meta.ForeignKey(auth.User, raw_id_admin=True),
        meta.ForeignKey(core.ContentType, name='content_type_id', rel_name='content_type'),
        meta.IntegerField('object_id', 'object ID'),
        meta.CharField('headline', 'headline', maxlength=255, blank=True),
        meta.TextField('comment', 'comment', maxlength=3000),
        meta.PositiveSmallIntegerField('rating1', 'rating #1', blank=True, null=True),
        meta.BooleanField('valid_rating', 'is valid rating'),
        meta.DateTimeField('submit_date', 'date/time submitted', auto_now_add=True),
        meta.BooleanField('is_public', 'is public'),
        meta.IPAddressField('ip_address', 'IP address', blank=True, null=True),
        meta.BooleanField('is_removed', 'is removed',
            help_text='Check this box if the comment is inappropriate. A "This comment 
                       has been removed" message will be displayed instead.'),
    module_constants = {
        # used as shared secret between comment form and comment-posting script
        'COMMENT_SALT': 'ijw2f3_MRS_PIGGY_LOVES_KERMIT_avo#*5vv0(23j)(*',
It just goes on and on from there. It's not very Pythonic, but it is the way that many of us used to do things in the Python world. But now, thanks to meta-programming being more accessible in recent versions of the Python language, you can have a system that looks like this - from a comments example for Subway, revision 57:
from subway import model
import sqlobject as db # funky alias

class Comment(model.Model):

    _table = 'comment'

    email = db.StringCol(length=50)
    website = db.StringCol(length=50)

    screenName = db.StringCol(length=50, dbName='screen_name')        

    content = db.StringCol()
    parsedContent = db.StringCol()

    created = db.DateTimeCol(dbName='date_created')
Granted, it's a much smaller example than the one listed above. But you can see that at least here, you have the more familiar class and attribute construct - a = b. Personally, I'm not fond of the 'Col' (column) suffix, but it's an improvement over the Django implementation. This does not show any foreign keys or row/object ids, but I expect them to be similar.

For the record, Zope 3 doesn't really require anything like this when going against the ZODB. But most Zope 3 development, which is interface driven, uses schema descriptors when defining object interfaces. This might look like:

from zope.interface import Interface
import zope.schema

class IComment(Interface):
    email = zope.schema.TextLine(title='Email', required=True, max_length=50)
    website = zope.schema.URI(title='Web Site')
    screenName = zope.schema.TextLine(title='Screen Name', required=True)
    content = zope.schema.Text(title='Content', required=True)
    parsedContent = zope.schema.Text(title='Parsed Content')

    created = zope.schema.DateTime(title='Created', required=True)
Of course, when using the full power of Zope 3, you could get the created date from the Zope Dublin Core, and even the screen name you can get from that as well. But I didn't want to go into those specifics. Note that the above code on its own doesn't really do anything. It's just specifying an interface. We could define methods that implementations of IComment would have to implement as well if wanted.

One of Rails big showoff pieces is scaffolding, which generates user interfaces based on ActiveRecord objects. If you add a comments field to the database as a TEXT column, it can immediately show up in the scaffolding UI as an HTML TEXTAREA. Zope 3 can do similar, although there's no cool name for how it does it like 'scaffolding'. There are a few layers that work together in Zope to do this naked objects style approach. Zope 3, using interfaces heavily already, extends them with Schema support to allow developers to specify an objects properties. Input systems, such as HTML forms and their handlers, can use this information to present and validate input. It's a way of using dynamic typing effectively by also being able to write and implement more expressive validation beyond 'email is a string'. Now it's known that "email is a string that's required to have a value" and code elsewhere in the system can better depend on the "email" value being present. And since interface definition is independent of implementation, one could use the IComment interface describe above with the SQLObject implementation above it and declaring zope.interface.implements(IComment).

What is my point with all of this? In general, it's that I don't think that Django's present implementation is a good example of the best that Python can be when it comes to the type of systems inspired by Rails. I think Subway is a better implementation and as a developer, it certainly looks more enjoyable to work with. I've done the big huge list of fields = (String('title'), String('description'), ...) things in the past. They're not fun. Subway, Zope 3, and Nevow better employ the Python language, in my opinion. I don't yet see what merits all of the sudden attention Django is getting. Oh well. Bobo - Principia - Zope 1 - Zope 2 have been helping me implement solutions for almost ten years now, and Zope 3 will probably be my platform of choice for the next 5-10 years. While everyone else in Python land tries to find the next thing to copy, I'll be working on the same basic python object publishing concepts that blew me away back in '96.

13.7.05. Faassen on the Zope 3 catalog

Martijn Faassen writes about implementing extended catalog queries in Zope 3.

Why was this so easy in Zope 3? I think there are two reasons:
  • Clean implementation of the catalog makes it code fairly easy to read and thus write similar code. The catalog implementation in Zope 2 is a horror to try understanding, in Zope 3 it really is surprisingly easy. This pattern holds for much of the Zope 3 code base.
  • Zope 3 gives every object an integer id using the IntIds utility, which helps making the catalog so clean. IntIds rock!

On the Zope 3 project that I'm getting ready to work on, I'll be dealing with the Zope 3 catalog for the first time. I'm actually looking forward to it. I'd like to see how well the whole process of writing an indexed application in Zope 3 works. Implementing against the ZODB is so nightmarishly easy, and it's nice to tinker with on my desktop without my having to worry about installing an RDBMS, adapters, and so on.

12.7.05. Adapting content attributes to Zope Dublin Core attributes

In many content oriented web applications - regardless of whether its a weblog, a simple knowledge base, a full bore CMS, a snippets library - there are often a number of common attributes that all items share - creation date, title, description, and so forth. In Zope 3, there are some built in components and utilities to provide these core elements to your content object, without using inheritance or having to implement all of these elements on your own.

As far as I understand it, this is done through an Annotations Adapter. When configuring and registering a content component through Zope 3's configuration language, ZCML, you (the developer) have the option of declaring additional marker interfaces. The most common way of supporting annotations is with the IAttributeAnnotatable marker interface.

This allows other content components to add their own data to your object in a transparent way - annotations are marked by a special key. WebDAV supports this in its properties system (if I recall correctly), allowing applications like Adobe GoLive to store their own interesting properties without the host storage system / application having to be impacted. In this Zope 3 case, annotations are all stored under a single hidden persistent attribute which holds the keys to the extra annotations.

You must forgive me. It's 1AM and I doubt I'm explaining this as well as I could be. In any case - the annotations system is a way of allowing objects to be extensible for use in other applications without the target object having to be impacted. This is done through adapters, which are other ways of extending objects. Adapters are commonly used in Zope 3, and I'm sure I've touched on them in other posts already.

So the common Zope Dublin Core implementation for Zope 3 uses annotation adapters to store and retrieve dublin core metadata. But what if your objects provide some bits of common dublin core data themselves? Zope 3 has an answer to that - partial annotatable adapter factories, which support the Dublin Core using a mixture of annotations and data on the context object. (source: zope.app.dublincore.annotatableadapter).

So for this snippets application, which I'm monkeying with as time permits, my IPost implementations provide a title and description (both common dublin core elements), and my IComment implementations provide a title and a body that could potentially be used as a description. I'd like to tell Zope that it can get these properties directly from my objects when it asks for dublin core data. Here's my implementation:

from zope.app.dublincore import annotatableadapter

def PostDCMapper(context):
    Uses the partialAnnotatableAdapterFactory to map certain DC attributes
    to content attributes.
    # map - {dublin core name -> our name}
    map = {'title': 'title', 'description': 'description'}
    return annotatableadapter.partialAnnotatableAdapterFactory(map)(context)

def CommentDCMapper(context):
    # map - {dublin core name -> our name}
    map = {'title': 'title', 'description': 'body'}
    return annotatableadapter.partialAnnotatableAdapterFactory(map)(context)
Notice how the 'CommentDCMapper' supplies the comment's 'body' property for the 'description' element. Here's the ZCML configuration to register these as adapters (well, as factories that provide adapters):
I found out about this from looking through the source code for Cubic, a mini-CMS that aims to be built using as many core Zope 3 components as possible (and looks to be a good example for me to look at as I need plan on building a simple and full indexed application using Zope's catalog and index capabilities). Cubic's implementation provides a few extra tricks for mapping the directly provided dublin core elements on a per-content-type basis, but I wanted to circumvent that for this round and provide direct adapters.

5.7.05. Adding new text source type options in my application.

Now that I have Textile support integrated into Zope 3 for my application, I decided to add support for different source types to said application. This didn't really require much on top of the previous work. First, I added a new field to the IPost interface and a new default class attribute to the Post implementation for the Post's "description_type". On the interface, I added the field as a Choice stemming from the "SourceTypes" vocabulary:

    description_type = zope.schema.Choice(
        title=u"Description Format",
        description=u"Type of the description text.",

Then I updated the 'renderDescription' method of the PostView class to get the description type from the adapted object and use that to get the renderer. Now the method looks like this:

    def renderDescription(self):
        """Renders the description from textile source."""
        description = self.context.description
        description_type = self.context.description_type
        source = zapi.createObject(description_type, description)
        view = zapi.getMultiAdapter((source, self.request))
        return view.render()

After restarting the application, I now have this as my add-form:

Notice another one of those types - "Source Code". I created that type for my code snippet content, with a renderer that wraps up text in HTML 'pre' tags and quotes some common trouble entities (angle brackets, ampersands).

Adding Textile Support to Zope 3

I wanted to add Textile support to my Zope 3 ‘snippets’ application. It was quite simple, thanks to Zope 3’s concept of Source Types. Source Types are marker interfaces and text rendering views which render a plain text source type into HTML. The sources that are registered with the system are kept track of in a Zope Vocabulary which could be used to give users input options – plain text? structured text? reStructuredText?

In a component architecture, this is just the type of thing one would want to be able to plug into and extend. Here’s how I added PyTextile support into my application.

First, I added textile.py into my packages root folder, although it could have been placed anywhere on the Python path.

Second, I created the marker interface and a renderer for it:

from zope.interface import implements
from zope.app.publisher.browser import BrowserView
from zope.app.renderer.interfaces import ISource, IHTMLRenderer
from zope.app.renderer import SourceFactory
import textile

## Textile
class ITextileSource(ISource):
    Marker interface for textile code.
TextileSourceFactory = SourceFactory(ITextileSource)

class TextileToHTMLRenderer(BrowserView):
    """ A view to convert textile source to HTML """
    __used_for__ = ITextileSource

    def render(self):
        rendered = textile.textile(str(self.context),  head_offset=3)
        if not isinstance(rendered, unicode):
            rendered = unicode(rendered)
        return rendered

Now I had to tell Zope about the source type and renderer. In my packages configure.zcml file, I added the following:

      description="Textile source" />
      permission="zope.Public" />

The first configuration statement lets me create a Textile source object by referring to the factory id. This is how another widget or variable could be used to create a source object. I'll show how the factory is used in a moment. The second configuration statement registers a browser view, which is a special kind of "multi-adapter", adapting an object and HTTP Request to an HTML view of the object. Finally, I need to render the Textile source stored in the Snippet Post objects into HTML when being viewed through the web. In a view class I've registered for IPost objects, I have the following method:

class PostView(DublinCoreViews):
    __used_for__ = IPost
    def renderDescription(self):
        """Renders the description from textile source."""
        description = self.context.description
        source = zapi.createObject('textism.textile', description)
        view = zapi.getMultiAdapter((source, self.request))
        html = view.render()
        return html

It is the zapi.createObject call which finds and calls the textism.textile source factory and passes in the 'description' as a value. (Note: self.context is the reference to the IPost object this view is written for). The next line finds an adapter for the source object and the HTTP Request, which is the TextileToHTMLRenderer class, and then the text is rendered and returned as HTML.

A benefit of all of this is that now any Zope 3 product / package / application that uses the sources system, such as the Zope 3 'ZWiki' implementation, now has Textile as a source option. And with only a tiny bit more work on my application (basically adding another field to the IPost Interface about source type), I could let my users have the option of other source types (simple plain text, structured text, reStructuredText) as well as Textile.