I recently blogged about developing a CherryPy application to drive the non-blog portion of Important features (for me) were a clean, web-based admin interface, the ability to organize content into “folders” and the ability to arbitrarily extend the system. After putting together a prototype (which actually worked… mostly), I realized that WordPress had added support for sub-page URLs. “Holy crap,” I thought, “Word Press can act as a mini-CMS, and I’ll get to leverage everything they’ve done [even if it is in PHP]”. So I did.

You’ll notice that is now powered by Word Press, along with a handful of plugins and hacks. In the development of the site, I actually did put together my own WordPress plugin, which I’ll hopefully be releasing “real soon now.” Stay tuned.

date:2005-05-25 13:09:38

Chasing Rails

At the risk of adding to the echo chamber, I’d like to point out the React Framework for Zope, a Zope 2.x product which attempts to ease web development by “stealing ideas from Ruby on Rails”. OK, so this looks cool. But I can’t help wondering why Rails has become the gold standard that web application frameworks aspire towards? Between React, Subway and CherryPy (which Subway uses), there seems to be quite a bit of interest in coming up with either “Python on Rails” or a “Rails Killer”. Is Rails really that good? I admit it looks cool, but I haven’t actually used it. Can someone help me out on this?

date:2005-05-18 09:15:37

30 days of my life

Well, it’s not 10 years, but I’m launching a little experiment in introspection and self improvement. For the next month I’ll be doing daily blog posts at 30 Days: Rehab + 2. The goal is to learn something about myself, and share the results with others in the process.

date:2005-05-13 08:46:01
category:my life

Distributing Python Applications

As a preface, this post is mostly rambling thoughts on the current state of ccPublisher 2, and some of the challenges yet to be worked through. You’ve been warned.

So now that the semester has wrapped up and my days are no longer consumed by homework, exams and projects, I’ve been trying to move forward with ccPublisher 2, the long awaited (and long promised) update to ccPublisher. While we’re not planning any new user features of ccP2, it’s an important milestone for another reason: extensibility. The current ccPublisher codebase is rather monolithic, and can be customized in only the broadest sense of the word. That is, yes, you can customize it. What, you want to merge features from the main tree? Hah! Since we already have two derivatives of ccPublisher in the wild (Jamloader and Ourmedia Publisher), a primary goal (maybe the central goal?) for ccP2 is making these customizations easier, and also making them more compatible over the long haul with the core ccPublisher codebase.

The central development philosophy we’ve been using to make this a reality can sort of be summed up as “extreme programming, table for one.” We’ve grabbed lots of pieces of code from the Zope 3 project, specifically the component model, interface support and ZCML. This lets us handle lots of situations that were previously part of the formal API with events, adapters and handlers. It’s not important where files are selected, the primary application class only needs to listen for the appropriate event. So when I’m working on the code, here’s what I keep in mind:

  • ignorance is bliss,
  • YAGNI,
  • and your code is crap.

Let me elaborate. First, “ignorance is bliss.” I’ve begun to think of object models and APIs much the way I think about property taxes. I know that I pay property taxes on my house, and I know that money is taken form my mortgage payment and placed in escrow for that reason. But I’m willfully ignorant about how much I’m paying or how the escrow works: I just know that I can afford the monthly house payment, and leave it to others to sweat the details.

Between the ccPublisher 1.x releases and the current ccP2 codebase, there was another implementation. It was better than the 1.x release, but had it’s own problems. It traded the maintenance problems of the ccP1 monolithic code base for a large, complex API meant to enforce MVC seperation, blah, blah, blah. That model relied on subclassing for customization, and as such you had to be aware of a fairly complex super class to make things work right. The new ccP2 codebase doesn’t have any enforced seperation: you just pick the pieces you want to replace, implement the correct event publishers or handlers, and the superclass does the rest. This may be a little hard to visualize in the abstract, but the result has been a much more flexible “feeling” API.

