[Pythonmac-SIG] Tips for using Python scripts from OS X apps

Sarwat Khan sarwat at sarwat.net
Sun Oct 19 17:32:34 EDT 2003

I've released the latest version of my port of BitTorrent to Mac OS X, 
which has an Objective-C Cocoa front-end GUI and a Python back-end 
BitTorrent implementation. I thought I'd share some of the stuff I did 
as it's useful to anyone who wants to use /usr/bin/python on Mac OS X 
to run Python scripts in their OS X programs. I expect this post to be 
mostly one for the archives :)

When I first shipped the thing, I shipped it with .pyo files for Python 
2.2. These don't work on Python 2.3, which comes with Panther. After 
thinking about it for a while, I decided that what I want to do is 
include optimized code for both py2.2 and py2.3, as well as include the 
raw source code in case if the user has a version of Python that I 
don't expect. Python 2.3+'s zipimport module makes this feasible.

When BitTorrentAgent initializes, it first reads a plist which 
describes the various optimized packages that are installed with the 
application. It compares this with /usr/bin/python, and then sets up 
some globals to make sure that things run smoothly, so that it uses the 
correct package for /usr/bin/python.

The process of generating this plist is done by a script. You use it 
like this,

% python2.3 BitTorrentAgent/Scripts/DefineInterpreters.py define
==> Defined python2.3 zipimport: 1

% python2.2 BitTorrentAgent/Scripts/DefineInterpreters.py define 
==> Defined python2.2 zipimport: 0

Defining an interpreter does two things. In addition to generating the 
plist for use by BitTorrentAgent's initialization routine, it maintains 
another dictionary that maps, for example, python2.3 <==> 
/usr/local/bin/python2.3. A Project Builder Build Phase uses this 
dictionary to compile the .py files into .pyo files when creating the 
optimized python2.3 package.

The point of describing all of this is just to say that it's automated. 
You tell the one script which versions of python you want optimizations 
for and what kind of output you want (zip or no zip, zip is the 
default), and the build process will put those optimized packages into 
the build product's bundle for you. When your build product executes, 
it will read the generated plist and pick the right package for the 
user's python. If there is no optimized build for the user's python, it 
falls back to the raw source code.

All the code and scripts in the BitTorrentAgent stuff that handles this 
is in the following files,

- btagent.h
- btagent_posix.c
	- implementation of btagent.h using posix API.
	- forks python, shuts down python, reads and writes to and from stdio 
with it.
- btagent_posix_cf.c
	- implementation of btagent.h using posix and CoreFoundation API
	- This contains the initialization routine that reads the plist using 
- main.m
	- sets up the process group and signal handlers for the application 

None of that is really specific to BitTorrent and the techniques can be 
applied to any app that needs to work with Python scripts. The scripts 
that manage the build process are the following,

- BitTorrentAgent/Scripts/DefinePythonInterpreters.py
	- Lets you define and undefine Python executables and list their 
configured options
- BitTorrentAgent/Scripts/InstallBitTorrentModules.py
	- Copies code from hard-coded source code directories and compiles 
them for each defined python interpreter with their configured options. 
Called during a build phase.

The last thing worth mentioning is that the latest release of my 
BitTorrent port has BitTorrentAgent as a framework. That means you can 
embed BitTorrentAgent.framework into your applications and include 
BitTorrent seeding/downloading functionality. All without needing to 
rewrite BitTorrent into a C++ library, which so many people seem to be 
fond of doing...

You can get the source from http://sarwat.net/opensource/

{sarwat khan : http://sarwat.net}

More information about the Pythonmac-SIG mailing list