Managing Multiple Versions of Python on Ubuntu 20.04

Managing Multiple Versions of Python on Ubuntu 20.04

Easily install and manage multiple versions of Python on Ubuntu 20.04 or newer.

Todd Birchard
Todd Birchard
notice-icon

There are a number of subtle differences in managing versions of Python on older distributions of Ubuntu. If you're running Ubuntu 18.04 or older, go here.


One of my earliest frustrations with Python development had nothing to do with Python itself but rather the needlessly esoteric act of deploying a Python app. Code boot camps and tutorials do a fine job of teaching students how to run Python code locally, but the most meaningful applications don't run on local machines: they run on servers, on the internet, because that's the point, isn't it? Maybe I'm taking crazy pills here.

Ubuntu 20.04 is the first LTS version of Ubuntu to drop Python2, coming fresh out of the box with Python 3.8.5. But what if you've written apps intended for a newer version of Python? If you're like me, you might have tried to replace your system's default installation and destroyed your machine in the process. If nobody has warned you, I'll do the honors: don't do that.

The risk of unintended destruction is only one of many unintuitive details that complicate the seemingly simple task of using an updated version of Python:

  • apt upgrade does not apply to versions of Python. In fact...
  • Newer Python distributions aren't even visible to apt; thus, we can't even use apt update to find a more recent version of Python without the help of a third party.
  • Versions of Python installed on the same machine do not share the same core features (such as pip), which leads to a lot of confusion.

What do we do?

Using Ubuntu's built-in alternative install is optimal for several reasons:

  1. We can install a new version of Python in parallel to the version of Python Ubuntu depends on, so we don't ruin our machine.
  2. It's best to avoid messing around with your Python PATH whenever possible.
  3. We can easily switch the active version of Python on our machine via a convenient CLI.

We're going to walk through how to install the latest version of Python alongside Ubuntu's system Python versions safely and (relatively) easily.

Python via Deadsnakes

Deadsnakes PPA is an actively maintained repository of Python distributions available to Ubuntu. Deadsnakes carries the burden of hosting versions of Python that have been tried and tested to work on Ubuntu, (their Github organization is essentially a collection of Ubuntu-friendly Python versions).

By adding the Deadsnakes PPA, we're making these Python versions visible to our Ubuntu machines:

$ sudo add-apt-repository ppa:deadsnakes/ppa
Add the deadsnakes repository

Upon adding this repository, you'll immediately receive a prompt explaining this in verbose terms. Press enter to move on.

This PPA contains more recent Python versions packaged for Ubuntu.

Disclaimer: there's no guarantee of timely updates in case of security problems or other issues. If you want to use them in a security-or-otherwise-critical environment (say, on a production server), you do so at your own risk.

Update Note
===========
Please use this repository instead of ppa:fkrull/deadsnakes.

Reporting Issues
================

Issues can be reported in the master issue tracker at:
https://github.com/deadsnakes/issues/issues

Supported Ubuntu and Python Versions
====================================

- Ubuntu 18.04 (bionic) Python2.3 - Python 2.6, Python 3.1 - Python 3.5, Python3.7 - Python3.11
- Ubuntu 20.04 (focal) Python3.5 - Python3.7, Python3.9 - Python3.11
- Ubuntu 22.04 (jammy) Python3.7 - Python3.9, Python3.11
- Note: Python2.7 (all), Python 3.6 (bionic), Python 3.8 (focal), Python 3.10 (jammy) are not provided by deadsnakes as upstream ubuntu provides those packages.

Why some packages aren't built:
- Note: for focal, older python versions require libssl<1.1 so they are not currently built
- Note: for jammy, older python versions requre libssl<3 so they are not currently built
- If you need these, reach out to asottile to set up a private ppa

The packages may also work on other versions of Ubuntu or Debian, but that is not tested or supported.

Packages
========

The packages provided here are loosely based on the debian upstream packages with some modifications to make them more usable as non-default pythons and on ubuntu.  As such, the packages follow debian's patterns and often do not include a full python distribution with just `apt install python#.#`.  Here is a list of packages that may be useful along with the default install:

- `python#.#-dev`: includes development headers for building C extensions
- `python#.#-venv`: provides the standard library `venv` module
- `python#.#-distutils`: provides the standard library `distutils` module
- `python#.#-lib2to3`: provides the `2to3-#.#` utility as well as the standard library `lib2to3` module
- `python#.#-gdbm`: provides the standard library `dbm.gnu` module
- `python#.#-tk`: provides the standard library `tkinter` module

Third-Party Python Modules
==========================

Python modules in the official Ubuntu repositories are packaged to work with the Python interpreters from the official repositories. Accordingly, they generally won't work with the Python interpreters from this PPA. As an exception, pure-Python modules for Python 3 will work, but any compiled extension modules won't.

To install 3rd-party Python modules, you should use the common Python packaging tools.  For an introduction into the Python packaging ecosystem and its tools, refer to the Python Packaging User Guide:
https://packaging.python.org/installing/

Sources
=======
The package sources are available at:
https://github.com/deadsnakes/

