Managing Python environments with pyenv

We all love Python - it’s a fantastic language, however managing installed packages can be a pain. How many times have you ran sudo pip install or sudo python setup.py install, and ended up conflicting with your system pacakage manager, or had some obscure import error because you accidentally installed multiple versions of the same package in different places?

The standard solution for this is to install Python packages into virtualenvs, within which we can install whatever packages we want without impacting the rest of the system. Once virtualenv is installed through pip, you can create virtualenvs anywhere with virtualenv myenv and then activate them with source myenv/bin/activate, however we are still left to manage our own set of environments, and virtualenv does not help us easily manage different Python versions. That’s where pyenv and pyenv-virtualenv come in.

pyenv

pyenv is a great tool for installing and managing different Python versions. To install it, use brew on Mac or install manually. You’ll then need to add the following line to your ~/.bashrc or similar to enable pyenv:

eval "$(pyenv init -)"

You can then start by listing all the available Python interpreters with:

pyenv install --list

You can see that many versions are available there, not just from the standard CPython but also anaconda, pypy and others. The standard CPython interpreters are the non-prefixed ones at the top of the list. To install one of these versions, run pyenv install with the desired version number, e.g.:

pyenv install 3.5.2

You can then set it as your default Python interpreter (instead of your system version) with:

pyenv global 3.5.2
python --version # 3.5.2

You can also override the default version temporarily in a single shell with pyenv shell, e.g.:

pyenv install 2.7.12
pyenv shell 2.7.12
python --version # 2.7.12

Another really useful feature is pyenv local, which allows you to configure a default Python interpreter for a particular directory tree. This allows you to use a different Python version automatically for different projects. In the following example, the default Python 3 interpreter is overridden inside the project directory with a Python 2 interpreter:

pyenv global 3.5.2
mkdir project
cd project
pyenv local 2.7.12
python --version # 2.7.12
cd ..
python --version # 3.5.2

pyenv-virtualenv

pyenv does a great job of managing different Python interpreters for you, but it still doesn’t provide a convenient way of encapsulating different sets of libraries in the way that virtualenv does. That’s where pyenv-virtualenv, a pyenv plugin, comes in.

To install pyenv-virtualenv, again either use brew on Mac or install manually. As with pyenv, you’ll need to add the following line to your ~/.bashrc or similar to enable pyenv-virtualenv:

eval "$(pyenv virtualenv-init -)"

You can then make a new virtualenv with an installed Python interpreter version:

pyenv virtualenv 3.5.2 myenv

You can then see a list of all installed virtualenvs with:

pyenv virtualenvs

You can explicitly enable and disable virtualenvs with pyenv activate <virtualenvname> and pyenv deactivate, and use the global and local features of pyenv with virtualenvs as the argument:

pyenv local myenv

This is a really convenient feature - I use it to set up a new empty virtualenv for each Python project I’m working on, with a name matching the project, then set it as the local default when inside that project directory. This means I can install what I like inside that project without worrying about other projects, and make sure that all the necessary dependencies are retrieved when using the project’s installation helper(s).

In summary, I hope you’ll agree that pyenv and pyenv-virtualenv are a great pair of tools to lift a lot of burden from managing Python interpreter versions and virtualenvs. Personally, I’m looking forward to saving a lot of time and effort in managing my Python environment in the future!