YAGNI is an extreme programming acronym, standing for “You Ain’t Gonna Need It.” As I’ve been working on ccP2, I’ve tried to keep this in mind. I (and XP guys, I guess) do this because it’s not necessary to spend time working on an API for implementation you don’t actually need. Better to implement the bare bones functionality, and then begin experimenting with more complex use cases. In the case of ccP2, this has allowed me to get a functional, testable application up and running, and then focus on “niceties” such as drop-down boxes and cleaning up the UI.

Finally, “your code is crap.” And by “your”, I mean “my”. This is my slightly stronger version of the XP principle of being willing to throw stuff away. I know that I tend to become very attached to my code, and want it to be pretty, elegant and pristine. And when it’s not, I like to delude myself into thinking it is, and continue to tack features on when clearly, I just need to throw it away. So I just tell myself, “Yergler [yes, I call myself by my last name — it has a middle school gym teacher sound to it that seems to motivate, or at least frighten, me in a productive manner]! Your code is crap! Drop and give me twenty!” This makes me much more willing to tear out code wholesale. And while I’m at it, this ties back in with the first point — if I’ve done it remotely right, I’ll be able to tear out the crap without disturbing the parts that are actually working.

So now that we have a working component model (well, one we stole from Zope 3 that we’ve successfully adapted), what’s left to implement? Distribution. One of the points of ccP2 is to allow minimally invasive customization. In the current code base, metadata fields can be added by simply modifying a configuration file, so it doesn’t make much sense to ask customizers to ship a slew of code if all they really have made is an XML file. Additionally, it doesn’t make much sense to have half a dozen (ok, 2) versions of the framework on the machine in different places — it should really be shared so that when one App updates the framework, everyone reaps the benefits of bug fixes and internal improvements. Here’s some of my thoughts on this right now:

  • For Windows systems, we can register the framework with a registry key. The installer can then check for the key and adjust the paths in the executable scripts accordingly. In this case, the framework includes the Python binary, and everything else generated by py2exe. I think (from my limited research) that NSIS can be used and scripted in such a way as to check for the existance and version of the framework before installing.
  • For Linux systems, a similar approach could be used, with gconf substitued for the registry. Maybe. Since wxPython has a mature GTK2 backend, I tend to focus on Gnome over KDE, but really we should be able to find things “the right way” (for some definition of right). Maybe has a semi-standard way for registering installations, or maybe the framework should be it’s own package (RPM, deb, etc) which the actual app can depend on.
  • For Mac OS X, the problem is a bit trickier. Up to this point when distributing Python apps, I’ve used Py2Exe for Windows along with an installer (WiX, etc). For OS X, I’ve been able to just use buildapp or py2app and bundle everything into a single app package. For this new model, we’ll need to install some pieces to the Library, some to Applications, etc. I’m sure this is possible (lots of apps do it), but have no experience with it. Additionally, I’m not completely clear on what will need to be tweaked in the final .app file to include the Library in the PYTHONPATH.

Overall the problem is not insurmountable, but simple one of resources. And it sucks that each platform will need it’s own attention. I guess the upside is that once we’ve figured it out, customizers won’t have to worry about the details. And that’s a good thing.

date:2005-05-12 13:05:45


My Mom and Dad have always been taken with our dogs, Bosco and Madeline. So for Mother’s Day, we took a chance and got my mom a puppy, Samson. We did this with my dad’s blessing, but as he repeatedly pointed out “It’s gonna be an interesting Mother’s Day.”

It actually went really well. We picked up Samson from the breeder on Wednesday, and he stayed with us until Saturday when we went to my sister’s house for Mother’s Day. Samson is a Schnoodle, a Schnauzer-Poodle mix. As such, he’ll top out at about 7 pounds. Tiny.

From the daily reports I’m getting from my parents, it sounds like he’s enjoying his new home. Which is good, since after only 3 days, I miss him terribly. Hopefully Mom and Dad will get as much joy from him as we get from our dogs.

date:2005-05-10 07:13:43
category:my life

CherryPy: Silly Name, Cool Framework

