[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
--no-zip
==> 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
CoreFoundation.
- main.m
- sets up the process group and signal handlers for the application
process
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