Skip to content

Installing different Python environments on Mac OS Leopard

This link at jessenoller.com is an excellent reference on setting up multiple Python installs on Mac OS Leopard and using virtualenv to create bespoke working environments for various Python packages:

jessenoller.com - So you want to use python on the mac?

Cappuccino and CherryPy, Part II

I'm in the process of blogging my experiences using the Cappuccino JavaScript framework and CherryPy, a Python web application project. The first post can be found here.

Cappuccino is designed to provide an application-like interface inside a web browser. As a result, when you're building a Cappuccino application, instead of the server providing a sequence of pages to view, the server is providing data (usually using JSON) that the Cappuccino application running in the browser retrieves and displays. For all practical purposes, using Cappuccino is very like old-fashioned client server programming with the client written in Objective-J and the server, in this case, written in Python.

In this post we'll focus on changing the Cappuccino "Hello World" application so that it retrieves it's message from the server using JSON. No, it's not a particularly exiting application but it has the virtue of being simple and fundamental: Once it's possible to act on JSON data from the server, the rest is just details.

First, we'll change the client side Objective-J code. We need to add the following two lines to the end applicationDidFinishLauching: method of our AppController in AppController.j

 
    var request = [CPURLRequest requestWithURL:"getLabel"];
    var connection = [CPURLConnection connectionWithRequest:request delegate:self];
 

The first line creates a CPURLRequest for the "getLabel" URL from the server. The second line actually makes the connection to the server using that request object. Like it's inspiration, Cocoa, Cappuccino makes heavy use of the delegate pattern. In this case we pass our AppController object as the delegate for the CPURLConnection. There are two methods that the CPURLConnection may call on the delegate. We'll add those next:

 
- (void)connection:(CPURLConnection) connection didReceiveData:(CPString)data
{
    var result = CPJSObjectCreateWithJSON(data);
    [label setStringValue:result.label]
}
 
- (void)connection:(CPURLConnection)connection didFailWithError:(CPString)error
{
    [label setStringValue:@"Label Did Fail With Error"]
}
 

The method "connection:didReceiveData:" is called with the original connection object (useful to distinguish between multiple pending connections) and the data that the server provided. The "connection:didFailWithError" is called if the connection failed for some reason.

For now, we'll simply change the label when the connection completes. If the connection fails, we'll note that. If the connection does receive data, we'll use that data to change the label. To do this, we use a CPJSObjectCreateWithJSON(data) object. Once we've done that, we can retrieve the "label" attribute of the result and display it.

There's one other thing that we need to do on the client side for all of this to work. In the original AppController.j, the label object is a local variable. Since other methods of our AppController object need to access that object, we need to make it an instance object. We do this by adding the following line to the "@implementation AppController" stanza in AppController.j:

CPTextField label;

We also need to remove the "var" qualifier from the first appearance of the label variable in "applicationDidFinishLaunching:"

The server side is even simpler. We simply need to add a method that will respond to the "getLabel" request that the client will make. We do this by adding a "getLabel"
method to the root CherryPy object:

 
    @cherrypy.expose
    def getLabel(self):
        data = {"label":"Server Hello" }
        return simplejson.dumps(data)
 

In that method, we'll create the Python dictionary that we'll return. It has one attribute/key "label" which we'll set to the string "Server Hello". Then we use the Python simplejson to convert that object to a JSON string which we return.

We've seen that it's fairly easy to communicate between the Cappuccino client and the CherryPy server. Next we'll start looking at building a somewhat more elaborate client application based on data returned from the server.

Cappuccino and CherryPy

Cappuccino is a JavaScript toolkit for building application like experiences on the web. It's developed (and used) by the folks who produced 280 Slides, a rather amazing presentation package for the web.

I've been doing a fair bit of of Mac development and have come to appreciate the syntax of Objective-C. One of the more interesting aspects of Cappuccino is that it has created a new dialect of JavaScript that they call Objective-J. This blog post explains some of the motivations they had for doing this. In any event, I decided that I'd like to give Cappuccino a spin.

My "go to" language for server back ends is Python. I also like CherryPy, a Python server framework that makes it easy to attach Python code to web requests. Since Cappuccino is designed to make it easy to build an application inside a browser window, the back end mostly needs to be able to serve up JSON data for the Cappuccino application to present. CherryPy makes this fairly easy.

