aaron maxwell

env and python scripts: controlling the python version

On Unix-like systems, python scripts will often start with this line:

#!/usr/bin/env python

How can you manually test this script under different versions of Python?

This "env-shebang" idiom effectively selects the primary Python interpreter installed on the user's system, at script execution time. On any given system, this will resolve to a particular version of Python. For instance, on stock Debian Lenny GNU/Linux, it's Python 2.5; the first python in the default path is /usr/bin/python, which is a symbolic link to /usr/bin/python2.5.

Now, if you're developing a Python script that is supposed to work on several different Python versions, and want to test it under each, the "env-shebang" idiom can get in your way. Temporarily editing the file, to change the argument to env, may do the trick. But that's error prone and difficult to automate.

So here's a better solution.

Let's say you want to test under Pythons version 2.5, 2.6 and 2.7, and you already have an interpreter for each version installed. For example, on my current development machine, python 2.7 is at $HOME/opt/python2.7/bin/python2.7, python 2.6 is at /usr/bin/python2.6, and python 2.5 is at /usr/bin/python2.5.

What you can do is create a subdirectory for each version in some convenient location. I name them like "env_pythonX.Y" and just place them under $HOME/bin (where X and Y are the major and minor version numbers). Then, inside each of these directories, make a symbolic link named "python" to the appropriate version.

Again using my dev machine as an example, $HOME/bin/env_python2.7/python is a symbolic link to $HOME/opt/python2.7/bin/python2.7, $HOME/bin/env_python2.6/python is a symbolic link to /usr/bin/python2.6, and $HOME/bin/env_python2.5/python is a symbolic link to /usr/bin/python2.5.

Now you're prepared. To run the script program.py from the Unix command line, using (say) python version 2.6, just define the PATH so that $HOME/bin/env_python2.6/python is first. At the prompt, you can type something like:

PATH=$HOME/bin/env_python2.6:$PATH ./program.py

Here, I've used a syntax provided by most modern shells for per-command variable assigments. Prepending a command with FOO=BAR means "Run the command in an environment where the variable FOO has the value BAR". This conveniently lets us set the search path to produce our python, for just that one invokation.

This is easy to repeat with the others. To manually run the script with each Python version in sequence, use this series of commands:

PATH=$HOME/bin/env_python2.7:$PATH ./program.py
PATH=$HOME/bin/env_python2.6:$PATH ./program.py
PATH=$HOME/bin/env_python2.5:$PATH ./program.py

Of course, this is all highly automatable in your test scripts.

By the way, if the symbolic link is wrong, a different python version may be silently used. You can quickly verify with python -V:

PATH=$HOME/bin/env_python2.6:$PATH python -V

This should emit something like Python 2.6.5.

You're all set. Now get to testing!