How to automatically install and maintain your Grok application in to the ZODB

Use the zope.generations infrastructure to automatically install and upgrade your application data when Grok starts.

Purpose

When I develop my Grok applications I need for my app to be already availabe after first Grok startup and I also need a decent way of safely upgrade application’s data after the deployment of any new release of application’s sources. This is a tiny how to that explains howto use the zope.generations infrastructure in order to do so.

Prerequisities

To demonstrate the usage of zope.generations we will create a grokproject called example. We need the zope.generations package available in our example grokproject. We can archive this by adding the package zope.generations to our setup.py install_requires:

install_requires=['setuptools',
                  ...
                  # Add extra requirements here
                  'zope.generations',
                  ],

Step by step

For installing an app without the grok-admin-interface we have to define a package e.g. example.generations. This package will contain a utility which manages the update and installation process, and little scripts which does the work.

Let’s take a look in the generations package:

├── generations
│   ├── __init__.py
│   ├── evolve1.py
│   ├── install.py
│   └── util.py

Ok let’s create the Manager which holds all information in the util.py

import grok
from zope.generations.generations import SchemaManager
from zope.generations.interfaces import ISchemaManager


schemaManager = SchemaManager(
    minimum_generation=0,
    generation=0,
    package_name='example.generations'
)


grok.global_utility(
    schemaManager,
    provides=ISchemaManager,
    name="example",
    direct=True
)

This means we register an instance of SchemaManager as global utility. This utility is picked up on startup. As it is the first run, the utility will look for a module called install.py:

from example.app import Example
from zope.generations.utility import getRootFolder

def evolve(context):
    root = getRootFolder(context)
    root['app'] = Example()
    print "CREATED App"

I think it’s not difficult to understand what goes on here. This script is found and executed by the SchemaManager on startup. It get’s the root folder and creates an instance of our Example Application it it. Internally the SchemaManager saves that the script was executes, so it get’s executed one times.

Step 2 how can we update some attributes on startup: We have to tell the SchemaManager that he should look for new scripts on startup. So let’s modify the our SchemaManager in the util.py package

schemaManager = SchemaManager(
    minimum_generation=1,
    generation=1,
    package_name='example.generations'
)

As you can see we increase the ‘generation’, ‘minimum_generation’ attribute to 1. This means that on startup the SchemaManager will look for a module called ‘evolve1.py’.

This is our sample evolve1.py:

from zope.generations.utility import getRootFolder

def evolve(context):
    root = getRootFolder(context)
    app = root['app']
    app.title = u"Hello World"

We simply get our Example Application from the root folder, and add an attribute title with the value “Hello World” to it.

Further information

You can have a look in the tests of zope.generations.