Nightly Builds
==============

For nightly builds, see ppa:deadsnakes/nightly https://launchpad.net/~deadsnakes/+archive/ubuntu/nightly
 More info: https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa
Press [ENTER] to continue or Ctrl-c to cancel adding it.
Deadsnakes prompt explaining usage

To pick up the versions of Python that Deadsnakes makes visible to us, we still need to run a quick update:

$ sudo apt update
Update packages visible to Ubuntu

Now check to see if the version of Python you're looking for is available for download like so:

$ apt list | grep python3.x
Check for your desired version of Python

If available, you'll see an output like so:

$ apt list | grep python3.9

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

idle-python3.9/focal 3.9.12-1+focal2 all
libpython3.9-dbg/focal 3.9.12-1+focal2 amd64
libpython3.9-dev/focal,now 3.9.12-1+focal2 amd64 [installed,automatic]
libpython3.9-minimal/focal,now 3.9.12-1+focal2 amd64 [installed,automatic]
libpython3.9-stdlib/focal,now 3.9.12-1+focal2 amd64 [installed,automatic]
libpython3.9-testsuite/focal 3.9.12-1+focal2 all
libpython3.9/focal,now 3.9.12-1+focal2 amd64 [installed,automatic]
python3.9-dbg/focal 3.9.12-1+focal2 amd64
python3.9-dev/focal,now 3.9.12-1+focal2 amd64 [installed]
python3.9-doc/focal 3.9.9-1+focal2 all
python3.9-examples/focal 3.9.12-1+focal2 all
python3.9-full/focal 3.9.12-1+focal2 amd64
python3.9-minimal/focal,now 3.9.12-1+focal2 amd64 [installed,automatic]
python3.9-venv/focal,now 3.9.12-1+focal2 amd64 [installed]
python3.9/focal,now 3.9.12-1+focal2 amd64 [installed,automatic]
Confirm your version of Python exists for download

That's our green light! Go on and proceed to install Python:

$ sudo apt install python3.9
Install Python3.x

Managing Alternative Python Installations

We now have two versions of Python installed on our machine: the system default Python 3.8.5, and our newly added Python 3.9.2. We want to leave our system default Python installation alone, but we want to run our apps written in Python 3.9... so how do we manage this?

Linux has us covered in this scenario with the update-alternatives command. We can tell Ubuntu that we have many alternative versions of the same software on our machine, thus giving us the ability to switch between them easily. Here's how it works:

$ update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1
$ update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 2
Set alternative versions for Python

We ran update-alternatives twice: once for Python 3.8, and once for Python 3.9. So now we can use update-alternatives --list [package name] to list all the alternative installations we have installed:

$ update-alternatives --list python3
/usr/bin/python3.8
/usr/bin/python3.9
List installed versions of Python

Now we can swap between versions of Python! Run the following:

$ update-alternatives --config python3
Swapping between versions

You should be hit with a prompt like the one below. This will list all the versions of Python your system recognizes. Select the version of Python you'd like to use by providing the "selection" number to the prompt:

There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                      Priority   Status
------------------------------------------------------------
  0            /usr/bin/python3.9   2         auto mode
* 1            /usr/bin/python3.8   1         manual mode
  2            /usr/bin/python3.9   2         manual mode

Press <enter> to keep the current choice[*], or type selection number:
CLI for switching active Python version

To switch Python versions, all you need is to respond to the above prompt with the selection number representing the Python version you want to use.

We've done the "hard" part, but there's a bit of housekeeping to take care of.

Finishing Touches

The version of Python we just enabled is a brand new installation, meaning there are a few critical pieces we still need to set up. For whatever reason, Python does not ship with its package manager (pip) included. Nor does it ship with distutils (necessary for installing older Python modules) or venv, Python's virtual environment manager. Let's take care of it.

First, we'll need to reinstall python3-apt with our new version of Python active:

$ sudo apt remove --purge python3-apt
$ sudo apt autoclean
$ sudo apt install python3-apt
Reinstall python3-apt for your alternative Python installation

Next we'll add distutils:

$ sudo apt install python3.9-distutils
Install distutils

And of course, pip:

$ apt install python3-pip
$ python3.9 -m pip install --upgrade pip
Install pip

Lastly, venv will need to be reinstalled as well:

$ sudo apt install python3.9-venv
Install venv

You Did It

As absurd as it sounds, successfully updating Python on Ubuntu is a legitimate accomplishment. I've witnessed software developers of all backgrounds struggle with dumb things like "setting up Python." Some tasks are unintuitive and lack any conventional patterns or logic. Updating Python on Ubuntu is one of those tasks.

You've managed to prevail, so congratulations are in order. If you're new to Python, please don't be discouraged by how weirdly complicated this was. The miserable journey we've just embarked on is no indication of what software development is like... or any related profession, for that matter. From here on out, it's sunshine, rainbows, and snakes 🐍.

DevOpsArchitecturePython

Todd Birchard

Engineer with an ongoing identity crisis. Breaks everything before learning best practices. Completely normal and emotionally stable.