Dealing with multiple python versions when python files have to use #!/bin/env python

dana picture dana · Jul 3, 2012 · Viewed 10.9k times · Source

I have this problem:

System A runs Ubuntu and needs Python 2.6 for a bunch of different things.
I Installed Python 2.7 separately on System A
System B has Python 2.7 natively.

I have a python script BLAH which says #!/bin/env python up top.
Further down it executes another script SIGH, which up top also says: #!/bin/env python.

BLAH needs to run on either System A or System B, and it always needs to run Python 2.7

----
Part of my solution so far:
Have a wrapper script that first tries to see if which python is pointing to Python 2.7
If that's okay then run BLAH with that path for python.
Else try which python2.7 and use that path to run BLAH , and add that path to env PATH.

Problem with this solution is:

On System A (which has Python 2.7 installed separately)
When BLAH executes, it runs with Python 2.7 because of the wrapper script I wrote (okay so far..)
When BLAH spawns SIGH, SIGH uses the shebang to find python in the path and then it's in trouble because it's looking for python in env's PATH and it should be looking for python2.7 in the path.

Is there a clean way of handling this problem?

Thanks in advance!

Answer

jedwards picture jedwards · Jul 4, 2012

If you have a script that needs a certain python version, for example 2.7, I'd change the first line to

#!/bin/env python2.7

And then ensure that python2.7 is on your path (you may have to add symlinks as appropriate). In all the distributions I've used, these symlinks already exist.

(In fact, python is typically a symlink to pythonX which is a symlink to pythonX.Y or, in my case, python -> python2 -> python2.7. )

There's no need to hard-code a full path, as this may vary from distro to distro or box to box.

But since there should be no ambiguity for an executable on your path named python2.7, you should be fine without having to worry about hard-coding paths.

Alternatively, from within the first script, you could call the python interpreter directly, as in:

subprocess.Popen(['pythonX.Y', SCRIPT_NAME])

instead of

subprocess.Popen([SCRIPT_NAME])

EDIT As J.F. Sebastian notes in the comments, you could use sys.executable in the first argument to ensure that the second script was passed to the same interpreter as the first. e.g

subprocess.Popen([sys.executable, SCRIPT_NAME])

As a side note, that may or may not be useful, you can access the version of the "current" Python interpreter inside the script by

import sys
print(sys.hexversion)

which may be useful to determine whether the correct interpreter is running.