Tools and scripts for creating development sandboxes for web applications that primarily use Zope
You can start a new Zope-based web application from scratch with just two commands:
$ easy_install zopeproject $ zopeproject HelloWorld
The second command will ask you for a name and password for an initial administrator user. It will also ask you where to put the Python packages (“eggs”) that it downloads. This way multiple projects created with zopeproject can share the same packages and won’t have to download them each time (see also Sharing eggs among sandboxes below).
(Note: Depending on how they installed Python, Unix/Linux users may have to invoke easy_install with sudo. If that’s not wanted or possible, easy_install can be invoked with normal privileges inside a virtual-python or workingenv).
After asking these questions, zopeproject will download the zc.buildout package that will be used to build the sandbox, unless it is already installed locally. Then it will invoke buildout to download Zope and its dependencies. If you’re doing this for the first time or not sharing packages between different projects, this may take a while.
When zopeproject is done, you will find a typical Python package development environment in the HelloWorld directory: the package itself (helloworld) and a setup.py script. There’s also a bin directory that contains scripts, such as paster which can be used to start the application:
$ cd HelloWorld $ bin/paster serve deploy.ini
You may also use the helloworld-ctl script which works much like the zopectl script from Zope instances:
$ bin/helloworld-ctl foreground
After starting the application, you should now be able to go to http://localhost:8080 and see the default start screen of Zope. You will also be able to log in with the administrator user account that you specified earlier.
Some packages required by Zope contain C extension modules. There may not always be binary Windows distributions available for these packages. In this case, setuptools will try to compile them from source which will likely fail if you don’t have a compiler such as the Microsoft Visual C compiler installed. Alternatively, you can install the free MinGW compiler:
Download MinGW-x.y.z.exe from http://www.mingw.org/ and run it to do a full install into the standard location (ie. C:\MinGW).
Tell Python to use the MinGW compiler by creating C:\Documents and Settings\YOUR USER\pydistutils.cfg with the following contents:
Let Python know about the MinGW installation and the pydistutils.cfg file. To do that, go to the Control Panel, System section, Advanced tab and click on the Environment variables button. Add the C:\MinGW\bin directory to your Path environment variable (individual paths are delimited by semicolons). Also add another environment variable called HOME with the following value:
C:\Documents and Settings\YOUR USER
When installing packages from source, Python should now automatically use the MinGW compiler to build binaries.
You can rename or move the sandbox directory any time you like. Just be sure to run bin/buildout again after doing so. Renaming the sandbox directory won’t change the name of the egg, however. To do that, you’ll have to change the name parameter in setup.py.
After having started up Zope for the first time, you’ll likely want to start developing your web application. Code for your application goes into the helloworld package that was created by zopeproject in the src directory.
For example, to get a simple “Hello world!” message displayed, create src/helloworld/browser.py with the following contents:
from zope.publisher.browser import BrowserPage class HelloPage(BrowserPage): def __call__(self): return "<html><body><h1>Hello World!</h1></body></html>"
Then all you need to do is hook up the page in ZCML. To do that, add the following directive towards the end of src/helloworld/configure.zcml:
<browser:page for="*" name="hello" class=".browser.HelloPage" permission="zope.Public" />
Note that you’ll likely need to define the browser namespace prefix at the top of the file:
<configure xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser" >
After having restarted the application using paster serve, you can visit http://localhost:8080/hello to see the page in action.
The standard setup.py and configure.zcml files list a set of standard dependencies that are typical for most Zope applications. You may obviously remove things from this list, but typically you’ll want to re-use more libraries that others have written. Many, if not most, of additional Zope and third party libraries are listed on the Python Cheeseshop.
Let’s say you wanted to reuse the some.library package in your application. The first step would be to add it to the list of dependencies in setup.py (install_requires). If this package defined any Zope components, you would probably also have to load its ZCML configuration by adding the following line to src/helloworld/configure.zcml:
<include package="some.library" />
After having changed setup.py, you would want the newly added dependency to be downloaded and added to the search path of bin/paster. To do that, simply invoke the buildout:
Automated tests should be placed in Python modules. If they all fit in one module, the module should simply be named tests. If you need many modules, create a tests package and put the modules in there. Each module should start with test (for example, the full dotted name of a test module could be helloworld.tests.test_app).
If you prefer to separate functional tests from unit tests, you can put functional tests in an ftests module or package. Note that this doesn’t matter to the test runner whatsoever, it doesn’t care about the location of a test case.
Each test module should define a test_suite function that constructs the test suites for the test runner, e.g.:
def test_suite(): return unittest.TestSuite([ unittest.makeSuite(ClassicTestCase), DocTestSuite(), DocFileSuite('README.txt', package='helloworld'), ])
To run all tests in your application’s packages, simply invoke the bin/test script:
While unit test typically require no or very little test setup, functional tests normally bootstrap the whole application’s configuration to create a real-life test harness. The configuration file that’s responsible for this test harness is ftesting.zcml. You can add more configuration directives to it if you have components that are specific to functional tests (e.g. mockup components).
To let a particular test run inside this test harness, simply apply the helloworld.testing.FunctionalLayer layer to it:
from helloworld.testing import FunctionalLayer suite.layer = FunctionalLayer
You can also simply use one of the convenience test suites in helloworld.testing:
Use the bin/python script if you’d like test some components from the interpreter prompt and don’t need the component registrations nor access to the ZODB. If you do need those, go on to the next section.
Occasionally, it is useful to be able to interactively debug the state of the application, such as walking the object hierarchy in the ZODB or looking up components manually. This can be done with the interactive debug prompt, which is available under bin/helloworld-debug:
$ bin/helloworld-debug Welcome to the interactive debug prompt. The 'root' variable contains the ZODB root folder. The 'app' variable contains the Debugger, 'app.publish(path)' simulates a request. >>>
You can now get a folder listing of the root folder, for example:
>>> list(root.keys()) [u'folder', u'file']
In case your application fails with an exception, it can be useful to inspect the circumstances with a debugger. This is possible with the z3c.evalexception WSGI middleware. When an exception occurs in your application, stop the process and start it up again, now using the debug.ini configuration file:
$ bin/paster serve debug.ini
When you then repeat the steps that led to the exception, you will see the relevant traceback in your browser, along with the ability to view the corresponding source code and to issue Python commands for inspection.
If you prefer the Python debugger pdb, replace ajax with pdb in the WSGI middleware definition in debug.ini:
[filter-app:main] use = egg:z3c.evalexception#pdb next = zope
Note: Even exceptions such as Unauthorized (which normally leads to a login screen) or NotFound (which normally leads to an HTTP 404 response) will trigger the debugger.
Before deploying a zopeproject-based application, you should make sure that any debugging tools are disabled. In particular, this includes
You can use the helloworld-ctl script to start the server process in daemon mode. It works much like the apachectl tool as known from the Apache HTTPD server or INIT scripts known from Linux:
$ bin/helloworld-ctl start
To stop the server, issue:
$ bin/helloworld-ctl stop
Other commands, such as status and restart are supported as well.
There’s currently no particular support for deployment on Windows other than what paster provides. Integration with Windows services, much like what could be found in older versions of Zope, is planned.
zopeproject maintains a bugtracker and help desk on Launchpad: https://launchpad.net/zopeproject
Questions can also be directed to the zope3-users mailinglist: http://mail.zope.org/mailman/listinfo/zope3-users
zopeproject is written and maintained by Philipp von Weitershausen. It was inspired by the similar grokproject tool from the same author.
James Gardner, Martijn Faassen, Jan-Wijbrand Kolman and others gave valuable feedback on the early prototype presented at EuroPython 2007.
Michael Bernstein gave valuable feedback and made many suggestions for improvements.
zopeproject is distributed under the Zope Public License, v2.1. Copyright (c) by Zope Corporation and Contributors.
Initial release as mkzopeapp