Tuesday, December 11, 2007

Rest in Peace, Twist

Well, today was a sad day. After months of care and rehabilitation, my big, strong, proud alpha horse had to be put down.

He was an older horse, and after the abuse he suffered before we got him and a couple bad falls, he started losing full control over his hind legs. For the past few weeks, we kept him warm and well-fed in a stall, with Marjorie caring for him like a brother. There was amazing improvement, but when we took him for a walk a couple days ago, our hopes were crushed. He had to go right back in the stall, for fear of hurting himself and others (by falling on them).

We are concerned about his best friend, Timer; Timer's whole life has been spent with Twist -- they've never been apart. Hopefully, between Marjorie's pony Kelly, our friend Nola, Marjorie and me, we'll be able to provide a nice transition for Timer.

Great and Strong Twist: run with the spirits my friend. Race the bardo winds unencumbered and taste freedom like never before.

Technorati Tags:

Friday, November 09, 2007

Twisted AJAX/COMET Tutorial Pre-release

As promised earlier, here is the new Athena tutorial!

Currently, the tutorial consists of a topical introduction and two example applications, built with the reader step-by-step. Note that this is still in branch and hasn't been reviewed for inclusion in trunk. Please feel free to leave comments to this blog post about the tutorial (good, bad and ugly). This will help us improve the content and prepare it for inclusion in trunk.

The tutorial includes detailed instructions on setting up an environment, obtaining the source code, and running the applications. There are also pointers on how to conceptually approach development with Nevow/Athena.

Due to concerns over code compactness, we pulled out the CSS that nicely styled the echo and chat tutorial apps. The curious can view the styled versions here:

And if you want to pretify your example apps, you can update the fragment templates per the links given below.

Thursday, November 01, 2007


Yeah, so I'm late to the game.

In fact, twitter's not really a game I was ever interested in. I only started using it today because of the work we're doing at Divmod. The reason I was never enthusiastic was I just couldn't see myself using yet another application or having yet another web page open all the time.

But it hit me this morning at 3:00am when I couldn't sleep that with tying a single script's name at the command line, I could push whatever command I had just issued to my twitter. That script uses bash's history command as well as python-twitter. I wrote another simple script that I can use to push arbitrary text too. That coupled with the fact that 1) twitter supports an IM service and 2) I'm now using BitlBee, I can now use twitter without context switching (since I spend 80-90% of my computer time in the terminal and my IRC client).

I'll probably be using twitter mostly as an open-ended replacement for setting IM/IRC status. Interesting commits or revealing bash activity will make their way, too. And, of course, I will be using it for the as yet unannounced Divmod app we will be releasing :-)

Technorati Tags: , , , ,

Monday, October 29, 2007

trac Stats Gathering with Storm

One of the things we've wanted to do recently at Divmod is track development status of milestones as well as gain some perspective on repository history/trends in activity. The first thing I did? Looked at SQL for about 2 and a half minutes. The second thing I did? Fired up a python instance and imported storm.locals :-)

With a few minutes of typing and looking stuff up (e.g., how to define compound keys for an already extant schema/db), I was up and running and was able to concentrate fully on the problem at hand (reports) and how to represent data visually (matplotlib). Now that's how an ORM is supposed to work :-)

Here are the schemas I defined in python:

Note the 1-to-m relationship of revision to nodes changed -- so easy :-)

This is exactly what a (good) tool is supposed to let you do: focus on and solve the larger problem at hand, not get lost fixing tools. With the schemas defined, the queries took literal seconds to write, I had my data, and was able to start generating textual summaries as well as processing the queries for graphs.

Wanna see some graphs? Below is a slide show of some graphs (just a few of the hundreds that are generated) representing the work of the Divmod dev team over various points in time on a secondary trac instance (not our main, Divmod trac instance). Though I haven't included them in the slide show, the code also generates graphs per-user, per-time-period.

Created with Admarket's flickrSLiDR.

Update: Thanks Nafai for poking me about the oversight of not giving shouts out for the graphing tool: matplotlib (of which I have been a huge fan of since I first heard about it years ago, having suffered through proprietary and kludgey Matlab as a physics student).

Technorati Tags: , , , , ,

Wednesday, October 17, 2007


I've been meaning to blog about this for a couple weeks: rst2a. I think this is a hot little site for the following reasons, in order of what my brain experiences when visiting the site:
  • Visually, this is a very "clean" (and good looking) application; in a world of over-featured web junk, this is most refreshing.
  • Similarly, the functionality of the application is represented excellently by the clear design and layout: I always know where to go and what button to click.
  • I use ReStructured Text all the time; any notes I take for everything, I write using rst (and I have already used rst2a a great deal).
  • This applications is most useful: it can output my rst text to styled HTML or PDFs, it handles unicode well, and new styles can be defined and uploaded.
Finding a nice web application that does one thing useful and doesn't try to be everything to everyone, looks good, and actually freakin' works feels like a one in a million occurrence. Having a web tool that converts your rst may not seem very "big" or sexy, but try it -- I think you'll find it surprisingly useful. And the way that they have designed this thing, you will enjoy the actual usage experience in addition to the result (or at the very least, won't have the pain associated with poorly- or over-designed apps).

Now, to encourage them to commit a crime which I have just decried, perhaps they could a feature I would use: slide show output. This would increase the output formats from two to three: HTML, HTML Slideshow, and PDF. That's not too bad, is it?

Technorati Tags: , ,

Tuesday, October 09, 2007

Twisted Horse

I've loved riding horses since I was a kid. I have no riding skillz, but I've been on horses (irregularly, and sometimes with large gaps of time in between) since I was a little boy. But *damn* it's amazing riding a horse.

So imagine my joy when
  1. my girlfriend tells me she wants to rescue two trail horses she's known for a couple years and is able to get a really good deal on;
  2. they are larger horses (quarter horses), so they will fit me; and
  3. the larger of the two is named "Twist".
Well, they arrived today, brought up from Colorado by our friend Lindsey. They were treated poorly by someone (riders and/or handlers) this summer, and so are in pretty rough shape, but Marjorie has already started working on them and is putting their recovery plan into effect immediately. As soon as they get fattened and happied back up, I'll be learning to ride bareback! Woo-hoo! Or perhaps "yee-haw," in the parlance of our locale.

I've got some initial pics up here, taken after we got them off the trailer and into the arena. Twist is the lighter colored, larger horse. I can tell you what I'll be doing on weekends, now! When I'm not traveling to Denver. Or hacking python. Or...