To get started, I downloaded the the Cappuccino "Starter Package". Inside that zip file is a "NewApplication" directory. I copied that directory as a directory called "static" in the my Application directory. If you open the supplied index.html, you are presented with a very basic "Hello World" application written in Cappuccino. In order to to build the application I have in mind though, I want that index.html to come from my CherryPy server so that the Cappuccino application can easily request information.

To do this, I configured my CherryPy application to server the contents of my Application/static directory. This is readily accomplished by creating a CherryPy configuration file cherrycappuccino.ini:

 
[global]
tools.staticdir.root = "/Users/keith/Projects/CherryCappuccino/Application"
 
[/]
tools.staticdir.on = True
tools.staticdir.dir = "static"
 

This tells CherryPy to server the contents of my "static" directory statically.

What remains is the Python code that builds the CherryPy application. At this point it's quite simple. We create one object that's mounted on the root of the CherryPy server. It's index method simply returns the contents of the index.html file in the static directory (there might be other ways to accomplish this but this was expedient. Here's the Python code from cherrycappuccino.py in my Application directory:

 
import cherrypy
 
class CherryCappuccino:
    def __init__(self):
        self.indexText = None
 
    @cherrypy.expose
    def index(self):
        if not self.indexText:
            indexFileName = os.path.join(os.path.dirname(__file__),"static","index.html")
            indexFile = open(indexFileName)
            self.indexText = indexFile.read()
 
        return self.indexText
 
cherrypy.quickstart(CherryCappuccino(),'/',"cherrycappuccino.ini")
 

This reads the cherrycappuccino.ini file to configure the application and starts the server with our single application object. Starting the server with "python cherrycappuccino.py" sets up the server that can be browsed to at http://localhost:8080.

In a future post, I'll show how to configure the Cappuccino view based on data returned from the server.

Article Summary

I've added a page that links to all of my published articles on the web.

To Publish Without Perishing (Clay Shirky guestblog post)

To Publish Without Perishing (Clay Shirky guestblog post)


Clay Shirky, guest blogging on Boing Boing does a nice job of delineating the differences between "Readers" and "book Lovers".

From Aldus Manutius until recently, book lovers have been the most passionate readers. Now they are mostly just the oldest readers. Thanks to digital data, there is a fateful choice to be made between serving lovers of the text and lovers of the page; I think even Manutius would have sided with the readers over the collectors. I hope today's publishers do as well.

New Linux.com Articles

I've had a number of articles published at Linux.com recently:

Finished NaNoWriMo

