Plone — The Development Environment
From InstallationWiki
| Official Page |
| Project Documentation |
| Download |
|
Zope is an open source application server for building content management systems, intranets, portals, and custom applications. The Zope community consists of hundreds of companies and thousands of developers all over the world, working on building the platform and Zope applications. Zope is written in Python, a highly-productive, object-oriented scripting language.
Before we can start building our application, we should set up a suitable development environment. This should as closely as possible mirror the final live server configuration, so that we can test our software locally before deploying it. The environment should also provide appropriate tools to support us during development.
In this tutorial we will learn more about the elements of Zope's software stack and how they can be configured for development. We will also cover some supporting tools and technologies, such as Python eggs and Paste Script.
Contents |
[edit] Prerequisites
Pre-built packages for Zope and Plone are available for many operating systems. These can be tempting, but as developers it is normally better to configure the environment ourselves, in order to fully understand and control it. During development, we need write access to the Python code and configuration files. We may also need to run different versions of Zope and Plone in parallel.
We will assume that you have at least the following as part of your regular development environment:
- Python 2.4. We will assume that Python 2.4 gets invoked when you run
pythonon the command line. Unfortunately, Zope, at version 2.10, does not yet support Python 2.5. Note that many Linux distributions have two packages for Python one containing the binaries, and one containing header files (typically calledpython-devor something similar). You will need both in order to compile Zope.
- PIL, the Python Imaging Library (http://www.pythonware.com/products/pil), should be installed for this Python interpreter.
- elementtree, an XML processing library, is required for Plone to start up. Most operating systems have packages for this. It can also be downloaded from http://effbot.org/zone/element-index.htm.
- A programmer's text editor. Preferably one with Python, XML/HTML and CSS syntax highlighting. You should set up your editor so that a tab/indent is output as four spaces. This makes Python development a lot more predictable.
- A shell. Bear in mind that path separators on Windows are backslashes (\), while other environments use forward slashes (/). Also, environment variables on Windows are referred to as
%NAME%, while in most Unix shells, including Bash, variables are dereferenced with$NAME.
- A Subversion client. We will show the command line client syntax, but you can use a graphical client if you are more comfortable with that. Subversion can be obtained from http://subversion.tigris.org.
- A C compiler. You will need this to compile Zope. The venerable gcc is fine on UNIX-like systems. On Windows you probably want mingw32 (http://www.mingw.org). Alternatively, you can use a Zope Windows installer to get a binary Zope distribution.
[edit] Quick Start
Understanding your development environment is an important step in becoming a productive developer. If you need to get up and running quickly, however, and you have the prerequisites outlined above in order, here are the key steps.
We will assume you have Python 2.4 as your main Python interpreter. First download easy_install if you do not have it already, and use it to install ZopeSkel:
$ wget http://peak.telecommunity.com/dist/ez_setup.py $ python ez_setup.py $ easy_install ZopeSkel
Then, use paster, which was installed as a dependency of ZopeSkel, to create a new buildout. This folder holds our source code and dependencies, including the Zope application server:
$ paster create -t plone3_buildout myproject
You can accept the defaults for all the questions, except for the password, which you must enter. Then, build the environment like so:
$ cd myproject $ python bootstrap.py $ ./bin/buildout
This last step may take some time, and you will need a live Internet connection. When it is complete, you can start Zope with:
$ ./bin/instance fg
Go to http://localhost:8080/manage and you should see the Zope Management Interface. Use the drop-down box to add a Plone Site. If you call this mysite, it will be accessible from http://localhost:8080/mysite.
[edit] Glossary
Let us now take a step back and consider our development environment in more detail.
The table below summarizes the various terms and technologies that you will encounter in this tutorial. It pays to be familiar with these names, because you will find them in Plone documentation.
| Term | Definition |
|---|---|
| Zope installation | Zope consists of Python code, C extensions, configuration files, documentation, scripts, and utilities. Collectively, these are known as the Zope installation. |
| Software home | The part of the Zope installation that contains the main Zope runtime. This is found in the lib/python directory of the Zope installation. The full path is assigned to the $SOFTWARE_HOME environment variable when Zope is run.
|
| Zope instance | The same Zope installation can be used to power multiple Zope servers, possibly running concurrently on different ports. Each instance has a directory containing a configuration file, instance-specific software components (e.g. an installation of Plone), and the local Zope database storage. |
| Instance home | When a Zope instance is running, the $INSTANCE_HOME environment variable refers to the directory where the instance is set up.
|
| Package
| A generic term for a distributable bundle of Python modules and supporting files. |
| Product | The traditional way to redistribute software for Zope 2 is in a "Product", which we will sometimes refer to as an "old-style Product". Products are placed in a special directory (Products/) and automatically discovered by Zope. The term "product" is also used more generally to refer to add-on components that extend Plone, even if they are not actually packaged as old-style Products.
|
| Egg | A more generic and flexible alternative to products. Eggs are not specific to Zope, and Zope has only recently been made egg-aware. In addition to code, eggs contain metadata such as version, dependencies, and license information. Egg management tools can use this information to manage concurrent versions or automatically fetch dependencies, for example. |
$PYTHONPATH
| The $PYTHONPATH environment variable lists the directories containing Python packages that should be available at run time. It can also reference specific eggs. You should not have to set this manually.
|
| setuptools | A Python library, which extends Python's built-in distutils package to support extended egg metadata and offers enhanced functionality when using software packaged as eggs.
|
| The Cheese Shop | Also known as PyPI (Python Package Index). An online repository of Python eggs. Anyone can upload a package here. Egg-aware tools can use the Cheese Shop to locate dependencies and download them automatically when installing other eggs. |
easy_install
| A command-line tool, which searches the Cheese Shop for a given package, and downloads and installs it. Note that, by default, easy_install puts packages in the global site-packages folder for the Python interpreter that was used to install easy_install itself. Normally, we want our Plone packages to be local to a specific Zope instance, necessitating different tools.
|
paster (Paste Script)
| paster, part of the Python Paste package, is a command runner. The paster create command invokes Paste Script templates, which are used to create skeleton packages based on command-line options and questions.
|
| ZopeSkel | A collection of Paste Script templates for Zope and Plone development. We will use this to create new egg-ready packages, as well as the buildout that manages our development environment. |
| Buildout (zc.buildout) | A "buildout", using the zc.buildout toolset, is a self-contained environment that is controlled through a single configuration file (buildout.cfg). We will use it to download, install, and configure Zope, Plone, and other dependencies. Buildouts are "repeatable", meaning that they can be used to replicate a particular setup across multiple servers or developers' machines.
|
[edit] Creating a Zope Instance Manually
To use Zope, we must first download and install its libraries and extensions, and then create an instance of the application server. The Zope instance keeps track of installed applications (such as Plone), any custom configuration settings, and the object database where all our content will live.
Later in this tutorial, we will show how to automate the installation of Zope and creation of a development instance using the zc.buildout tool. It is important to understand how to install Zope manually, not least because other documentation may assume you are using this style of installation.
First, download Zope from http://zope.org. If you are on Windows and you do not have a C compiler installed, it may be easier to use an installer. For Plone 3.0, you should use the latest version of the Zope 2.10 series, and at the very least Zope 2.10.4 (if in doubt, check the Plone release notes).
For example, let us install Zope into a folder called zope in our home directory:
$ mkdir ~/zope $ cd ~/zope $ wget http://www.zope.org/Products/Zope/2.10.4/Zope-2.10.4-final.tgz $ tar xzf Zope-2.10.4-final.tgz $ cd Zope-2.10.4 $ python setup.py build_ext -i
This will download Zope (you could of course use a web browser instead), unpack it (for which you could use a graphical tool such as WinZip if desired) and build it in place, including its C extensions. See the documentation that comes with Zope for information on other build options.
Next, we will create an instance of the application server using our newly installed version of Zope:
$ mkdir ~/instances $ cd ~/instances $ ~/zope/Zope-2.10.4/utilities/mkzopeinstance.py -d testinstance
At this point you will be asked to specify a username and password for the default Zope user. When the script is complete, you will have a fully featured Zope instance in the testinstance directory. At run time, this directory is known as the $INSTANCE_HOME.
You may want to edit testinstance/etc/zope.conf, for example to change the default port from 8080 if you have another server running there.
You can start the instance like so:
$ testinstance/bin/zopectl fg
On Windows, you will need to use:
> testinstance\bin\runzope.bat
When Zope is running, you can access the Zope Management Interface (ZMI) with the username and password you provided, by opening a web browser and going to http://localhost:8080/manage.
To stop the server again, press Ctrl+C in the terminal window where Zope was started. If you used the Windows installer, you can start and stop the instance from the Services control panel in Administrative Tools.
To be able to use Plone, you now need to install its products and packages. Stop Zope, download the Plone tarball from http://plone.org/download, and extract it into testinstance. This should put various directories into the Products folder. For example, you should have testinstance/Products/CMFPlone and testinstance/Products/ATContentTypes among other directories.
Similarly, several new packages should have been extracted to testinstance/lib/python. You should have testinstance/lib/python/plone and lib/python/kss, among other packages.
You should now be able to re-start your instance, return to the ZMI and add a Plone Site to the root of the object hierarchy. When you add objects in the ZMI or in Plone, they are stored in the ZODB Zope's built-in object data base.
If you have a problem using Zope or Plone, you may need to review the instance's log files.
[edit] Understanding Eggs and Setuptools
Python eggs are not specific to Zope or Plone. However, since Zope has only recently become egg-aware, they are new to many developers.
Traditionally, almost all Zope add-on products, including Plone, have been distributed as Zope products. These are fairly easy to manage you typically copy or symlink them into $INSTANCE_HOME/Products. Zope will scan this directory on startup, taking care of any product initialization and registration.
However, code inside products is nearly impossible to re-use outside Zope because Zope does magic things with the Products.* namespace. Further, the namespace quickly becomes crowded, which deters developers from breaking up functionality into smaller, more re-usable and better-isolated packages.
The Zope 3 philosophy is to be as close to "plain Python" as possible, and that means distributing code as such small packages. So long as its dependencies are in order, any package should be able to run in any environment. For example, the zope.interface package is used by the Twisted project, which is not otherwise dependent on Zope. This design goal has made it much easier to adopt Zope 3 packages in Zope 2 and Plone.
Starting with Plone 3, the Plone community has also embraced "plain Python" packages and uses them wherever possible. A number of packages, such as plone.memoize and plone.portlets are generic enough to work without any dependencies on the rest of Plone. Others are more specific to Plone and live in the plone.app namespace, such as plone.app.layout and plone.app.portlets, the latter containing Plone-centric extensions to the generic plone.portlets package.
All that is needed to use these packages is a sensible $PYTHONPATH. Thus, we can copy or link packages into $INSTANCE_HOME/lib/python/plone/memoize, lib/python/plone/portlets, lib/python/plone/app/portlets, and so forth for Zope to find them. This works, but it is pretty tedious when there are many packages, and it can become outright confusing when there are nested namespaces being used by multiple packages.
Luckily, other Python programmers have solved these problems, first creating distutils, then its successor setuptools and with setuptools, Python eggs.
[edit] Installing Eggs
When using setuptools, each project or package lives in a directory that has a top-level setup.py file. This contains metadata about the package itself, and declares its current version as well as any dependencies. Dependencies can be specified down to particular versions (e.g. ">=0.2,<1.0" means "later than version 0.2 but before version 1.0"). When a package is installed, setuptools will attempt to fulfill dependencies by downloading and installing them if necessary.
If you have a setuptools-enabled package, you can use setup.py to install it globally, by running:
$ python setup.py install
This will copy the source code to the system-wide Python site-packages directory.
Having to re-run this command each time you make a change can make development a little awkward, so while you are working on a particular package, you can install a development egg. This is essentially a link to the package's source code that ensures it is added to the $PYTHONPATH. To install a development egg, run:
$ python setup.py develop
New packages can be released as binary eggs for distribution, which are just ZIP files of the package with some additional metadata. You can build an egg from within a package by running:
$ python setup.py bdist_egg
The new egg will be placed in the dist sub-directory, which will be created if necessary.
Eggs can be uploaded to the Cheese Shop, also known as PyPI (the Python Package Index). This central repository makes it easy to find packages. You can browse packages at http://cheeseshop.python.org/pypi. New packages can be uploaded via this website, or directly from the command line:
$ python setup.py egg_info -RDb "" sdist bdist_egg register upload
You will be asked to specify or create a Cheese Shop account if this is the first time you run this command.
A script called easy_install lets you search the Cheese Shop (or a similar index, if you specify a URL) for packages that it can download and install into the global Python environment. Dependencies will be included automatically. This is great for simple libraries and end-user applications, but less great when you are working on multiple Zope projects that may have different version requirements. This is why we tend to manage our eggs inside $INSTANCE_HOME or, as you will see in the next section, as part of a controlled buildout.
When eggs are activated (either explicitly, or implicitly by being unambiguously found in the $PYTHONPATH), they can be discovered by other packages listening for plug-ins, using a mechanism called entry points (see http://peak.telecommunity.com/DevCenter/setuptools#dynamic-discovery-of-services-and-plugins). Zope does not yet directly use entry points, so we will not be covering them in any detail here. However, entry points are a very powerful system, and there are proposals to let Zope's discovery of packages use entry points instead of scanning magic directories.
With eggs, we therefore have the tools to manage multiple packages, from different developers and repositories, possibly across multiple versions. By using the package management tools that the rest of the Python community employs, we also make it easier to re-use other libraries and share our own code with outside developers.
[edit] Automating the Build Process with zc.buildout
Creating a Zope instance and copying or linking packages into $INSTANCE_HOME/lib/python as we have seen earlier is not too difficult, but this approach has a few limitations.
- The process is manual and cumbersome to repeat across multiple environments.
- Multiple developers working on the same project may share the code in eggs and products by using a version control system such as Subversion. However, each developer would be responsible for setting up their development environment, and subtle differences may cause problems that are difficult to debug.
- Packages are installed manually, and so cannot benefit from setuptools' ability to manage dependencies and updates.
- Complex deployments that include other libraries, non-python code, or specific configurations will also need to be taken care of manually.
Luckily, there are tools to make deployment easier. zc.buildout is one such tool, written largely by Zope founder Jim Fulton at Zope Corporation. It makes heavy use of eggs and setuptools and is very flexible in supporting a wide range of deployment scenarios.
Central to a buildout (i.e. what zc.buildout is managing for us) is a file called buildout.cfg. This specifies various options, including a list of parts, which will be executed when the buildout is run. Each part is associated with a recipe a named egg, which will be called upon to parse the options provided, and perform a particular task, such as building a Zope instance or downloading Plone.
A project-specific buildout directory can be checked into a version control system and shared among developers. It can also be used to replicate a particular environment across different servers with a high degree of predictability.
By writing custom recipes, you can make zc.buildout do almost anything. Writing a recipe is not particularly hard, and there are plenty of examples and generic solutions available.
[edit] Installing Paste Script and ZopeSkel
To create the buildout.cfg file and some necessary boilerplate, we will make use of Paste Script, a tool for creating project skeletons from templates. Later, we will also use Paste Script to create new packages following standard conventions.
Paste Script is an extensible system with which other packages (or rather, eggs) can register new templates (using entry points). For Zope and Plone development, the ZopeSkel package provides several useful templates.
You can fetch ZopeSkel using easy_install. If you do not have easy_install, you must download it:
$ wget http://peak.telecommunity.com/dist/ez_setup.py $ python ez_setup.py
If you do not have wget (e.g. you are using Windows), download the ez_setup.py script using a web browser instead, and run it with python as shown.
Keep an eye on where the script puts the easy_install executable. Depending on your setup, you may need to add this to your $PATH environment variable or reference it by an absolute directory. Adding the script's directory to your $PATH may be a good idea, though, since the paster command and other egg-installed binaries will go in the same place.
Now, simply run:
$ easy_install ZopeSkel
This will find ZopeSkel in the Cheese Shop, download it, and install it, including its dependencies.
[edit] Creating and Customizing the Buildout
Now we can create our project's buildout, using a Paste Script template from ZopeSkel:
$ paster create -t plone3_buildout optilux
If you run this command, you will be asked a series of questions, including:
- The path to an existing appropriate installation of Zope 2. You can specify an absolute path here if you have installed Zope already and wish to share the same Zope installation across multiple buildouts. Leave the option blank to have buildout download and build Zope for you.
- The path to an existing directory containing all the Plone products. Again, this lets you share the same code across multiple buildouts and save some time. If you leave it blank, Plone will be downloaded for you.
- The Zope root user and password.
- The port that the Zope HTTP server will run on.
- Whether or not debug mode should be on by default. Note that even if it is off, you can enable debug mode by starting Zope with
./bin/instancefginstead of./bin/instancestart. - Whether "verbose security" should be on by default. Verbose security is very useful for debugging security problems by offering more detailed log messages, but it is best turned off for production servers.
Buildout will create a new environment, containing a generated buildout.cfg file and some standard directories. To bootstrap the buildout to get the standard zc.buildout tools, run:
$ cd optilux $ python bootstrap.py
This step is only needed once. We are now ready to build the system. Simply run:
$ ./bin/buildout
This may take a long time, depending on the speed of your computer and internet connection. It will download and build Zope, download and install Plone, and configure the two. When it is finished, you can start Zope by running:
$ ./bin/instance start
Stop it again with:
$ ./bin/instance stop
[edit] The Buildout Configuration File
That is all that is needed to get started. To understand what is going on, though, let us take a look at the buildout.cfg file that was generated for us (slightly abbreviated):
[buildout] parts = plone zope2 productdistros instance zopepy find-links = http://dist.plone.org http://download.zope.org/distribution/ http://effbot.org/downloads eggs = elementtree develop = [plone] recipe = plone.recipe.plone [zope2] recipe = plone.recipe.zope2install url = ${plone:zope2-url} [productdistros] recipe = plone.recipe.distros urls = nested-packages = version-suffix-packages = [instance] recipe = plone.recipe.zope2instance zope2-location = ${zope2:location} user = admin:admin http-address = 8080 debug-mode = on verbose-security = on eggs = ${buildout:eggs} ${plone:eggs} zcml = products = ${buildout:directory}/products ${productdistros:location} ${plone:products} [zopepy] recipe = zc.recipe.egg eggs = ${instance:eggs} interpreter = zopepy extra-paths = ${zope2:location}/lib/python scripts = zopepy
Starting from the top, this file defines various things that will happen when our buildout is run:
- The main
[buildout]section sets buildout-wide options. First, it lists several parts, which will be executed in order. These refer to sections later on in the file. Then, a number of eggs to install can be listed. By default, this includeselementtree, which is required by Plone. Even if you haveelementtreein your system-wide Python installation already, listing it explicitly here will not hurt. The eggs are referenced again in the[instance]section, causing them to be downloaded from the Cheese Shop (or another source, as listed underfind-links) and installed when the instance is built and needs to know about them. The emptydevelopoption will let us manage development eggs later. - The
[plone]section will download Plone's products and eggs. It also exposes the URL to a "known good" version of Zope, which we will reference in the the[zope2]section. To peg Plone to a particular version, you can specify a version for the recipe, e.g. withrecipe=plone.recipe.plone==3.0.1, which would make sure that we got the version of the release recipe corresponding to Plone 3.0.1, if and when it is released. - The
[zope2]section will download and build Zope 2 from the given URL, here supplied by the previously defined[plone]section. This will only be present if you did not specify an existing Zope installation above. It may be worth checking the URL to ensure you get the latest appropriate version of Zope. - The
[productdistros]section can be used to download and install archives of old-style products; it is referenced again under theproductsoption of the[instance]section. We will add a few download URLs later in this tutorial. Thenested-packagesandversion-suffix-packagescan be used to deal with archives that do not immediately extract to usable product directories. See the comments in the file for more information. - The
[instance]section is the most important one. This will create a new Zope instance, and configure it with the appropriate options. The given list of eggs, referring back to the eggs in the main[buildout]section (although additional eggs can be added if necessary), will be activated and made available to Zope. Zope is also told where to look for products. Thezcmlsection can be used to load ZCML slugs special files that Zope 3-style packages can use to make themselves known to Zope. - The
[zopepy]section sets up a custom Python interpreter, which will have available to it all the same eggs as the Zope instance. This is very useful for debugging and quick prototyping.
If for any reason buildout.cfg is changed, or if you wish to obtain recent updates to any eggs listed, you should run ./bin/buildout again. You can often save some time by running buildout in offline and non-updating mode, where it will not check for updates to eggs and products online, by using:
$ ./bin/buildout -No
To get a full explanation of the various options available, run:
$ ./bin/buildout --help
[edit] The Buildout Directory
Let us now take a look at the directories zc.buildout creates for us.
- The
bindirectory contains theinstancecontrol script,zopepy, and thebuildoutcommand itself../bin/instanceis equivalent to$INSTANCE_HOME/bin/zopectl. - The
eggsdirectory contains eggs that buildout has automatically downloaded. These are enumerated and referenced when needed, for example by theinstancecontrol script. This is similar to linking packages into$INSTANCE_HOME/lib/python, but allows us to use the full power of setuptools and eggs. - The
develop-eggsdirectory contains egg-links to any development eggs specified inbuildout.cfg. This will be empty for now. - A
downloadsdirectory will be created as necessary. Recipes such asplone.recipe.ploneandplone.recipe.distrosthat fetch archives of products and packages will place their downloads in this directory. If an archive has already been downloaded, it will not be downloaded again. - The
productsdirectory can be used for any old-style products that are being developed as part of the project. It is analogous to the aforementioned$INSTANCE_HOME/Productsdirectory. Our buildout will also manage various products for us inside thepartsdirectory. - The
srcdirectory contains the sources of any custom eggs. This is empty now.
- The
vardirectory houses theData.fsfile and Zope's logs. - The
partsdirectory is zc.buildout's playground. This is where Zope 2 is downloaded and built, for example the$SOFTWARE_HOMEbecomingparts/zope2/lib/python. The$INSTANCE_HOMEis inparts/instance. You will not typically manage the Zope instance directly when using a buildout. You should not make changes to anything in thepartsdirectory, as zc.buildout may stomp on your modifications when you re-run./bin/buildout.
[edit] Avoiding Duplication between Buildouts
If as a developer you are managing several projects with different buildouts, you may want to share some source code between them. We have already seen the options that allow you to specify shared Zope 2 installations and Plone product directories. This will save considerable disk space, but bear in mind that old-style Zope products are not individually versioned, so any changes or upgrades will affect all instances where they are referenced.
It is also possible to share an eggs directory between different buildouts. Unlike products, eggs carry version information, and so it is possible to keep different versions installed simultaneously. For example, if one egg was referenced in buildout.cfg as my.package==0.9 and another buildout used my.package>=1.0, two versions could be downloaded and activated as appropriate.
The eggs directory to use is controlled by the eggs-directory option in the [buildout] section of buildout.cfg. Rather than having to add this to each project, however, we will put it in the defaults.cfg file, which zc.buildout examines to pick up additional options in addition to what is in the buildout.cfg file.
In your home directory, create a directory called .buildout. Within it, add another directory called eggs, and a file called default.cfg, containing:
[buildout] eggs-directory = /home/username/.buildout/eggs
Similarly, you can specify a shared archive downloads directory, using the download-directory option. For example, you can create a directory called downloads next to the aforementioned eggs directory, and add the following to default.cfg:
[buildout] eggs-directory = /home/username/.buildout/eggs download-directory = /home/username/.buildout/downloads
This file can be used for other defaults if necessary. In particular, if you need to use a specific Python interpreter instead of the default system-wide one, use a line like the following:
executable = /path/to/python2.4
[edit] Additional Development Tools
During development, we typically rely on various tools to help us debug our code and inspect Plone and Zope. The oldest of these is the DocFinderTab, a Zope product that adds a Doc tab to every object in the ZMI. This tab lists the class and base classes for the object being inspected, including methods and their docstrings.
By using a regular expression in the Filter box at the top, you can look for specific methods.
If DocFinderTab is old-school, Clouseau is hip and happening. It is essentially an in-browser Python shell, using JavaScript and AJAX technologies. It supports two modes:
- A general interpreter prompt, which can be accessed from the Clouseau control panel under Site Setup.
- An object inspector, which can be invoked on any content object. It is available from the "document actions" shown at the bottom of most content views.
Note that Clouseau makes use of the DocFinderTab to inspect objects, in order to provide auto-complete suggestions for method and attribute names.
Here is an example of Clouseau inspecting the default Plone front page, changing the title and saving the results:
Please refer to the Clouseau help, under the Clouseau control panel, for more information.
Clouseau is a full, unprotected interpreter shell with access to all of Zope and the currently installed products and packages. A fine demo of Clouseau is to use it to delete your entire Plone instance. Obviously, it should be kept far, far away from production servers, and by default it is only available when Zope runs in debug mode. Being able to prototype things in the browser, inspect the innards of any object in Zope, and make changes on the fly can be incredibly useful, though. Just keep a backup of your Data.fs file.
Both DocFinderTab and Clouseau are distributed as old-style products in separate archives. To obtain and install them, edit buildout.cfg and modify the [productdistros] section like this:
[productdistros] recipe = plone.recipe.distros urls = http://www.zope.org/Members/shh/DocFinderTab/1.0.1/ DocFinderTab-1.0.1.tar.gz http://plone.org/products/clouseau/releases/0.7.1/Clouseau.0.7.1.zip
These URLs are correct at the time of writing. You may want to check for newer versions, especially of Clouseau, at http://plone.org/products/clouseau.
Now, we can re-run buildout and start Zope in debug mode:
$ ./bin/buildout -N $ ./bin/instance fg
We should then be able to install Clouseau from the Plone control panel. DocFinderTab requires no explicit installation.
[edit] Learning to Help Yourself
During development, there will probably be times when you are stumped. Plone is fairly well-documented, but the documentation is certainly not perfect. The mailing lists and chat room are great resources if you need help, but it is also very important to learn how to help yourself.
[edit] Use the Source, Luke!
Python's readability is both a blessing and a curse. A blessing, because it is normally possible to read the source code and find out what is going on. A curse, because this sometimes makes developers a little lax about documentation.
One of the first hurdles new developers should overcome is any undue respect for the Python files that make up Zope and Plone. There is (almost) nothing magical about them. In this tutorial, we have seen where the source code lives: core Zope modules in $SOFTWARE_HOME, third-party products in the products folder, and eggs in lib/python or the eggs folder managed by buildout.
Get used to searching for code in these files using grep or equivalent graphical tools, opening them, and looking for specific classes and methods. Seeing what a piece of code does can often be faster than looking up documentation or examples. As time goes by, you will find that a few packages come up again and again, and finding code will be easier.
You can of course change these files as well. A backup is advisable, but if you think that temporarily raising an exception or printing a message from somewhere deep inside Zope helps you to solve a problem, go right ahead. It is probably a bad idea to make permanent changes this way, however, because those changes will be overwritten if you upgrade or re-install the particular component.
| Plone bugs can be reported at http://dev.plone.org/plone. Zope bugs are collected at http://zope.org/Collectors/Zope, and CMF bugs at http://zope.org/Collectors/CMF. |
Here are some examples of where you may look for source code if you see an import or a description of a module in this tutorial:
| Module
| Location
|
|---|---|
Products.CMFCore.MembershipTool
| A product bundled with Plone. Found in $INSTANCE_HOME/Products/CMFCore/MembershipTool.py for a manual Zope installation, and in parts/plone/CMFCore/MembershipTool.py when using a buildout to download and install the tarball containing this package.
|
plone.memoize
| A simple package bundled with Plone. Could be anywhere on the $PYTHONPATH, but most likely in $INSTANCE_HOME/lib/python/plone/memoize when using a manually created instance, or in eggs/plone.memoize/plone/memoize if installed as an egg via a buildout.
|
AccessControl.ImplPython
| A low-level Zope 2 module, found in $SOFTWARE_HOME/AccessControl/ImplPython.py. Recall that when using a buildout, the $SOFTWARE_HOME is parts/zope2/lib/python.
|
Products.Five.browser
| A product bundled with Zope 2 and therefore found within $SOFTWARE_HOME/Products/Five/browser. These are less common than products in the $INSTANCE_HOME, Five being the most common example of something may want to look at.
|
zope.component.interfaces
| A package that is part of Zope 3 (as evidenced by the top-level zope namespace). This could be anywhere on the $PYTHONPATH, but is most likely in $SOFTWARE_HOME/zope/component/interfaces.py.
|
[edit] Become Familiar with the Debugger
It is also very important to be familiar with pdb, the Python debugger (see http://docs.python.org/lib/module-pdb.html). To insert a breakpoint in your code or in some other code that you are trying to debug add the following line and (re-)start Zope in the foreground in a terminal:
import pdb; pdb.set_trace()
When the line is encountered, execution will stop, and the terminal will display:
(pdb)
This is the interactive pdb prompt. Type help and press Enter to see available commands: the most important ones are pp to print a variable or the result of an expression, n to step to the next line, s to step into a function call, l to show a listing of the source code around the current execution point, and c to stop debugging and continue execution.
If you want to quickly test syntax or libraries, you can run Python's interactive interpreter. To make sure you have all the same eggs and packages available as Zope will when it starts up, run:
$ ./bin/zopepy >>>
[edit] Write Tests for Everything
Finally, the biggest favor you can do yourself as a developer is to learn to write unit tests. To learn more about tests, see http://plone.org/documentation/tutorial/testing. Without unit tests, there is no telling whether your code is working, and whether you have inadvertently broken it. Since tests are normally small and isolated, they are also a great starting point for diagnosing problems or examining the behavior of other components. Try writing a small test and placing a pdb break point in it, stepping into other code as necessary.
[edit] Summary
In this tutorial, we have seen:
- How to create a Zope instance and install Plone into it manually
- The various elements that make up a Zope installation, including the meaning of the
$SOFTWARE_HOMEand$INSTANCE_HOMEenvironment variables - Some background on Python's setuptools and eggs, and how they differ from Zope products
- How to use
pasterand zc.buildout to automate the creation and building of Zope instances in a repeatable manner - Some important debugging tools, including pdb, DocFinderTab, and Clouseau
- A few tips on how you can more effectively help yourself by learning to look at source code, using pdb effectively, and prototyping things with
zopepy
[edit] Additional References
For instructions on customizing themes for Plone, click here
[edit] Source
The source of this content is Chapter 3: The Development Environment of Professional Plone Development by Martin Aspeli (Packt Publishing, 2007).