But, man! I can't believe that I've got a horse named Twist, of all things! How sweet is that synchronicity?

Technorati Tags: ,


I was in Chicago very briefly this weekend for the Chicago Marathon; several of my friends from the 311th MI Bn (101st Airborne Division) were running in the event and others of us from the same unit were there supporting them. For us, the whole event was dedicated to our dear friend Todd Drobnick who was killed in Iraq several years ago. It was really great seeing some old friends, savoring some memories, making some new ones and even planning the next get-together. I put some pics up here.

For the weekend, we ended up renting this great little place (two places in fact: 2nd and 3rd stories) that was right on Clark Ave. at mile marker 9: a perfect location. I also ended up bringing my dog with me, and as a result, did lots of walking in and around the area.

I am not a city person; I generally am fairly averse to them. Cities with character, however, I find most appealing. Boston, San Francisco and New Orleans come at the top of that list. But I tell ya, I gotta admit that Chicago rocketed through the ranks this last weekend. I've been there before, but only downtown. Staying for a day and a half in Chicago's Mid-North District made me want to come back right away! Here are some pics I took (with my cell phone; not the best light control) of some of the places that caught my eye.

Sadly, PyCon 2008 won't be held in Mid-North. However, 1) I look forward to exploring the area near the conference, and 2) Mid-North is only going to be about 13 miles from the hotel, so I can always talk some of you into catching the 'L' with me and riding over for dinner and a walk :-)

Technorati Tags: ,

Wednesday, September 19, 2007

Code Monkey

Why isn't this our theme song? I can't believe I haven't heard of Jonathan Coulton until now (and it was a non-coder who shared it with me). Turns out this guy wrote a song a week for a year. Totally insane. And brilliant.

More for the geeks:
He reminds me of Jeffery Gains and They Might Ge Giants. I will probably end up buying all this guy's albums...

Technorati Tags: , , ,

Saturday, September 15, 2007

The Schro is Back

Well, after year and a half of no posts, Schrödinger's Böx is back, with three new entries:


The reason for the long gap is that feedster.com had stopped publishing their top 500 list. The list was pretty convenient, since they provided RSS links of each blog's full recent entries. Parsing them was cake. When that went away, so did posts for SchroBox.

I had a few minutes this morning to play, so I hacked on the really awful code to add support for parsing Technorati's top 100. This should make Greg very happy, as he has oft lamented the early and sad demise of The Box.

As for what this madness is and where it comes from, this post tells all (hint: it uses NLTK extensively).

Thursday, September 13, 2007

Nevow Athena: AJAX/COMET with Twisted

Some of you may remember when, given 5 seconds to say something about Nevow's AJAX capabilities at the PyCon Web Framework panel, I said "we were there first." I was serious about that. If you take the time to dig through the dusty attics of Twisted's and Divmod's svn repositories, you'll see it too.

Not that I blame anyone for not knowing, though. If there are any two crimes that Twisted devs are guilty of (among potentially uncountably many) they would be:
  1. being frighteningly clever, and
  2. not sharing the useful bits of the cleverness with the world at large.
We're trying hard to really start sharing the goodness, though, honest!

Along these lines, we've got a series of tutorials about Athena that will be published "real soon, now." Initially, we're going to put out some intro text and two basic tutorials. Follow-on tutorials will cover advanced topics and/or basic ones in more detail.

It will be very exciting, though, to bring the power and elegance of Athena to the masses :-)

Personally, I've found that writing Athena apps (with its tightly bound Python and JS) provides ease of use and peace of deterministic structure in an arena (AJAX/COMET application development) that is usually littered with the bodies and casualties of poor planning, poorly established boundaries between application components (in requirements, architecture, and implementation), and poor education.

I look forward to community feedback on the tutorials: it's a complicated topic that will be condensed into only a little code in each fully functional example. The need for clarity and the defeat of confusion is paramount.

Technorati Tags: , , , , , ,

Tuesday, September 04, 2007

Merging New trunk Features to a Development Branch

When I was on the development team for Zenoss, I tried to get them to use branch-based development, including Divmod Combinator. They eventually did switch to using branches for any big changes, but they didn't embrace Combinator. When I'd taken over development of the Zenoss community code, there were only two developers, so I only implemented a very basic branch management process. But having used Combinator a lot recently, I wish that I'd taken that opportunity to get them using Combinator... man, their lives would be so much easier right now if I'd taken that step.

I am now managing all of my svn-based projects with Combinator. Even the ones were I am sole developer. The time saved and convenience gained is enormous.

Below is a perfectly good example of how Combinator makes svn management less painful. I don't know about you, but every time I have to manually to push new trunk changes into my current development branch, my brain does a little freak-out dance. I stress, thinking "Crap; I have to get this right. What are the exact commands I have to use again?" Thanks to Combinator, this is no longer a problem, and my brain does a happy dance instead.

These days, I am using Combinator on an almost hourly basis. It's very simple (to get setup with Combinator, see the tutorial and other example usage).


Assuming you've got a Combinator-managed project called "Project", let's do some background first. Say you want to branch trunk for a new feature, one that you're tracking in ticket #836. Here's how:
$ mkbranch Project viking-feature-836
Now, just to make sure that you are no longer in trunk, check which branch you are in:
$ whbranch
Project: viking-feature-836
Divmod: trunk
Twisted: trunk
(Note that every project that you are managing with Combinator will be listed.)

Say you've got another ticket you're working on, #1066. You created the branch with this command, just like the other branch:
$ mkbranch Project norman-feature-1066
After starting this branch, you complete 836 and merge to trunk:
$ chbranch Project viking-feature-836
$ unbranch Project
$ svn commit -m "Completed 836."
unbranch updates trunk with the latest changes and then merges the branch it just came from (viking-feature-836) into trunk. Running svn diff will show you just how true this is.


So much for the background! Now for the merging I'd promised:

If the norman feature depends on the viking feature, we need to "merge" trunk to branch. Using Divmod Combinator, this is how that is accomplished:
$ chbranch Project norman-feature-1066
$ unbranch Project
$ mkbranch Project norman-feature-1066-2
$ cd ~/Project/branches/norman-feature-1066-2
$ svn commit -m "Merged changes from norman-feature-1066."
In other words, we:
  1. merge our work to date from norman-feature-1066 to trunk (without committing!)
  2. make a new branch, based on that trunk, which includes the norman feature to-date and all the latest changes made to trunk
  3. commit the branch changes to our new branch
