Cooking with Eggs
Every now and then, the computer gods smile and give me a freebie.
I’ve been worrying my mind out over a few problems / obstacles for my Review Board extensions GSoC project. In particular, I’ve been worrying about dealing with extension dependencies, conflicts, and installation.
I racked my brain. I came up with scenarios. I drew lots of big scary diagrams on a wipe board.
And then light dawned.
Batteries Come Included
Enter Setuptools and Python Eggs.
All of those things I was worried about having to build and account for? When using Python Eggs, It’s all built in. Dependencies? Taken care of. Conflicts? Don’t worry about it. Installation? That’s what Setuptools and Python Eggs were built for!
In fact, it even looks like Setuptools was designed with extensible applications in mind.
Wait, really? How?
Here’s the setup.py file for the rb-reports extension in the rb-extensions-pack on Github:
from setuptools import setup, find_packages
PACKAGE="RB-Reports"
VERSION="0.1"
setup(
name=PACKAGE,
version=VERSION,
description="""Reports extension for Review Board""",
author="Christian Hammond",
packages=["rbreports"],
entry_points={
'reviewboard.extensions':
'%s = rbreports.extension:ReportsExtension' % PACKAGE,
},
package_data={
'rbreports': [
'htdocs/css/*.css',
'htdocs/js/*.js',
'templates/rbreports/*.html',
'templates/rbreports/*.txt',
],
}
)
Pay particular attention to the “entry_points” parameter. What this is doing, is registering rbreports.extension:ReportsExtension to the entry point “reviewboard.extensions”.
“Hold up!”, I hear you asking. “What’s an entry point?”
Entry Points
An entry point is a unique identifier associated with an application that can accept extensions.
The unique identifier for Review Board extensions is “reviewboard.extensions”.
This is the first handshake, more or less, between Review Board and any extensions: in order for Review Board to “see” the extension, the extension must register an entry point at “reviewboard.extensions”.
This blog post shows how extensions can be found and loaded up.
Other Goodies
INSTALLED_APPS and Django
I remember also being worried about how to create tables in Django for extension models. I thought “holy smokes, I’m going to have to either shoehorn some raw SQL into the extension manager, or maybe even trust the extension developers to write the CREATE TABLE queries themselves!”.
Luckily, there’s a better alternative.
Django knows about its applications through a dictionary called INSTALLED_APPS. When you add a new model to a Django project, you simply add the model app to the INSTALLED_APPS dictionary, and run “manage.py syncdb”. Django does the magic, bingo-bango, and boom – tables created.
So if a new extension has some tables it needs created, I simply insert the app name of the extension into INSTALLED_APPS when the extension is installed, and call syncdb programmatically. Tables created: no sweat.
django-evolution
Creating tables is easy. But what if an extension gets updated, and the table needs to be modified? Sounds like we’ve got a mess on our hands.
And don’t expect Django to save you. When you modify a model in Django, they expect you to into that DB and alter that table by hand:
[syncdb] creates the tables if they don’t yet exist. Note that syncdb does not sync changes in models or deletions of models; if you make a change to a model or delete a model, and you want to update the database, syncdb will not handle that.
From The Django Book – Chapter 5: Models
Thankfully, there’s a mechanism that’s already built into Review Board that makes this trouble go away: django-evolution. Django-evolution, when used properly, will automatically detect changes in application models, and alter the database tables accordingly. This is how Review Board does upgrades.
And to top that off, RB co-founder Christian Hammond just became the django-evolution maintainer.
Wow. Everything is falling neatly into place.