Installing multiple versions of Python with Pyenv

I write a lot of stuff in Python – some of it useful, some of it… not so useful. But as a relative newcomer to Python, it’s almost always in Python 3. Most modern Linux distributions come with Python 3, so what’s the problem?

Although yes, a lot of distributions do come with a version of Python 3, it’s often an older version. It’s not uncommon to see 3.4 installed, which can be a problem if you’re relying on the newer ways of using async in 3.5+“Okay”, you say. “I can just build the newer version of Python 3 and install it alongside the system-provided one”. At that point, a large hand appears out of nowhere and slaps you across the side of the head. A loud voice, reminiscent of Death from the Discworld series, booms:-


Jack Nicholson in The Shining
Terrifyingly accurate representation of what yum will do if you change the version of Python on it

You look at your cup of coffee and wonder if someone slipped something into it when you weren’t looking, but there’s a serious point here – messing around with the system-installed versions of Python is a recipe for a world of hurt. There’s a fair few system utilities that are written in Python, and the distribution maintainers are doing their job by ensuring that the correct version of Python gets installed along with them. While it’s definitely possible to install a newer version of Python system-wide, it’s often not worth risking the potential for subtle fuckery if your newly-installed version of Python ends up being used for something that didn’t expect it.

Side note: at this point I should clarify that the imaginary situations I’m referring to here are when you need a particular version of Python for development. Making a new version of Python available for services deployed in production is definitely a problem you might run into, but is a topic for another post.

So what to do? Luckily, there’s a relatively straightforward way to make pretty much any version of Python available to you – and only you. Enter pyenv.

pyenv lets you easily switch between multiple versions of Python. It’s simple, unobtrusive, and follows the UNIX tradition of single-purpose tools that do one thing well.

This project was forked from rbenv and ruby-build, and modified for Python.

I won’t go over the installation instructions because I’d just be repeating the clear and concise instructions the pyenv project already has, but here’s what it’ll let you do:-

  • have multiple versions of Python installed at once – both Python 2 and Python 3
  • have multiple implementations of Python installed at once – for instance, Jython or Pypy alongside the standard CPython
  • set the version of Python in use on a per directory basis
  • set the global – for you – version of Python in use if you don’t otherwise specify a version

It does this by using shims – that is, inserting itself in your path and making sure that when you – or your application – calls the Python interpreter it will get the version that you intended it to get. It’s a lot safer than installing a version of Python system-wide, it doesn’t need root[0] and there’s no endless manual fucking around with PATH or LD_LIBRARY_PATH. It’s so useful that I even have the following in my dotfiles repo[1] I drag around between systems I work on:-


function install-pyenv() {
  if [[ ! -d ~/.pyenv ]]; then
    echo "Downloading pyenv..."
    git clone ~/.pyenv
    . ~/.bashrc
    echo "~/.pyenv already exists!"

if [[ -d ~/.pyenv ]]; then
  echo "~/.pyenv found, initialising pyenv..."
  export PYENV_ROOT="$HOME/.pyenv"
  export PATH="$PYENV_ROOT/bin:$PATH"

  eval "$(pyenv init -)"

This lets me just run install-pyenv on a system I haven’t already installed it on, and it will pull pyenv from GitHub and then do the things it needs to make it available in my session. Far nicer than being slapped around the face by a character from a fantasy novel series.

[0] while you don’t need to be root to install pyenv, since it will build the version of Python from source you may need to install additional packages (such as gcc) if they aren’t already installed.
[1] one of these days I will tidy it up enough to make it publicly-available, but it doesn’t do anything that these public projects already do, and probably do better.