We're using trunk to get what we need by only making changes to trunk in the working directory, without making any changes in the repository. Keep in mind that the changes from the first branch were added (and not committed) to trunk before creating the second branch. Since the second branch was created from this modified trunk, we will need to commit those additions. Also, you will most definitely want to revert your tweaked trunk once you have finished creating your new, updated branch!


As a side note, Combinator is especially excellent for python projects, because of its python path management features. Any python tools, scripts, pluggins, or applications that use the code in your Combinator-managed projects will import from the current, active code (whatever shows up in whbranch). So when you're working in branch and you run your unit tests, you know that it's the branch code that's getting tested. When you switch back to trunk, all your code is running against trunk. Very nice :-)

Technorati Tags: , , , ,

Wednesday, August 29, 2007

Hello, Divmod

As I've mentioned before, the first time I had face-to-face time with Glyph and Amir was not too long after they'd formed Divmod, at pycon 2004. I'd toyed with Twisted for about two years prior to that, and the stuff they were doing with Quotient was just amazing (better feature sets than gmail). So, when they reached out after I'd blogged about my Zenoss contract coming to an end, I was just thrilled. We had some exciting talks about current development and the future, and given my long-standing love of Twisted and Divmod products (such as Nevow), wild horses couldn't have dragged me away.

I consider the core Twisted developers (and Divmod programmers) to be some of the best in the world. To be working with these guys is a dream come true and I am giddy with anticipation of both what we will be producing and all that I will be learning.

And now, I would like to take a moment to give some love to the python community in general: you guys are awesome.

I know you already know this, but one can never say it enough :-) I had all sorts of people and companies offer really cool positions when they heard I was available. There are some exciting startups that need developers and fantastic non-profits (that pay salaries) that would be great fun to work for (and feel good about). Also, my favorite dev team at my favorite Linux distribution's parent company reached out; they totally rock and I want to thank them for that (you know who you are!).

Two things I learned: VMware uses python and even better, LucasFilm uses Twisted. How totally cool is that? Hopefully we'll be talking to them on the TwistedShow sometime in the near future...

Technorati Tags: , ,

Friday, August 24, 2007

Skater Heaven

So I completely flipped out this morning before breakfast: I looked out the bedroom window after a morning conference call, and there are skaters slaloming down the road behind the house. I've got a 3' Sector9 bamboo longboard and love to get me some slalom action. But I suck. These guys were awesome.

I grabbed Sengey (my girlfriend's Tibetan mastif) and took him out for a walk up the hill. The skaters were amazingly friendly and totally mellow; they jumped at a chance to tell someone about their event. Turns out today is day one of the Seismic Nationals which is being held in my back yard!

I took my phone with me and snapped some shots of the skaters, and they are here in this flickr set. Enjoy!

We've been renting this house month-to-month while waiting to move into the house in Valentine, NE. It's a McMansion and not cozy at all, so this skating event has made the past two months here totally worth while.

Update: a sweet video of the same event last year.

Technorati Tags: ,

One Number to Rule Them All and in the Phone Book Bind Them

Thanks to Grand Central, I've got a new perma-number. This service completely rocks. I've already got my current temporary house number connected to it, and when I move in a week, I'll be updating it with that number.

Here are the features I love:
  • being able to chose you number
  • no more hated phone voice mail -- I can check all voice mail on line
  • I get an email for every new voicemail
  • I can share voice mails with friends with a link
Yeah, I have voice mail issues...

I believe registration is open now, but ping me if you need an invite. Don't for get to use this once you've got your new number.

Monday, August 20, 2007

Ubuntu 7.04 on iMac Core 2 Duo, 2G

Well, I busted me arse this afternoon and evening trying to get Ubuntu set up on my new iMac. It installed without issue (using the "alternate" x386 iso), but has the following critical issues:
  1. No wireless
  2. No widescreen support
  3. No sound
  4. Doesn't recognize CD/DVD drive after install and reboot
I'm kind of bummed, since I'd planned on doing dev work on this box (can we even call the iMacs "boxes"?) in native Ubuntu, and now I'll have to use parallels until the driver support is developed. Or until someone sends me a link that I've managed to miss despite incessant googling today...

Once I'm moved into the new place, I'll have a GB switch in the office and will be able to work in Ubuntu over copper. The resolution bugs me more than the lack of sound and DVD, but I can live with those for now. I guess.

But, hey -- it plays WoW and UT2004 in OS X like a champ :-)

Technorati Tags: , , ,

Saturday, August 18, 2007

publish-bot with logging capability

Last year sometime, I received several emails from people wanting me to release the supybot IRC plugins I wrote back in 2005 for svn and RSS updates. I'd actually written for several different IRC bots (both twisted-based, and non-twisted bots) but the code was particularly messy for supybot. During one conversation, I said that I'd really done it all wrong, and the last thing I wanted to do was clean up wrong code. If I got a chance, I would do it right:
  • create an IRC client for communicating to servers+channels
  • create a message server running on local host
  • process/parse data from the local server to the IRC client (i.e., appropriate IRC channel)
Such a flexible design would suit every need I have for writing data to an IRC channel.

Turns out radix did just so earlier this year for Canonical, as he relates in this blog post. This is exactly what I needed this weekend while migrating my old IRC bot to a new server. Well, almost all I needed. There were a couple features I wanted to add...

Not having worked with bzr or launchpad much, I asked radix about branching his code, since I heard that Canonical actually provides developers a way of doing that without leaving the launchpad environment of trunk. His instructions were quite simple, and I summarize them here for the benefit of others:
  • find the project you want to branch on launchpad
  • checkout trunk (if that's what you're branching)
  • commit (a local action) with a message about this being a new branch
  • make your changes (with any number of commits)
  • push all your commits to your branch on launchpad
The steps above assume that you have bzr installed and have uploaded your SSH keys to launchpad.

Here are the bzr commands that I used:
bzr branch http://bazaar.launchpad.net/~radix/publish-bot/trunk publish-logger-bot
cd publish-logger-bot
bzr commit --unchanged -m "Created branch of radix's publish-bot."
bzr push sftp://oubiwann@bazaar.launchpad.net/~oubiwann/publish-bot/publish-logger-bot
The changes I committed:
  • enabled logging
  • added log-rotation
  • added an HTTP service for browsing the log files
The code is available here:

