2011-05-29

Snow Leopard, wxPython and py2app

As I write this blog post I'm happy to say that I have finally managed to get a new build of the QTIMigration tool on OSX, however this post is not about the migration tool so much as the process of getting the binaries built on a Snow Leopard-based machine.


The QTIMigration app runs in either GUI or command-line mode.  The GUI is based on wxPython which does not run well on 64-bit python builds.  The GUI part was written by Pierre and hasn't been changed in 3 years, in 2008 we had no trouble using py2app to bundle up a binary distribution.


In Snow Leopard, the default python interpreter runs in 64 bit mode.  It takes a bit of fiddling but it is relatively straightforward to check out the migration tool source and run it from the terminal forcing the interpreter into 32bit mode to satisfy wxPython.  I found this stackoverflow thread helpful in understanding the issue and ended up with a little script like this on my path:


#! /bin/bash
arch -i386 /usr/bin/python2.6 "$@"

I called the above script python32 (which seems dumb now that python3.2 is out) and it works well enough.

So to build the binary distribution, in theory, all I need to do is run py2app from the command line...

python32 setup.py py2app

Unfortunately, the resulting app fails when run with an unusual error about a missing attribute:

AttributeError: 'module' object has no attribute 'TickCount'

The error can be found on the system console.  As ever, someone has experienced the problem before (for example, see this post) but the real solution lies in the sage advice that the best way to run py2app is to use a standard python distribution from python.org and to ignore the one that came with the original OSX.  Furthermore, if you want to create applications that will run in 32bit mode you need to install the 32bit architecture version of python.

So I downloaded python-2.7.1-macosx10.3.dmg and installed it.  Fortunately there is no python2.7 on Snow Leopard so there is no problematic name clash to resolve.  I also installed setuptools by downloading setuptools-0.6c11-py2.7.egg (note that this uses whatever python python2.7 points to).  Then I installed wxPython from wxPython2.8-osx-unicode-2.8.12.0-universal-py2.7.dmg.  There doesn't seem to be a way of forcing the wxPython install to use a particular python but again, it seemed to find its way into my new python2.7 install without difficulty.  At last, I was ready to install the other modules needed by the migration script, including py2app.

To avoid confusion I extracted the tars manually and ran each of the add-in modules setup.py script using:

python2.7 setup.py install

This step included installing the new pyslet package I'm working on and its dependencies.

Finally, I was able to re-run the py2app package step using my new python environment:

python2.7 setup.py py2app

The resulting binary worked!  Although I no longer have an older Mac to properly test the compatibility of the new binary I could at least test it worked on a machine that hasn't had the custom python build applied.

I guess all this extra complexity has at least helped to test out the code a bit more thoroughly.  I was pleased that the unit tests for pyslet all ran fine on python2.7.  Unfortunately the migration tool itself has a bug when handling non-ascii file names.  This is because my python2.7 environment is now capable of using unicode strings for file names but at one point in the migration code I'm using the old urllib.pathname2url which chokes on my chinese examples (as they have chinese filenames).  I believe this behaviour is different from the built-in python on Snow Leopard, but either way there is no easy fix and it looks like I'll have to wrap or replace my use of this function before I can post the new OSX binaries.

Watch this space, I feel like I'm getting close to a new binary distribution now.