How to manage multiple Python versions?

If you work with Python long enough, you will find yourself in a pickle. You might want to have multiple versions of Python installed on your computer at the same time, because your OS requires one version, different version is required for your project, and another one is a requirement for that one weird library you need for whatever reason and there is no compatibility with newer version of Python.

What you can do is install all the versions you need and reference them by their version, let's say you have python 2.7, 3.6 and 3.8:

python2.7 hello.py
python3.6 hello.py
python3.8 hello.py
multiple python versions on single machine

I would say that this kind of usage is pretty common. But there is a way to make our lives easier and simpler. No more remembering which version is required for which project, making sure you and your team use the same one, having issues while running your code because you have selected the wrong version to run.

Welcome to pyenv

This interesting library allows us to have multiple Python versions installed on the system, allows us to configure Python versions per folder and also set single global version. Sounds too good to be true? Let's take a look.

Installation

This article was be written for MacOS, since it is the system I'm using (and I think it's really good for developers). You should install tools (like pyenv) and libraries using Homebrew. Homebrew is a package manager, something similar to Ubuntu's apt-get, which makes it easy to install almost everything on your system even if it requires configuration and compilation.

So we will install pyenv with Homebrew:

brew install pyenv

Yes, it is that easy. Everything is being installed and being taken care of, just sit back, relax and let brew do its thing.

Once we have pyenv installed, let's install multiple Python versions! In this example I will be showing how to install version 3.6 and 3.8, but you can list all available versions for installation with following command:

pyenv install --list

We will install version  3.8 first by running the install command:

pyenv install 3.8

And we should see something like this:

python-build: definition not found: 3.8

The following versions contain `3.8' in the name:
  3.8.0
  3.8-dev
  3.8.1
  3.8.2
  miniconda-3.8.3
  miniconda3-3.8.3

See all available versions with `pyenv install --list'.

It appears that we  have to also specify patch version number we want to install. I would argue that this is a good thing because you have to pick the exact version you want to install and use, you are in total control of your Python, however that also means no automatic update to the latest version.

Ok then, install version 3.8.2 and check if it's registered in pyenv:

pyenv install 3.8.2

You should see a list similar to this one (note I have used pyenv before and my output might differ from yours as it's fresh installation of pyenv):

pyenv versions
* system (set by /Users/martin/.pyenv/version)
  3.8.2

Let's install also version 3.6.9 and check versions again:

pyenv install 3.6.9
pyenv versions
* system (set by /Users/martin/.pyenv/version)
  3.6.9
  3.8.2

Now we can set different Python versions for different folders, and we can also switch global version (default version when there is no specific local version in a folder). Let's do that now, let's make 2 new folders and set different python version for each one of them:

cd ~
mkdir version1 && cd $_
pyenv local 3.6.9
python

Python 3.6.9 (default, Jun 10 2020, 01:11:21) 
[GCC 4.2.1 Compatible Apple LLVM 11.0.3 (clang-1103.0.32.62)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
folder with Python 3.6.9
cd ~
mkdir version2 && cd $_
pyenv local 3.8.2
python

Python 3.8.2 (default, Jul 18 2020, 20:10:28) 
[Clang 11.0.3 (clang-1103.0.32.62)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
folder with Python 3.8.2

You can see that with command "pyenv local VERSION" you can set any arbitrary installed Python version in a folder. It actually creates invisible file named ".python-version" in that folder, so if you want you can include it in your repository and your entire team will now be using the same python version when executing code in that folder (they have to have pyenv installed as well of course).

I want to quickly mention that you can also set your default global Python interpreter version with this command:

pyenv global 3.6.9

Also you can set version for your current shell instance:

pyenv shell 3.6.9

As you can see pyenv is really good at managing Python versions. If you want to know how it does it in the background, you can read more about it here. It is very powerful tool for Python development and really useful one if you need to have multiple versions installed at once and switch seamlessly between them. I personally use it everywhere, but it is kind of configure-once-and-forget-about-it type of tool, which is the best kind I think. Simple, powerful and yet unobtrusive. It does its thing and let's me do my work effectively.

How do you like pyenv? How do you manage your Python version installations? Let me know in the comment section below!

M.