Forthcoming features:
  • a search form for the log files
  • a parser for bot commands, thus enabling human -> bot communications (will probably dust off my old pyparsing code for this)
  • arbitrary time log rotation (currently it's by day, ad midnight)

And for dessert:
[18-Aug-2007 17:56:50] [connected at Sat Aug 18 17:56:50 2007]
[18-Aug-2007 17:57:00] [wallflower (logger bot) has joined #supersecretchannel]
[18-Aug-2007 18:00:38] <keturn> what's a wallflower?
[18-Aug-2007 18:20:09] <PenguinOfDoom> It's a flower that grows out of a wall
[18-Aug-2007 18:20:52] <keturn> and has an irc client?
[18-Aug-2007 18:22:49] <keturn> is it related to an oubiwann?
[18-Aug-2007 18:34:00] <exarkun> I reckon it is

Technorati Tags: , , , , , ,

Tuesday, July 31, 2007

Export iTunes Playlists as .m3u Files

I got really pissed at iTunes today: it crashed and then wouldn't start back up, throwing the infamous 'locked file' error. In exasperation, I tried Songbird. It looks promising, but still needs lots of work and didn't play my music-over-Samba very well. I then got the latest Cog release.

In my experience, Cog is simple, straight-forward, performs no voodoo and just works (Troll: "Stay away from the voodoo!"). I really like the fact that I can browse the file system in Cog, and drag the albums into the list pane, but I didn't want to start years worth of playlists all over again...

At which point I remembered that a couple of years ago I blogged about parsing iTunes playlists with ElemetTree. It looks like the effbot archives no longer point to the link I updated that post with, but google cache served me well and I found Fredrik Lundh's code, repasted here:

from cElementTree import iterparse
except ImportError:
from elementtree.ElementTree import iterparse
import base64, datetime, re

unmarshallers = {

# collections
"array": lambda x: [v.text for v in x],
"dict": lambda x:
dict((x[i].text, x[i+1].text) for i in range(0, len(x), 2)),
"key": lambda x: x.text or "",

# simple types
"string": lambda x: x.text or "",
"data": lambda x: base64.decodestring(x.text or ""),
"date": lambda x:
datetime.datetime(*map(int, re.findall("\d+", x.text))),
"true": lambda x: True,
"false": lambda x: False,
"real": lambda x: float(x.text),
"integer": lambda x: int(x.text),


def load(file):
parser = iterparse(file)
for action, elem in parser:
unmarshal = unmarshallers.get(elem.tag)
if unmarshal:
data = unmarshal(elem)
elem.text = data
elif elem.tag != "plist":
raise IOError("unknown plist type: %r" % elem.tag)
return data

Which was a great start, but I needed .m3u output. After reading how simple the format was, I was off and running. The end result was all of my iTunes playlists playable by Cog, which I am using now -- as I type -- to enjoy my music, free of pain. One thing worth exploring would be how to preserve the ordering of iTunes' playlist items.

Here's the code I used to "export" the iTunes playlists as .m3u:

import re

m3uList = "#EXTM3U\n%s\n"
m3uEntry = "#EXTINF:%(length)s,"
m3uEntry += "%(artist)s - %(album)s - %(song)s\n%(filename)s\n"

def phraseUnicode2ASCII(message):
Works around the built-in function str(message) which aborts when non-ASCII
unicode characters are given to it.

Modified from http://mail.python.org/pipermail/python-list/2002-June/150077.html
newMsg = message.encode('ascii')
except (UnicodeDecodeError, UnicodeEncodeError):
for uc in message:
char = uc.encode('ascii')
except (UnicodeDecodeError, UnicodeEncodeError):
newMsg = ''.join(chars)
return newMsg.strip()

class Playlists(object):

def __init__(self, filename=None, destDir=None):
self.lib = None
if filename:
self.lib = load(filename)
if not destDir:
destDir = './'
self.destDir = destDir

def processTrack(self, trackData):
length = trackData.get('Total Time') or 300000
song = trackData.get('Name') or 'Unknown'
artist = trackData.get('Artist') or 'Unknown'
album = trackData.get('Album') or 'Unknown'
data = {
'filename': trackData['Location'],
'length': int(length) / 1000 + 1,
'song': phraseUnicode2ASCII(song),
'artist': phraseUnicode2ASCII(artist),
'album': phraseUnicode2ASCII(album),
return m3uEntry % data

def processTrackIDs(self, ids):
output = ''
for id in ids:
trackData = self.lib['Tracks'][str(id)]
output += self.processTrack(trackData)
except KeyError:
print "Could not find track %i; skipping ..." % id
return output

def cleanName(self, unclean):
clean = re.sub('[^\w]', '_', unclean)
clean = re.sub('_{1,}', '_', clean)
return clean

def exportPlaylists(self):
for playlist in self.lib['Playlists']:
playlistName = self.cleanName(playlist['Name'])
items = playlist['Playlist Items']
except KeyError:
print "Playlist seems to be empty; skipping ..."
trackIDs = [x['Track ID'] for x in items]
data = m3uList % self.processTrackIDs(trackIDs)
fh = open("%s/%s.m3u" % (self.destDir, playlistName), 'w+')

def exportPlaylists(filename, dest=None):
pls = Playlists(filename, dest)

With usage like the following:

>>> from iTunesExport import exportPlaylists
>>> BASE = "/Volumes/itunes/__Playlists__"
>>> exportPlaylists('%s/Library.xml' % BASE, BASE)

Update: I've tweaked the code in this post a little bit, due to a reader's questions. To run this, copy both code blocks into a single file you should be good to go.

Saturday, July 28, 2007

OpenOffice, Python and Plone... and Java

The last big project I'm working on for Zenoss is an OpenOffice-to-Plone publisher. Specifically, for the Zenoss Guide (combined admin and user manuals). The Guide is maintained in OpenOffice format, but in addition to .sxw/.doc and .pdf formats, they want to publish as HTML, where each section of the doc gets its own page in the Zenoss Community portal and users have the ability to comment on each section.
There are several things I'm using to implement this:

  • Zope/Plone and Five
  • OOoPy (for processing sections and creating .sxw files)
  • lxml.etree (for preserving the original XML namespace names)
  • writer2LaTeX (for converting generated .sxw files to HTML)
Sadly, I spent a great deal of time trying to figure out why w2l (writer2LaTeX) wasn't converting sections with images; I won't relay the horrors of debugging. Finally, I tossed in the towel and emailed the author, Henrik Just. He was phenomenally helpful... and he uncovered the underlying issue, one that I consider to be a dirty little secret (though perhaps those familiar with the combinations of Zip files, python and Java consider an openly acknowledged issue). From Henrik:
A little debugging showed that the java's zip classes causes the problem. Unfortunately they are not very tolerant with variations of the structure of zip files. With java 1.4, I cannot open the file at all. This, it turns out, is due to a bug that was fixed in java 1.4.2. But even with java 1.5 I can only read 5 of the 12 files in the zip file, which causes the odd behaviour you have seen.
I don't know who to blame here: Python or Java. Regardless, doesn't this seem absurd? That the standard compression format used to create .zip files is not implemented completely either in Python, Java or both? Though not completely surprised, I was surely flabbergasted. Despite my frustration, Henrik was helpful in offering some alternatives, as well as using w2l with an option for splitting a doc by headings.

Yet another example of the phenomenal goodness that is the community of open source developers (if not the languages used in that community...). Thanks Henrik!

Technorati Tags: , , , , , ,

Twisted JSON-RPC on Google Code/Projects

I've been getting lots of emails from folks asking for the Twisted JSON-RPC code that I had put up a while ago. They weren't able to find it due to my having to bring down the trac instances I was running. Good news: I've moved the repository up to Google:
The front page has a link to the wiki which in turn has all the usage info. You can get recent eggs here:
If you want to contribute to this code base and bring it up to date, email me.


Update: Primary development has moved to Launchpad. Documentation is maintained on the Ubuntu.com wiki page here.

Monday, July 23, 2007

Farewell, Zenoss

Well, python community, I am back on the market.

After a year and half of consulting for Zenoss, where I contributed to the Zenoss code base and was lead dev on the community development effort, I am on my own again.

It's been pretty amazing having a front-row seat on the growth of Zenoss as a company. When I fist started consulting for them, there were only three employees and the general view was that most of the employees would end up being remote developers (this didn't end up being the case, as they found a fair number of local python developers). I was actually on-site when they interviewed Drew "the Docs guy", who ended up being employee #4. Since then, the number of consultants and employees has increased as greater and greater focus has been placed on non-dev business like marketing, sales and customer support. It was kind of strange being there this week... while at a party, I remarked to Erik Dahl that I barely recognized the place anymore.

I do feel badly that I have poured so much time and work into the recent Zenoss community effort and not had the time to contribute to the Twisted and Divmod code bases (as well as other projects) like I had wanted to this Summer. Hopefully my next gig will provide for more support in that arena. At the very least, I could very well have some spare time in the next few months to tune back in and maybe even crank out some tickets :-)

Well, I'm off to pick up some red curry or pad thai at the Lemon Grass!

Technorati Tags: , , ,

Tuesday, July 10, 2007

Open Source Community Interaction: Is More Less?

I have a friend who needs our help. In fact, there are potentially disturbing ramifications in the trend mentioned below, so *we* may need our help.

Here's the deal: my friend is a research assistant at McGill University in Quebec. He is working with his professor with regard to the following topic:
"Open source software (OSS) developers who interact MORE with leaders (administrators) apparently contribute LESS (e.g., write less codes). We need more insights into this finding. Basically, we want to know why this is happening. We have speculated that open source software (OSS) communities are public, voluntary-based and self-organized communities. Therefore, if OSS leaders are too controlling, then developers don't contribute as much. This was one of our speculations. I am wondering if any OSS developers agree with this."
Sadly, very few of the developers their research team has contacted have given feedback on this matter. Below is the short list of questions they are asking developers. Note that though the example of contribution was code in the above statement, these questions assume contribution to take any of the following forms:
  • source code
  • documentation
  • answering questions and providing assistance to other users via mail lists, IRC channels, forums, etc.
  • grass-roots marketing
  • other forms of community involvement that contribute positively to an open source project
Okay, so here are the questions:
  1. Does the open source project's leader/lead developer have a huge impact on your contribution?
  2. What reasons would make developers who interact more with core project contributors apparently contribute less to the open source project?
  3. How would you feel if the leaders of the open source projects to which you contributed became too controlling?
I responded when Meral sent me his email with the two examples of Twisted and Python communities, but these guys need many more points of view than a few... and they aren't getting much traction. I feel that this research is important, and when published, could affect how open source projects and contributions to said projects are viewed by a wider population.

If this is also important to you, I encourage you to send an email to meral dot hussein at mail dot mcgill dot ca. Give it the subject of "McGill University Survey" and let 'er rip. The sooner you can do this, the better -- the deadline for the first round data is July 13th.

Technorati Tags: , , , , , ,

Tuesday, July 03, 2007

It's Been a Long Time

To use the words of Rakim (track 4), though without their import: it's been a long time. There's so much that's going on in my non-technical life, just thinking about blogging has seized up all my joints and limbs. Until now, that is.

To summarize:
  • the good folks at Zenoss keep me mercilessly busy where our community efforts are release-a-rific
  • I'm no longer living in Loveland, CO, but leasing month-to-month in other parts of this great State... and wondering where home base will end up being (I'm thinking of buying my first-ever actual property)
  • I've got a girlfriend for the first time in 4 years; her magical qualities defy enumeration, though I will say that she is a highly accomplished practitioner of the healing art of Jin Shin Jyutsu (studied with Mary Burmeister herself) as well as being a fellow meditator
  • I'm preparing to support two people at an up-coming Lakota Sundance in South Dakota
  • In addition, I'm preparing for my first shedra classes this fall (specifically, Madhyamaka)
Since I now need a nap after deciding which (of the millions of) things to recount/summarize, the rest of this post will be dedicated to game music, in particular System Shock 2 :-)

