plutonian python

3 years after


This project aims to bring some of the fun and ease of the Pyramid development style into Plone.

At its current stage it only has some helpers to simplify GenericSetup handling, especially around upgrade steps.


The code and issue tracker can be found at


This project assumes you are writing a specific application based on top of Plone. You have one policy package that manages the specifics of one site.

This library wasn't intended for writing reusable add-ons for Plone, but what's here should work for such a use-case.


Preliminary notes on using the GenericSetup helpers:

In your policy package's (for example named policy) in the initialize function::

def initialize(context):
    from policy import config

For the initialize function to be picked up, you need a configure.zcml::


  <five:registerPackage package="." initialize=".initialize"/>


The module::

from plutonian import Configurator

config = Configurator('policy')

Create a

from import loadMigrationProfile
from import import_step
from import upgrade_to
from Products.CMFCore.utils import getToolByName

from policy.config import config

def set_profile_version(site):
    # while creating a new site, assign the last version number and thus
    # treat it as not needing any of the existing upgrade steps
    setup = getToolByName(site, 'portal_setup')
        config.policy_profile, config.last_upgrade_to())

def various(context):
    if context.readDataFile('policy-various.txt') is None:
    site = context.getSite()

def do_something(context):
    # apply some existing GS files again from the policy profile if they
    # have changed or do anything else you might need to do
    loadMigrationProfile(context, 'profile-policy:default',
        steps=('cssregistry', 'jsregistry', '', ))

And finally create a GS profile with a folder structure of profiles/default and put a metadata.xml file in there::

<?xml version="1.0"?>
  <!-- The version is determined based on the registered upgrade steps
       and must not be set here -->
  <!-- <version>unknown</version> -->

You also need to create the empty flag file named policy-various.txt.

The upgrade_to decorator takes integers. No number can be taken multiple times, but there can be numbers missing in the sequence.

The upgrade steps are registered in the normal place and can be run via the portal_setup ZMI screens. As an alternative you can create a zopectl command to run them from the command line. In your add an entry::

upgrade = policy.commands:upgrade

And create a with the function::

import logging
import sys

import transaction
from AccessControl.SecurityManagement import newSecurityManager
from import setHooks
from import setSite

logger = logging.getLogger()

def _setup(app, site=None):
    """Set up our environment. Create a request, log in as admin and set
    the traversal hooks on the site.
    # Do not import this at the module level, or you get a demo storage
    # ZODB instead of the real one!
    from Testing import makerequest
    app = makerequest.makerequest(app)

    # Login as admin
    admin = app.acl_users.getUserById('admin')
    if admin is None:
        logger.error("No user called `admin` found in the database.")

    # Wrap the admin in the right context
    if site is not None:
        admin = admin.__of__(site.acl_users)
        site = app[site.getId()]
        admin = admin.__of__(app.acl_users)
    newSecurityManager(None, admin)

    # Set up local site manager, skins and language
    if site is not None:
        site.REQUEST['HTTP_ACCEPT_LANGUAGE'] = site.Language()

    return (app, site)

def upgrade(app, args):
    # Display all messages on stderr

    existing = app.objectValues('Plone Site')
    site = existing and existing[0] or None
    if site is None:
        logger.error("No Plone site found in the database.")

    _, site = _setup(app, site)

    from policy.config import config"Starting the upgrade.\n\n")
    setup = site.portal_setup
    config.run_all_upgrades(setup)"Ran upgrade steps.")

    # Recook resources, as some CSS/JS files might have changed.
    site.portal_javascripts.cookResources()"Resources recooked.")

    transaction.get().note('Upgraded profiles and recooked resources.')

You can then call this script via::

bin/instance upgrade

It will currently recook the CSS/JS resources on each run, but otherwise has no ill side-effects, so you can run it as many times as you want.

Top Contributors



-   0.1a3 zip tar
-   0.1a2 zip tar
-   0.1a1 zip tar