In the last nine months or so, not long after Philipp von Weitershausen published the second version of Web Component Development with Zope 3, Zope 3 underwent a massive change and restructuring. The application once known as Zope 3 split into a hundred peices in favor of “Zope 3 the framework”. Each component of Zope became a separate package distributed via eggs with ever-complex dependency trees. Another big change for Zope in the past 9 months has been the creation of numerous community maintained packages which are not considered “zope core”. These are the z3c.* packages. Written predominantly by rebelious Zope 3 hackers looking to make Zope even more powerful than before, the z3c.* packages quickly took center stage. Unfortunately for the rest of us, those who knew how to use the z3c.* packages were too busy being incredibly productive and successful that they never wrote any new books, tutorials, or easy to follow documentation. This document aims to assuage the woes of those still doing things the old way by providing a humble introduction to z3c.*.
This tutorial was primarily written for people who have already had some experience with Zope 3. The reader is assumed to have a certain level of understanding regarding basic zope paradigms: the component architecture, ZCML configuration, tal page templates, and of course python. Fortunately, there are already great books out there that cover these topics. If you haven’t done so already, I highly recommend taking a look at Philipp von Weitershausen, book Web Component Development with Zope 3, and using it as a supplement to this tutorial. Baiju M has also written a great online book detailing the ins and outs of the component architecture, which you can find here: http://www.muthukadan.net/docs/zca.html
Before we start working on our application, it is always a good idea to set up a python environment that is separate from the system python that came preinstalled with whatever linux distribution we are using (in my case, Ubuntu Gutsy). By creating a “virtual” python environment, we can easily avoid many problems associated with system python like broken packages, conflicting dependencies, etc.
A virtual python environment can be easily created using the virtualenv.py script available from http://svn.colorstudy.com/virtualenv/trunk/virtualenv.py. For documentation about what this script does, check out the pypi page at http://pypi.python.org/pypi/virtualenv. Download this script to your home directory and create a new environment called sandbox:
$ wget http://svn.colorstudy.com/virtualenv/trunk/virtualenv.py ~/
$ python ~/virtualenv.py sandbox
Alternatively, you can put this environment wherever you’d like and call it whatever you want. This folder now has a bin directory with a new python executable and easy_install script. It also comes with a bash script for placing your shell into the new environment so you do not have to type full path to run the environment’s python. Run this with:
$ cd sandbox
$ source bin/activate
After this you can see that it worked:
(sandbox)$ which python
/home/pcardune/sandbox/bin/python
From this point on, anywhere you see a shell command to run, it is assumed you have the virtual environment activated.
It’s helpful to start with a basic application skeleton so you don’t have to worry about writing all intial configuartion from scratch. Fortunately, Philipp von Weitershausen has written an excellent tool called zopeproject_ for doing this.
zopeproject can be installed using easy_install. Simply type:
$ easy_install zopeproject
Next we’ll create a new project called zcontact. zopeproject creates all the basic configuration you’ll need to be able to immediately start an empty zope application and log in with an administrative account. You will be asked for an intial username and password for the administrative account (which can be changed at any time) along with a location for installing the necessary components:
$ zopeproject zcontact
Enter user (Name of an initial administrator user): manager
Enter passwd (Password for the initial administrator user): zcontact
Enter eggs_dir (Location where zc.buildout will look for and place packages) ['/home/pcardune/buildout-eggs']: eggs
This step may take several minutes as a lot of code needs to be downloaded and some of it compiled. While you wait, I highly recommend glancing over the zopeproject_ documentation to get a better idea of what it is doing.
With that finished, you can jump right in and start your nascent application which will run on port 8080 by default.:
$ cd zcontact
$ ./bin/paster serve deploy.ini
Starting server in PID 23818.
serving on http://127.0.0.1:8080
You should now get an empty zope screen that looks like the one below:
The deploy.ini file given to the ./bin/paster command specifies options for running the server such as port settings. zopeproject also generates a debug.ini file that includes a WSGI filter for handling errors. If you ever run into errors, you can use the debug.ini configuration to inspect the code, as it is running, in your web browser!
To Keep Things Simple (Stupid) in this tutorial, we will adjust the permissions generated by zopeproject so we don’t have to worry about them later. Add the following lines to the site.zcml file in the root directory of your application:
<role id="zope.Anonymous" title="Everybody" />
<grantAll role="zope.Anonymous" />
This gives completely anonymous users access to everything with no restrictions.
Before we can jump into the world of z3c.* packages, we’ll have to have some object that we want to play with. Since ZContact is supposed to be a contact manager, let’s start with a contact object. To Keep It Simple (Stupid), we will just have two fields, a first name and a last name.
Note
All source code lives in the zcontact/src/zcontact folder so that zcontact/src/zcontact/interfaces.py could be imported as import zcontact.interfaces.
Open up interfaces.py and add the following:
import zope.interface
import zope.schema
class IContact(zope.interface.Interface):
"""A simple contact."""
firstName = zope.schema.TextLine(
title=u"First Name",
required=True)
lastName = zope.schema.TextLine(
title=u"Last Name",
required=True)
Now we can make our quick implementation. Open up contact.py and add the following:
import zope.interface
from zope.schema.fieldproperty import FieldProperty
import interfaces
class Contact(object):
"""See ``zcontact.interfaces.IContact``."""
zope.interface.implements(interfaces.IContact)
firstName = FieldProperty(interfaces.IContact['firstName'])
lastName = FieldProperty(interfaces.IContact['lastName'])
We also need to register the Contact class in zcml and set permissions for accessing the attributes. Just add the following to the src/zcontact/configure.zcml file:
<class class="zcontact.contact.Contact">
<require
interface=".interfaces.IContact"
permission="zope.View" />
<require
set_schema=".interfaces.IContact"
permission="zope.ManageContent" />
</class>
With that done, we can jump into views that use z3c.* components.
Caution
Don’t forget, in the real world you would write unit tests for this code first, if only to ensure that the Contact class really does implement the IContact interface.