Check out this thread. In particular, scroll down to "Reply #6 on: 23. April 2007, 13:05:18" and witness the goodness:

"These are the real arrangements created by Eric Brosius himself, authored as full soundtrack songs and burned as an album. Crafted from the original audio, unlike the 22khz audio files from the shipped game, this release is CD quality."

Technorati Tags: , , ,

Sunday, March 25, 2007

Genshi Templates in Nevow

Update: When done reading through this example and code, please see the most recent blog post about this that addresses the dynamic rendering of Genshi templates in Nevow.

I have been exploring the extensibility of Nevow, and I'm finding it surprisingly easy to integrate other tools. I've only used Genshi for recent Trac hacking, but I hear more and more about it and it seems to be gaining a little momentum as one of the preferred template systems for python web application developers.

Using the code from the blog post Object Publishing with Nevow, I have created an example of how to integrate Genshi with Nevow. I will provide a link to the source code at the end of the post.

Integrating another templating system into Nevow is actually a no-brainer: you just need to have the "alien" template parsed by its own parsers prior to Nevow performing its parsing. This impacts only one module: nevow.loaders.

Before we dig any deeper, how about some eye-candy? Then a quick review, and finally the code. Here are some screenshots of the Genshi templates running along-side native Nevow templates:

434358390 65710Bc3A0 O
434358446 Df7816377A O