I’ve been playing with CherryPy, one of many Python web frameworks, over the past 12 hours, and have to admit I’m really impressed. I first ran across CherryPy a few years back, and was thoroughly unimpressed. The details are hazy, but I seem to remember that in it’s first incarnation, it involved embedding Python in templates, running some sort of compiler over them, and then serving them up. Like I said, the details are hazy, so I could be completely wrong on that. What I do remember is that I couldn’t get the Warrant song out of my head for days, and that itself was enough to make me write it off. This may say more about my white trash background than anything, but that’s not a path I want to explore this morning.

So CherryPy reentered my radar during PyCon, when it was mentioned in reference to the PyWebOff (a session I seriously regret missing). Last night I finally decided to address a naggling problem (more on that in a moment) and installed CherryPy (which I’ll refer to as “CP” from here on out). Here’s what it has going for it:

  • Like Quixote, CP focuses on mapping requested URLs to Python objects. Specifically, callables. So a function, def foo(): ... in the root of a CP site maps to http://[root]/foo.
  • Unlike Quixote, CP provides fewer “special” methods. Quixote uses things like _q_index, _q_lookup, etc (I may have those wrong… it’s been a while) to provide special index or name resolution methods. CP also uses the idea of an index, but it’s just a callable, index. And there’s only one other special method, default, which is called to resolve names when CP can’t find them. This means you can easily implement Quixote-like behavior if you need it, but for 90% of the cases I run into, the default, simpler implementation is sufficient.
  • CP does not include a templating language. This is a good thing. “Recipes”: are available for integrating Cheetah Templates, and I was able to integrate ZPT in about 30 minutes. This means that if you don’t need or want templates, you don’t have the overhead. If you do want them, you can use the ones you’re most famliar with.
  • CP uses modern language constructs like decorators to annotate methods with security and visibility information. I’m sure other web frameworks could implement similar syntax without much trouble, but this gives CP code (in my opinion) a clean, literal quality.
  • Finally, CP includes support or example code for both sessions and authentication, two very common web application idioms.

I’ve used Quixote and Zope extensively in the past. Both have really compelling qualities. However, I think the most compelling thing about CP is how quickly I was able to get up and running.

It took months to get this far in Zope. Now that I’m there, though, I know Zope is incredibly powerful, and wouldn’t hesitate to use it for a large system. Once you figure out the idioms, you know how to get things done.

With Quixote, I find I have to refer to the samples and documentation much more than I’d like. Given the fact that session handling and authentication isn’t built in, it’s annoying to have to figure out how to implement the shelve session handler every time you build an app. This isn’t entirely fair: I’m sure if I built Quixote apps on a regular basis, I’d be able to do it without the docs. But I’m confident I can write something in CP and come back in 6 months, and still be clear on what’s going on in the code. I think the understanding would be far less with Quixote (admittedly, this may say more about my code than Quixote itself; I can only speak for myself).

So what was the itch I had to scratch? Content management. Aside from my blog, the rest of tends to stagnate and become horribly out of date (really, I haven’t work for Canterbury for 9 months). I think part of that has to do with the fact that I’m running the site with “PyBlosxom”:. PyBlosxom is cool in that it allows you to use flat text files for content, and merge them with the “presentation” at the time of request. But to edit those files you need to SSH into the server, edit the file, etc. Constrast that with WordPress which runs by blog, where I can easily log in from a university computer (which probably doesn’t have an SSH client on it), and create, edit or manipulate content. So I’ve been wanting a simple, bare bones CMS which would allow me to create content using a common template.

The requirement which has kept me from using something like TextDrive, or even WordPress is that I need URLs that match what I currently have. That basically translates into unlimited depth “sub-categories” or directories.

Anyway, in about 12 hours (of which 6 or 7 were spent sleeping), I’ve been able to put together a basic system that features through the web editting, rendering using Zope Page Templates, and basic security for the admin areas. Take that, Rails.

date:2005-05-03 10:48:26