A workaround for the Python module search path issue on Unix

August 8, 2008

One of the little challenges with writing Unix programs in Python is the search path problem. The natural structure of Python programs is to split functionality up into a bunch of modules and then import them all in the main program, but the natural structure of a Unix program is to put its binary into one directory (such as /usr/bin) but all of its helper bits into a second, completely different directory. So the problem is: how is a Unix Python program supposed to find its modules?

(The normal Python search path for import is the directory that the program is being run from, such as /usr/bin or $HOME/bin, and the system Python package areas.)

The obvious solution is to have your program start off by adding its module directory to sys.path. The problem here is that this is an installation dependent location, which means that you're customizing your main program each time it gets installed. I dislike this and find it ugly, plus I maintain that overriding sys.path gets in the way of a number of things and can cause subtle problems.

It turns out that there is a simple workaround, hinted at by the aside there: put the Python main program into its library directory along with the rest of its modules, and turn the command that gets installed into the binary directory into a tiny shell script that is just:

#! /bin/sh
exec /where/ever/prog.py "$@"

This results in the library directory being added to the search path, because it is the directory that the actual Python program is being run from. (And you can be confidant that Python will know what that is, since the program is being started by absolute path.)

It is easy to create this tiny shell script as part of your installation process (when you're sure to know where the library directory is, since you are about to put things in it). As a bonus, your main program can still have a .py extension so that you can easily do things like check it with pychecker or import it into an interpreter to poke at something.

(Credit where credit is due: I didn't invent this trick. I believe I first saw it being used by a Python program on Fedora or one of the pre-Fedora Red Hat version.)


Comments on this page:

By Dan.Astoorian at 2008-08-08 09:59:06:

I've found that it is, in fact, sufficient to use a symbolic link: if /usr/local/bin/foo is a symbolic link to /usr/local/myapp/foo.py, then it's /usr/local/myapp (not /usr/local/bin) which gets added to sys.path when /usr/local/bin/foo is run.

--Dan

Written on 08 August 2008.
« The pragmatics of language changes
How to exploit unsigned repository metadata »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri Aug 8 00:23:47 2008
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.