The second image is the page in the little demo that showcases all the functionality of Genshi as documented on this page.

Traditionally with Nevow, Page classes contain data_*() and render_*() methods. These Page classes are "web resources" whose locateChild() method is called after an HTTP GET. Each page class that will have an HTML view needs to set a docFactory attribute; this is the loader instance I referred to above.

Here is a toy example of a page class from a previous blog post:
from nevow import rend
from nevow import loaders

class SiteRoot(rend.Page):

docFactory = loaders.xmlstr('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
What we need is to be able to do something link this:
from nevow import rend

import myloaders

class GenshiStuffResource(rend.Page):

docFactory = myloaders.genshistr('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
<h1>Genshi Test</h1>
<span genshi:with="y=7; x=y**2; z=x+10">$x $y $z</span>
<span>Your name is ${username}</span>
To make this work, all we have to do is create myloaders.py with the following content:

from genshi.template import MarkupTemplate

from nevow import inevow
from nevow.loaders import xmlstr

class genshistr(xmlstr):

def load(self, ctx=None, preprocessors=()):
attrs = inevow.IRenderer(ctx).__dict__
tmpl = MarkupTemplate(self.template)
xmlStr = tmpl.generate(**attrs).render('xhtml')
self.template = xmlStr
return super(genshistr, self).load(ctx=ctx,
There is a minimal amount of magic happening here: MarkupTemplate.generate() takes keywords (or a dict, with extended call syntax) and those key/value pairs are available to the template that is rendered. We are using our class's __dict__ for this; so if you want data in your template, you need to make it a class attribute. There are many ways to do this, and you can choose the one that is safest, cleanest, and least consumptive of resources for your application.

This is an example using a string as a template. The source code link below includes a folder where the templates are broken out into files and with a myloaders.genshifile class defined. The screenshots above were taken from a running instance of that example.

Browse the example source code here: nevow/templating/genshi.

Technorati Tags: , , , ,

Wednesday, March 21, 2007

Front Range Pythoneers Meeting

Sean Reifschneider of tummy.com (Twisted and PyCon sponsor) started up Front Range Pythoneers here in Colorado about a million years ago. Last year at PyCon 2006 Jim Baker talked about breathing life back into it... and he has. Today was not only proof of this (and my first meeting) but yet more validation of the local python community: enthusiastic, motivated and highly intelligent . Sean presented his PyCon 2007 Vim+python talk and Matt Boersma gave his wxPython and XRC talk.

Afterwards, I talked with Fernando Perez about IPython and its distributed computing branch, lead by Brian Granger and Benjamin Kelly (yet another physics guy/python coder). They are doing interesting things with Twisted and IPython, stuff that was brought up at the Twisted BoFs at PyCon this year (and in which radix and I took an interest). I look forward to attending the sprint in April and looking over Brian's shoulder, getting up to speed on how they are using Twisted and what they want to be doing (possibly exploring the use of twisted.conch.insults in IPython).

Technorati Tags: , , , ,

Wednesday, March 14, 2007

Zope 3 Surprise

I haven't blogged about Zope 3 in a while. Haven't had much of a chance to use it, really. I have had a bunch of people contact me recently about z3 work that I've done in the past, and it's been kind of nice refreshing my memory.

More importantly, though, one of my oldest clients asked for a site update and new set of features for a custom-built z3 CMS solution I started work on about 2 years ago. It only had one update in the past: from Zope 3X to Zope 3.1.0. Tonight, a year and a half later, I performed the second upgrade, and I'll be damned if it didn't take more than 30 minutes to "migrate" form 3.1 to 3.3.1. I use the quotes because the codebase actually ran without any problems on 3.3.1; all I did was make changes to a few ZCML files and update some import statements in order to remove the deprecation warnings. Unbelievable.

This really needs to be emphasized: the upgrade of Zope 3 was freaking amazingly painless. There aren't too many projects that can make that kind of boast. In fact, I know only one: Twisted. When I first started at Zenoss, I wrote some code for them that required deferredSemaphore, but sadly they were still running on Twisted 1.3. Eric Newton upgraded to Twisted 2.4, with only a few minor fixes required. I don't think it took him longer than an hour or two.

Projects that can do this are definitely doing something right. There's a good chance that their software development practices have a lot to teach other open source projects. And hell, closed source projects, for that matter.

Technorati Tags: , ,

Monday, March 12, 2007

Bouncing Balls

As mentioned earlier, there was a surprise Twisted contingent at PyCon this year, and I had the opportunity to hang out with both those of the gang that I'd already met and done some hanging with, as well as those that I had not. Brian Warner was one that I hadn't had a chance to chat with much until PyCon, and it was amazing. I plan on interviewing him in the future regarding Foolscap, his thoughts on E and python, as well as the innovative business he's working for right now.

But what the hell, you ask, does this have to do with "Bouncing Balls"? Well, in addition to going (or not going) to talks, attending BoFs, engaging in extensive business networking, and eating/drinking copious quantities food/drink stuffs, we also had time for good old-fashioned geek fun: watching movies. I do use the term loosely, though, indicating essentially anything *.mov, *.avi, *.wmv, etc. Brian shared with a whole gaggle of us the joys of The IT Crowd (all six episodes), Stalking Santa (preview), George Lucas in Love (which I had never seen), and the apparently famous (and rightfully so) Bravia commercials. The paint "fireworks" advert filmed in Scotland was just brilliant and hilarious (be sure to watch the making of), but I left my heart in a superball, bouncing down the streets of San Francisco. See if the same doesn't happen to you when you watch the Bouncing Balls.

That video simply mesmerizes me. I've watched it tens of times and it still makes me feel like a joyful little kid. Just amazing. Side by side with the insanely awesome cinematography and the astounding colors, the music makes this a stunning classic. The song has been haunting me since PyCon and last night I finally had a chance to sit down and search for the artist. I didn't have to search long, though, as the Bravia and last.fm pages share all. Turns out the song is "Heartbeats" from José González's album Veneer, a cover from eccentric Swedish band The Knife. After reading more about Veneer, I bought it immediately. I highly recommend it.

And, no, I'd never see this ad before; I don't have TV service. I am of the "pull" school for entertainment, versus "push" (or "always on").

Technorati Tags: , , ,

Friday, March 09, 2007

Django-esque URL Resolution in Nevow

So, from the previous post on object publishing in Nevow, we had the following resources:
  • http://localhost:8080/
  • http://localhost:8080/mystuff
  • http://localhost:8080/yourstuff
We added child_* attributes and methods to the "root" class, thus defining the "mystuff" and "yourstuff" resources. But what if we want to do it like Django does it? In other words, how do we map paths in the URL to resources via regular expressions?

It's actually fairly straight-forward. All we need to do is the following:
  1. Create a tuple of patterns.
  2. Override the locateChild() method in our "root" class.
Working with and extending the examples from the previous post, we might create a patterns tuple like this:

urlPatterns = (
(r'/mystuff(.*)', MyStuffResource),
(r'/yourstuff/blog(.*)', BlogResource),
(r'/yourstuff(.*)', YourStuffResource),
Then, in SiteRoot, we could do something like the following:

    def locateChild(self, context, segments):
path = '/'.join(('',) + segments)
for regex, resource in urlPatterns:
match = re.match(regex, path)
if match:
newPath = match.groups()[0]
r = resource()
if newPath in ['', '/']:
return r, ()
newSegments = newPath.split('/')[1:]
return r.locateChild(context, newSegments)
return super(SiteRoot, self).locateChild(context, segments)
What we're doing here is interrupting the "natural" flow of Nevow's path processing. If there are more segments once we've found a match, we pass the additional segments on to the child resource's locateChild() method. If not, we have a final destination and can return the resource itself.

Here are some screenshots of this in action:

415352821 6C5Cd31031 O
415352839 64Bee68A6A O
415352871 267C96D7A0 O
415352893 73D1095E30 O

You can browse the code for this at the following links:

Technorati Tags: , , , ,

Friday, March 02, 2007

Python Will Rule the World

Before I tell you why, how about a story first?

When I was a kid, my parents bought a KayPro II so that they could use the spreadsheet program for financials and my dad could write a medical text book. I, of course, discovered the BSD games (BASIC clones) that came with it almost immediately. All of my friends had TSR-80s and C-64s, and it seemed that we all discovered BASIC and the hackability of games simultaneously. We would gather around the school computer and take turns making changes to the available games and then playing each others' variants. It was a time of bliss that was only surpassed 15 years later when I discovered Linux and began contributing to and writing open source software.

Most programmers I talk to in my generation have similar stories to share: we got completely hooked on the industry (long before we knew there was an industry) solely on the merits of editable source code. My parents hated when I played "too much" and they never really "got" that I was actually only playing a fraction of the time. They thought I was getting wound up on high scores and grue evasion... but they were missing the bigger picture. I spent far more than half the time changing the games, adding levels, extending star fields... enriching my gameplay. The high that I had discovered and was totally addicted to was the mutability of my universe.

Enter OLPC. The One Laptop Per Child project is absolutely phenomenal, far more so than I had ever anticipated. After Ivan Krstić's keynote at PyCon this year, everyone I talked to had the same impression that I had: Python Will Rule the World. And here's why:

Thousands, hundreds of thousands and possibly millions of children around the world will be using these innovative little machines. Children are amazing, curious, and fantastically brilliant sentient beings. Highly sentient. And into these little genius hands will be placed laptops that connect them to their friends, their teachers, and the rest of the world. Their interface to these laptops will be written in python. There is even a button on the laptops to "show source." Just as a small portion of my generation became addicted to the mutability of our universe, an insanely larger number of kids will have this same experience thanks to OLPC and python.

Look at what we've done so far. It's been amazing. And look how few of us it took. But what's going to happen when thousands and thousands of eager, curious, children from all over the world discover that, through the power of changing software, they can make changes to their world?

They will learn python. And with that, they will make this world theirs.

Technorati Tags: , , , , ,

Tuesday, February 27, 2007

Object Publishing with Nevow

Update: Code for the "Nevow Object Series" of blog posts is available here. Note that the examples can be viewed and run as single files or "project style" with code broken out into separate files.

Object publishing is a very simple concept: making code objects accessible over some medium. The medium most often discussed, due to the prevalence of web applications is HTTP/S. For our purposes, the published objects we will discuss are instantiations of python classes written to provide resources over the network.

In the python community, the most famous example of object publishing is the Zope application server. Zope exposes object written in python or with various Zope scripts/products/etc. In an old Zope 2 Book, Zope's object publishing is broken down very simply:
  1. The client sends a request to the server
  2. The server locates the object using the request URL as a map
  3. The server calls the published object with arguments from the request.
  4. The server interprets and returns the results to the client
What we have here is essentially object look-ups by URL. Given the web context, this makes obvious sense.

With such a simple definition of "object publishing", we can begin seeing "object publishing" pretty much anywhere python is used to deliver content or other resources on the web. For instance, Django qualifies as having an object publisher by means of the configuration mechanism whereby one can use regular expressions to map URLs to its "view" objects. We'll come back to Django in a bit.

Twisted's web "framework" Nevow has a object-publishing capabilities that, due to it being controlled by python classes is limited only by the python code you can write. There are four primary mechanisms by which one can publish objects in Nevow:
  • child attributes on a resource
  • child methods on a resource, or
  • dynamic children using the childFactory() method
  • manipulating the traversal of objects via locateChild() method
I will be focusing on the first two, however, before showing examples of these let's cover some minimal background. Twisted services are commonly run using what's called a .tac file ("Twisted Application Configuration"). Here is a trivial example of this:
from twisted.application import service
from twisted.application import strports

from nevow import appserver

import stuff

# instantiate the application
application = service.Application('Site')

# set up the main resource
root = mystuff.SiteRoot()
site = appserver.NevowSite(root)

# setup the web server
server = strports.service('tcp:8080', site)
Give than this file was saved as site.tac (and that there was a sibling file named stuff.py with the resource SiteRoot defined), you would enter twistd -noy site.tac at the system prompt to run this. This would start a server listening on port 8080. But what is SiteRoot? It is a resource we are making available at the root of our application, "publishing" it at http://localhost:8080/. And what would it look like, you ask? Well, a silly example of stuff.py that define SiteRoot might be something like the following:
from nevow import rend
from nevow import loaders

class SiteRoot(rend.Page):

docFactory = loaders.xmlstr('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
One reason that this is a silly example is that it does nothing other than declare that the published resource will be an XHTML file with a Nevow namespace, providing no methods (and little content). Additionally, it uses the XML "string" loader, instead of using stan or the XML file loader (for using templates from disk). Regardless, if we add a child attribute that points to another class, we can start to see the object publishing behavior of Nevow:
from nevow import rend
from nevow import loaders

class MyStuffResource(rend.Page):

docFactory = loaders.xmlstr('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"
<h1>My Stuff</h1>

class SiteRoot(rend.Page):

docFactory = loaders.xmlstr('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"

child_mystuff = MyStuffResource()
Starting up our application with these changes will allow us to access the root and child object via the following URLs, respectively:
  • http://localhost:8080/
  • http://localhost:8080/mystuff
This demonstrates how to publish objects via the child_ attribute. child_*() methods do the same thing, while offering all the flexibility that comes with methods. For instance, we could define the method child_yourstuff(self, context) in SiteRoot that would check for your username in the application cookie and pass that info when instantiating a UserStuffResource class. Then the URL http://localhost:8080/yourstuff could publish data specific to whatever was available in a data source associated with the username. The child_*() methods do need to return a resource object, though.

This has been a brief run-down on how you can use child_*() methods and child_ attributes to publish objects. In the next installment, I will show how to customize URL traversal for accessing these resources via the locateChild() method. In particular, I will show how to duplicate the Django URL conf functionality in Nevow.

Technorati Tags: , , ,

Saturday, February 24, 2007

Twisted BoF, Part Deux

Yes, we had another BoF today. How could we not? "But why?" you ask. "How could it get any better?" Well, if it wasn't better, it was just as insanely awesome as last night's. Only completely different.

I don't want to give away too much... there are many others who have a much greater right to share (and celebrate!) this news with you. So I will tease and tantalize instead: exciting things are afoot in the Twisted community. If you ever were curious about diving into Twisted and decided not to, now is definitely the time to reconsider, start checking it out, learning, and getting involved. You won't want to miss out on this.

"Do you know what I'm talking about?"

"The Matrix?"

"Do you want to know what - it - is?"

Technorati Tags: , , , ,

Friday, February 23, 2007

The Twisted Conference

I just got up to my hotel room from the BEST freakin' BoF tonight. Not only were there way more people than any of us expected, but most hung in there like CHAMPS: we started at 8:30pm and didn't get out until almost midnight! Okay, that's a little exaggeration... it was more like 11:30pm. Those present represented the spectrum of new users to intermediate through "founding members", and it was a damned trip. Just tons of amazing energy and latent excitement. And the love, baby -- you could just feel the love :-)

This came as a surprise to many of us, considering that 1) like last year, there are no Twisted talks and 2) most of the Twisted folks didn't know who all was showing up and we didn't think there'd more than a few. At last count, there are eight of us here now, and when Itamar shows up tomorrow, that will make nine.

But back to the BoF: the energy was truly palpable and the room was pretty packed. The topics covered were diverse and very interesting. The questions were stimulating, the answers insightful (and often hilarious). It was, in essence a conference within a conference :-) I believe over half stayed for the duration, and not only did it end with a standing-O (well, we were standing to leave...), but there were cheers and suggestions to do it again tomorrow. An hour later, I'm still pumped and totally incapable of considering sleep. If the enthusiasm of the BoF continues through the rest of the conference, we could end up with a couple sprints...

Technorati Tags: , , ,

Monday, January 29, 2007

Ben Harper

This dude is just awesome. I've been listening to him casually since college (one of my suite-mates was a big fan). Through my casual enjoyment, my housemate has become a pretty big fan, so I got her the three-disc edition of Both Sides of the Gun. Of course, I've been listening to it as well :-)

As a result, I've been hearing a much more diverse selection of his music than I've ever had at my fingertips. And I've been listening more closely...

This guy is just amazing. He's got sounds and styles that range from Cat Stevens and Mick Jagger to Stevie Wonder and Stevie Ray Vaughn. He's got punk, jazz, honkey-tonk as well as his signature quiet laments. And he pulls it off in a manner fantastical. Not once does it appear as if this is a musician who can't make up his mind; quite the contrary. Everything he does on three-disc album is 100% Ben Harper, 100% committed to the music.

Go get it now. Before you get hit by a bus.

Technorati Tags: ,

Friday, January 26, 2007

The Twisted Show

We're doing a little experiment on the Twisted Labs site, and I thought I would invite folks to check it out:


It's also linked off of the front page under "New Feature", so it's hard to miss :-) We're aiming for podcasts down the line, but right now (while I'm learning how to actually *conduct* an interview) we're providing (edited) transcripts.

I'm actually kind of excited about this: it's such a great opportunity to chat one-on-one with folks who are using Twisted as part of their success -- which is ultimately what software is supposed to help us do.

Our first interview was with Renkoo, providers of a social networking software for fluidly and intuitively plan events with friends. It's a perfect match for planning get-togethers when the "when" and "where" haven't yet been decided.

We've got a list of projects in mind for interviews and/or podcasts, but I'd love to hear from folks on who *you'd* like us to interview. And the kinds of questions to which you'd be interested in hearing answers.

Technorati Tags: ,

Friday, January 12, 2007

How to Skin a Trac

Twisted ScreenshotAs some folks know, I worked with Huw Wilkins on the new redesign of the Twisted site. Huw did the design, CSS etc., and I hacked around on trac to make his vision work within that framework. He made my life very easy, though, as he produced the entire design to fit perfectly within trac.

The new Twisted site has been a success -- we're getting many more visitors and they are staying longer than ever. I believe that the design and the improving info architecture are the most significant contributors to this. And after seeing these changes and the assumed enjoyment that folks are deriving from them, all I could think was "This was so easy to do, there's no excuse not to have a good-looking trac instance."

Zenoss Trac ScreenshotHaving been inspired by Huw's great design for Twisted, I did the same thing for The Zenoss internal trac instances. I had a great time doing this, having explored a lot with the Twisted site redesign. What's more, with the use of the trac dev branch (forth-coming version 0.11) the Genshi templates really simplify the process. With the process I had established with the Twisted work and the Zenoss work, I was have the courage to update my own massive number of trac projects: 3 domains with each one being a trac "multi-sites" setup.

355032827 Ebeb9A759D M

People don't realize how quickly you can take a generic trac and have something quite unique. Here's all you need to do:

  • install Genshi and 0.11 Trac from subversion
  • design your look and feel and then prepare your images
  • edit the trac.css file
  • update the site.html and layout.html Genshi template files
Now, things do get a little complicated when you have trac multisites running. You have to write code that will render the sites index the way you want. Then you need to consider how to manage the templates across all the sites.

As an example, I've put the trac customizations in subversion here.

Technorati Tags: , ,