Teacher: Paul Carduner
Students: Brittney, Will, Preetam, and Linda
Introduction
Paul:
Good morning, everyone, let's start learning to program in Zope3!
Zope stands for the Z Object Publishing Environment. It is the web framework that we will be using to write our web application. Zope's greatest strength is its component architechture. The component architecture allows us to break things up (programmatically) into different parts that work with each other yet independently. For example, we can use the component architecture to separate the data storage, business logic, and user interface so that programmers don't have to worry about how things look, and web designers don't have to worry about how things work.
In addition, with a component architecture, an application is comprised of chunks of functional code, which can be reused easily in other third party applications.
So to begin with, I will assume you have each read over the user stories and have a running instance of zope3 in your home directory in a subdirectory called
zope3. You will need an editor you can use to edit python files. Vim or Emacs are always good choices. Starting in your home directory, do the following to begin setting up thezcontactapplication:
cd $HOME/zope3/lib/pythonmkdir zcontactcd zcontactecho "# Makes this folder a python package" > __init__.py(to make thezcontactdirectory a module)vi interfaces.pyA note about the
__init__.py:
It makes the zcontact directory a python package. So that if a python interpreter is opened while in~/zope/lib/python, you can import the zcontact package like so:>>> import zcontactTry importing
zcontactwithout__init__.pyto see what happens.Now create and edit
interfaces.pyso that it looks like this:import zope.interface class IContact(zope.interface.Interface): """The interface for a contact.""" lastName = zope.interface.Attribute("A contact's last name.")The triple quoted string,
"""The interface for a contact.""", is used to specify a particular kind of comment, called a docstring because it is used to provided documentation for the object in which it is found. Docstrings must be written immediately underneath the class definition header.
Brittney:
Stephan Richter, on page 52 lines 01 & 02 of the Zope3 Developer's Handbook, uses a different syntax for the import. He uses:
from zope.interface import InterfaceCan you explain the difference?
Paul:
You can use either method of import. Since many of you are fairly new to writing a large Python application like this, I thought it would be clearer to make the source of the classes we are importing explicit, rather than bringing them into the main namespace of the program.
Will:
Why do we use"A contact's last name."when creating thelastNameattribute? Is it a default value or something?
Paul:
That is a good question. The string we pass to thezope.interfaces.Attributeobject is not a default value. The string actually serves as documentation for that attribute. You might ask,Well why don't we just put a comment aboveUnfortunately, when you use regular python comments, it is difficult to figure out what piece of code the comment is talking about. However, if we make the comment as part of the code itself, then it will be available to us programmatically.lastNameinstead?
Brittney:
Is interfaces.py supposed to do anything?
Paul:
At the moment, no, it won't do anything. If you wanted to run it through Python to make sure you don't have any syntax errors, you could run
python interfaces.py. If Python doesn't report any errors, then your syntax is OK. As soon as we begin to import things though, you would need to add the following line to the bottom of your.bashrcfile so Python can find the zope source:PYTHONPATH=/usr/local/src/Zope3/src export PYTHONPATHNote that in this case we are assuming you have installed zope as described in https://wiki.ubuntu.com/LearningZope3. If you have installed zope somewhere else, you will need to adjust the
PYTHONPATHaccordingly.
Preetam:
You can check that this worked by typing:echo $PYTHONPATH
Paul:
All right, is everyone ready to move on? Good, let's begin.
The first thing to understand is that Zope is a content management system, so the most important thing we are going to be working with is content, specifically what are called content objects. A content object is any type of information we want to store as a complex python class. For example, what we are working on now is a representation of a
Contactthat can be stored in the system.For every content object, there will be interfaces which define what features the content object will provide. That is, the implementation you come up with for this object must fit a
contractdefined by an interface.Interfaces are also heavily used for documentation purposes. So, in the
interfaces.pyfile, you see theIContactinterface, and we have defined one attribute,lastName. That means that all implementations of theIContactinterface must have alastNameattribute.
Brittney:
I don't understand, where is the implementation of IContact?
Paul:
We haven't written the implementation yet. That is the next step we are going to do.
Create and edit a new file in your zcontact directory called
contact.py. This file will contain our implementation ofIContact. Add the following code to your file:import zope.interface import interfaces class Contact(object): """Implementation of IContact""" zope.interface.implements(interfaces.IContact) lastName = u''Notice that we are importing
interfaceswhich is the code that containes theIContactinterface. We create a class named the same asIContactexcept without theIbecause this is an implementation. Although the standard prefix for interfaces isI, there is no prefix for implementations. The line that sayszope.interface.implements(interfaces.IContact)is used to connect this implementation to the interface it is implementing. In one sense we areregisteringthis class as implementing theIContactinterface. Finally, we include alastNameattribute in the class definition because theIContactinterface requires it.
Brittney:
Why is there a
uin front of the quotes for thelastNameattribute?
Paul:
The
udenotes that this empty string is a unicode string. It is very important in web applications that all strings in the program be unicode strings. Unicode strings allow us to put characters from other languages like Arabic or Chinese rather than just the ASCII characters. Zope often requires strings to be unicode, and will even throw errors if the strings are not unicode strings.Let us continue. We have now defined a simple
Contact. The next step is to create and edit a file calledconfigure.zcml. ZCML stands for Zope Configuration Markup Language. It is an XML language we use toglueall our code together. You will see what I mean by this shortly. The first lines should be:<configure xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser">The
configuretag is always the first tag in a zcml file, just like<html>is always the first tag in an html file. In this tag we specify the xml namespace for the rest of the document. The namespace defines what kind of tags will appear in the configuration file. The first namespace we define is the zope namespace, which allows us to configure the content objects we created, likeContact. Since there can only be one default namespace in a configuration file, additional ones have to be specified using a prefix. For the browser namespace we specify the prefixbrowserby writingxmlns:browserinstead of justxmlns. The browser namespace allows us to configure how objects get displayed in a web browser.The next lines to put in the zcml file are:
<class class="zcontact.contact.Contact"> <require permission="zope.View" interface="zcontact.interfaces.IContact" /> <require permission="zope.ManageContent" set_schema="zcontact.interfaces.IContact" /> </class>The class tag is used to register and configure a particular object within zope. By default, zope does not allow access to any attributes defined in a class, so we have to explicitly define permissions for them using the
requiretag. With the first require tag we are saying that you must have the zope.View permission in order to read the attributes defined in theIContactinterface. The second require tag says that we must have the zope.ManageContent permission in order to change the attributes defined in theIContactinterface. We will talk about why it saysset_schemainstead ofset_interfacein a later lesson. We will also cover more on permissions in later lessons.Finally, the last lines to add are:
<browser:addMenuItem title="Z Contact Page" description="Add a Z Contact Page" class="zcontact.contact.Contact" permission="zope.ManageContent" /> </configure>Don't forget to close the
configuretag at the end of the zcml file. Thebrowsertag allows us to add a link in the ZMI, or Zope Management Interface, under a specialAdd Menuwhich allows us to actually add an instance of the Contact object to our database. We will talk more about how the database works later.I see we are almost out of time, so now would be a good time to stop. But before we go, I want you to make a file called
zcontact-configure.zcml, and, in addition to having it in yourzcontactdirectory, have a copy in yourzope3/etc/package-includesfolder. The file only needs one line:<include package="zcontact" />. This lets Zope know about our package so that it gets included when the zope server starts up.Now you should be able to start up your zope server and log in to the ZMI. If the zope server doesn't start, then there is something wrong with your code. Once you are logged into the ZMI, you should see a link in the add menu called
Z Contact Page.When you click on it, you will be able to enter in a name for the new object and actually create it.Now would be a good time to show you another way you can look around the zope3 source. Start zope (by executing
./zope3/bin/runzopefrom your home directory). Now point your web browser athttp://localhost:8080/++apidoc++. After you login you will be in theZope 3 API Documentationbrowser. Click onCode Browserand then theBrowse Zope Sourceon the bottom frame on the right. You will be able to click your way through the entire source tree using your web browser.For homework, look over the Writing New Content Objects chapter (http://wiki.zope.org/zope3/contentobject.html) from the Zope 3 Developer's Handbook. (http://wiki.zope.org/zope3/Zope3Book). You will see what we did today in class in that chapter.
Well, see you all next week. Class dismissed.
Files:
When you click on the links below you will be presented with text versions of these files. If you choose to save these files from your web browser, be sure to put the files in the proper directory structure.
- zcontact/interfaces.py
- zcontact/contact.py
- zcontact/zcontact-configure.zcml
- zcontact/configure.zcml
- zcontact/__init__.py
A gzipped tarball of all these files is located here: lesson01.tgz