Supporting Multiple Python Versions with Tox on OS X

Screenshot of Python code distorted and warped

I recently started developing some Python packages and wanted to be able to test my code with multiple Python versions: 2.6, 2.7, 3.3, 3.4, and 3.5. I already had the OS X system Python, which was version 2.7, plus I had a /usr/local/bin install of Python from Homebrew, and then I ran Enthought Canopy with Python 2.7 on top of that. Needless to say, I didn’t want to mess up my existing setup, I just wanted to have the other versions of Python available to Tox when testing my package. I already added multiple Python versions to my tox.ini, but they didn’t exist on my system yet:

[tox]
envlist = py26, py27, py33, py34, py35

Installing Python 2.6, 3.3, 3.4, and 3.5 as “alternative installs” of Python is a fairly simple solution, although there doesn’t seem to be a consensus about how this should be done, with examples using Macports, pyenv, and other tools. Here’s how you do it the good ‘ol clean way:

First, we need to install Xcode command line tools so we can get zlib. If Python is not compiled with zlib Tox will not be able to create its virtualenvs. We also need to ensure we have openssl, and probably readline, then we can download and compile a specific version of Python.

xcode-select --install  # Get zlib and other nonsense
brew install readline  # Worth a try
brew install openssl
export CPPFLAGS=-I$(brew --prefix openssl)/include; export LDFLAGS=-L$(brew --prefix openssl)/lib
wget https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz
tar xfz Python-3.4.3.tgz
cd Python-3.4.3

Next, open setup.py, find the line that begins {python inline=”true”}search_for_ssl_incs_in = {/python} and add {python inline=”true”}/usr/local/opt/openssl/include/{/python} to that list. This is the path to your Homebrew openssl, which you’ll need to compile Python. Exporting the CPPFLAGS above should do this trick, but I found I had to modify setup.py, as well.

The {bash inline=”true”}–prefix=/usr/local{/bash} line below configures this version of Python to be installed in the /usr/local/bin folder, so that folder needs to be in your {bash inline=”true”}$PATH{/bash}; if you’re using Homebrew, it already is. Next, and critically, rather than using {bash inline=”true”}sudo make install{/bash} we use {bash inline=”true”}sudo make altinstall{/bash}, which prevents your existing {bash inline=”true”}python{/bash} executable from being overwritten.

./configure --prefix=/usr/local
make
sudo make altinstall
sudo chown -R Nikhil:staff /usr/local/  # Replace username

# Test that it works
mkvirtualenv test -p /usr/local/bin/python3.4

Multiple versions of Python can be installed using this same method. They will be installed to /usr/local/bin/pythonX.Y, where X.Y corresponds to the version number. To run Python 3.4, simple run {bash inline=”true”}python3.4{/bash} in your Terminal. Tox should now have access to these alternative versions of Python, as well.

If you have already run Tox, then you’ll might need to recreate the virtualenv: {bash inline=”true}tox –recreate -e py34{/bash}. Or to recreate them all, use {bash inline=”true”}tox –recreate{/bash}. As of virtualenv version 13.something, Python 3 virtualenvs created with Python 2.x will fail, so revert back to virtualenv==12.0.2 to ensure you can create and test with Python 3.Y virtualenvs.

About the author

I like learning, programming, and creating. I'm an incessant problem solver, and have an insatiable desire to absorb information. I'm an information sponge. A critical thinker. My left brain and right brain function as one. Business and technology should be one. I invest based on opportunity or technicals, whichever is right. I never let my schooling interfere with my education. Marketing is not fluff, it is data-driven. I find patterns, and analyze the random. I like to teach and explain.

Leave a Reply