This past Sunday I finished my NaNoWriMo (National Novel Writer's Month) novel. For those not familiar, NaNoWriMo is a yearly event, held every November, in which people sign up to write a 50,000 word novel entirely within the month of November. Those who achieve the 50,000 word goal are designated "winners". This is my second year participating and my second "win".

It'd be fair to ask why a software developer in upstate New York would participate in such an event. At the first level, I now have a first draft of something that could, with a lot of work, become a fairly decent novel. It's only a first draft, and a rough one at that. But a completed first draft of a novel is more than most people ever produce.

The real value of NaNoWriMo though, is that it is an exercise in discipline and in sustained creativity even in the face of difficulty or lack of inspiration. Miss more than a day or two of the 1667 average daily quota and catching up can become daunting. I learned a lot about writing and about myself during my first NaNoWriMo, and I learned even more this time.

For now, I'm glad it's over. It's nice to have a little free time again. But come next September or October, I imagine I'll be considering possible plots and getting ready for another November of writing.

Using Mercurial for Mac OS X Development

As a budding Mac developer, one of the things that I've had to sort out is which source code version control system I want to use. I first started using version control with RCS some 25 years ago. I've introduced version control or better version control at several of the jobs I've had. Heck, I've even published an article on using version control. Most recently I've used Perforce at an installation with a few thousand fellow developers.

Which is to say that while my eyes will still glaze over during a discussion of the relative merits of different delta storage mechanisms, I know enough to know why the latest crop of distributed version control (DVCS) systems are interesting and that I wanted to use one of the "big three" (Git, Mercurial, Bazaar).

I didn't bother trying Git. Mostly because cross platform support (especially Windows support) didn't seem to be "job 1" (or "job 2" or even "job 3 or 4") with the developers (understandable given Git's history but not as useful to me -- sooner or later all projects cross platforms it seems). Besides, both Mercurial and Bazaar are largely written in Python which I use extensively and that made them interesting to me. Given that all three are used extensively for large projects, whimsical winnowing criteria like this feel safe enough.

I started out with Bazaar, largely because at the time it was easier to find a non-Fink, non-MacPorts installer for it. It was pretty easy to set up and use and the benefits of it's distributed nature were readily apparent -- my favorite productivity trick is to take my laptop somewhere without a net connection and trivially easy branching and versioning while offline were a breath of fresh air to a Perforce expatriot.

But. I've switched to Mercurial. Mercurial now has a non-Fink, non-MacPorts installer as well (maybe it always has). And it has "hg serve". The "hg serve" command starts an ad-hoc web server that you can browse to locally or over a network to get a quick graphical view of your repository. It comes built-in with Mercurial and it works anywhere Mercurial works. Nothing else to install, no half baked GUI clients, just a good, easy to use GUI. It's not a particularly functional UI (you don't use it to check things in for example) but it provides the thing I want most from a VCS UI: the ability to quickly and easy browse through my repository and look at differences between revisions of code. I keep my own code and any third party code I use under source control and the ability to easily look at revisions (color hilighted, full context etc.) is an important aspect of code archeology. Life's too damn short to spend it looking at raw diffs in a terminal window.

So that's why I decided to give Mercurial a try. I wound up sticking with it (at least so far) becuase it was relatively easy to find information (mostly on the Mercurial wiki) on how to use Mercurial on a Mac, in particular it turned out to be very easy to confgure Mercurial to use FileMerge for diffs and, more importantly, merges (I've never been very good at textual merges with the ">>>>" token markers).

Beyond that, using "bzr" or "hg" commands is largely the same with some minor translation required. In the end, though, it was just easier to make Mercurial dovetail with my Mac and my style quickly and with very little fuss.

The rest of this post will describe how I've set up Mercurial. It's quite possible that all of the following can be done with Bazaar and Git just as easily. I'm putting it here so that it will hopefully will save some one who wants to try Mercurial on the Mac some time.

Once you've installed the lastest version of Mercurial on your Mac you'll want to configure it. You'll do this by creating and editing an ~/.hgrc file. Here are the contents of mine:

[ui]
username = Keith Fieldhouse <keith@rex...>

[extensions]
hgext.extdiff =

[extdiff]
cmd.opendiff = opendiff-w

[merge-tools]
filemerge.executable = opendiff-w
filemerge.args = $local $other -ancestor $base -merge $output

The "username" in the [ui] section simply provides a nice username to label changes in your repository with. the "hgext.extdiff =" line simply turns on the "External Diff" extension. While it's labeled an "extension", it comes as part of the Mercurial distribution. The "cmd.opendiff" line tells Mercurial to run the opendiff-w script (see below) when the "hg opendiff" command is used. Simillarly, the commands under [merge-tools] tells Mercurial how to run the same opendiff-w script when it wants to allow you to do a merge.

The opendiff-w script simply runs opendiff (the command line command that starts FileMerge) through a pipe so that it will wait until FileMerge has exited before returning from the command which is the behavior that Mercurial expects from the diff and merge tools. My copy of opendiff-w is kept in /usr/local/bin and looks like this:

#!/bin/sh
opendiff "$@" | cat

Note that all of the above works after installing the Mac OS X version of Mercurial. No further software is required (well, beyond the Mac developer tools themselves). Most of this information can be found at the Mercurial Wiki. This page and this page describe using FileMerge as a diff tool and a merge tool respectively.

Update: For completeness, here is the ".hgignore" file that I typically use:

syntax: glob

.DS_Store
*.swp
*~.nib

build

*.pbxuser
*.perspective
*.perspectivev3

Self Publishing Revlolution? Maybe.

Bill McCoy comments about the recent Wired article describing the success of a self published novel Daemon. Bill points out that ultimately Daemon only sold about 1200 copies and that in the publishing trade, sales of less than 5000 copies would be considered "misery". Further, a typical successful mid-list novel would sell 3500-7500 copies in hard cover and another 10,000 or so in paperback. Bill draws the conclusion that this suggests the rumors of the death of the trade publishing industry are greatly exaggerated.

Now, as it happens, I don't think the trade publishing houses are likely to die anytime soon, but I do think Bill is a little too certain that the disparity in sales provides as much comfort to the industry as he thinks.

Consider the situation from the author's perspective. He's written a book that he'd like to get into the hands of readers and he'd like to make some money for his trouble. He has roughly two options:

He can go the traditional route. If he can find and agent, and if that agent can sell his book, he can expect roughly $5000 as an advance against royalties. Given the typical mid-list numbers above, and a simple royalty formula of 10% of the the wholesale cost of the book, our author will either just earn out his advance or maybe see a few more dollars. In any event, his book is likely to earn him about $5-6000. And there's always the possibility that the book won't sell -- either because it's not a very good book or because the publisher didn't market it very well (something completely out of the author's control). In that case, it becomes significantly less likely that our author will be able to interest a publisher in another book.

Or, our author can self-publish as did the author of Daemon. If he can market it he might sell 1200 copies (today that'd probably be considered quite a success) It's not clear how the finances break down for Daemon, but let's assume that the author is making $3-4 per copy. With POD that's not out of line for a $15.95+SH book. At 1200 copies, he's seeing reasonably similar dollars in his pocket. Now, he's had to put significant effort into marketing (though these days it seems that the successful traditionally published authors are also doing so). On the other hand, his downside risk of harming his ability to sell future books is negligible. And he's gotten his book out there. Even if he only sells 500 copies, that's 500 more than he would have sold if he couldn't interest an an agent or a traditional publishing house as the author of Daemon couldn't.

So, what does our author do? Well, it depends. If he's got a novel that lends it self to a targetable audience (say a mystery novel that focuses on quilters and quilting) and some marketing skills, going it alone might make sense. Especially if he's got ways to leverage his book (say partnering with a quilter to sell quilt patterns based on the MacGuffin in the book). It's not for everybody, but it is an alternative. It's also an alternative that may leave him in a better position to respond to a changing market. And it gives him somewhat more control over his book.

The point is, the author of Daemon probably made as much money self publishing as he would have if he'd been published by a traditional publishing house.

Now you might say that this is no skin off the traditional publisher's nose. They'll just keep looking for the next King or Rowling and keep on keeping on. That might work. The question is, do these alternative means of distribution shrink their available pool of talent over time? And, is the woman who just bought the latest novel from that author who posts on her favorite quilting forum going to spend more money on the latest Oprah Book Club wannabe?

Professionalism

One of the unexpected benefits of my interest in the recent WGA strike was my discovery of a number of screenwriters who maintain quite interesting blogs. One such was John August, who wrote the screenplays for "Big Fish" and "Charlie and the Chocolate Factory" among others. His blog was an excellent source of information on the strike from a writer's perspective. It is also a treasure trove of information for anyone interested in the screenwriting process or story telling in general.

Mr. August has the text of a speech he gave at Trinity University in San Antonio, "Professionalism and the Rise of the Amateur", posted on his site. In it, he meditates on the distinction between "amateurs" and "professionals". The core of his thesis is that a "professional" is characterized by professional behavior more than anything else. He elaborates on that quite a bit in his speech and I recommend that you read his text.

This is relevant to me in light of the sorts of things that I've been seeking out on the Interenet of late. All of the items in my last post are, in my view, "professional" as described my Mr. August. Indeed the "New Voyages" folks specfically can't make any money (often used as the measure of a professional) lest the dogs of Paramount be set on. Money or not, the "New Voyages" episodes are done with an attention to detail and affection of the source material that would be difficult to describe as anything but professionally done.

The folks at Decoder Ring Theatre went on a marathon binge of writing and producing their shows so that their producer's pending paternity leave did not interfere with their release schedule.I was willing to start listening to "Playing for Keeps" before it had been completed because Ms. Lafferty's reputation in the Podosphere was such that I was confident that I wouldn't be left "hanging" before the story was completed.

All done very professionally despite the fact that they aren't the product of the traditional sources of media in are world, and in fact come to me very nearly directly straight from the artist's brush as it were.In a recent email to a friend, I observed that in the old equation:Talent + Discipline + Luck == Success The mechanics of the Internet are diminishing the importance of the "Luck" component. What I'm coming to realize is that that comes with a corresponding rise in the importance of the "Discipline" component. Perhaps the crux of the good that the Internet does lies in the fact that the component least under an individual's control, "Luck" is being replaced in importance by the component most under and individual's control, "Discipline". "Talent" of course, remains the wildcard.