Install Python 3.9 on Raspberry Pi OS or Debian 10 (for Ansible or other uses)

I've started getting a lot of bug reports on my repos to the effect of "Ansible won't install on my Raspberry Pi anymore". Accompanying it is a debug message like one of the following:

$ python3 -m pip install ansible
...
No matching distribution found for ansible-core<2.13,>=2.12.0 (from ansible)

# Alternatively:
ERROR: No matching distribution found for ansible-core<2.13,>=2.12.0

The problem is ansible-core 2.12 has a new hard requirement for Python 3.8 or newer. And ansible-core 2.12 is included in Ansible 5.0.0, which was recently released. Raspberry Pi OS, which was based on Debian 10 ("Buster") until recently, includes Python 3.7, which is too old to satisfy Ansible's installation requirements.

There was recently a fix that makes it so Ansible 5.x won't get installed on these older systems, but who wants to get stuck on old unsupported Ansible versions?

There are three options:

  • Stick with Ansible 4.x or earlier
  • Switch to Debian 11 "Bullseye" (download the latest version of Pi OS) or another newer OS that has Python 3.8 or later by default.
  • Install at least Python 3.8

Workaround: Stay on Ansible 4.x

The easiest workaround for now is to install the latest version of Ansible 4, which uses ansible-core 2.11, which is compatible with the version of Python (3.7) that ships with Debian 10 Buster. To do that, run:

$ python -m pip install --user ansible==4.9.0

That should work, and as long as you don't try upgrading to Ansible 5, you'd have a stable (if no longer supported) version of Ansible running.

Best fix: Install Python 3.9

It's best to upgrade Python so you can install the latest version of Ansible cleanly. Unfortunately for those with older OSes that don't have a pre-packaged version of Python available, you will need to either deal with the complexity of pyenv, or build a newer version of Python from source.

If you're running Debian 10 or the slightly-older version of Raspberry Pi OS based on it, you can still install Python 3.9 using apt, but you'll need to update your 'apt sources' to pull down a newer version of Python.

Edit /etc/apt/sources.list:

$ sudo nano /etc/apt/sources.list

Then add the following line to the bottom of the file and save it:

deb http://http.us.debian.org/debian/ testing non-free contrib main

Now, to install Python 3.9, run:

$ sudo apt update
$ sudo apt install -y python3.9

Now you should start seeing a Python 3.9 version installed:

$ python3 --version
Python 3.9.9

And you can now install the latest version of Ansible without an issue:

$ python3 -m pip install ansible

Note: If you get an error like AttributeError: 'HTMLParser' object has no attribute 'unescape', try running python3 -m pip install --upgrade setuptools and then try installing Ansible again (thanks to this answer for the solution). You may also get an error like can't find Rust compiler'—if so, also runpython3 -m pip install --upgrade pip` and then try installing Ansible again.

Note 2: Please read through the first few comments below for suggestions on how to do this while also pinning the change to just Python—if you don't do that, you could end up upgrading a lot of other packages unintentionally, leading to system breakage!

Now verify that Ansible's installed:

$ python3 -m pip freeze
ansible==5.0.1
ansible-core==2.12.0
cffi==1.15.0

Comments

The steps to install Python 3.9 can have an unintended side-effect of updating other packages on the system from testing. This can be avoided if one creates a file, say, /etc/apt/preferences.d/90_python3, with the contents:

Package: *
Pin: release a=testing
Pin-Priority: -1

A negative priority means packages from testing can only be installed with e.g. apt install -t testing python3.9. Other choices may make sense; further detail of how priority is handled is in the apt_preferences(5) manpage:

https://manpages.debian.org/buster/apt/apt_preferences.5.en.html#How_APT_Interprets_Priorities

Instead of using a wildcard for the Packages: field, one can also specifically list the python3.9 packages that are required to further prevent other changes.

This is technically correct, and also what I was suggesting over on Twitter (https://twitter.com/zhenech/status/1467397693517488130), but has an interesting twist: the Python from Bullseye (and Bookworm) depends on a newer libc, and one probably doesn't want to do this -- you could just upgrade the whole system in that case.

FTR, the following would have worked, if Python 3.9 from Bullseye (11) would be "just installable" on Buster (10):

# grep bullseye /etc/apt/sources.list
deb http://deb.debian.org/debian bullseye main

# cat /etc/apt/preferences.d/python.pref
Package: *
Pin: release n=bullseye
Pin-Priority: -10

Package: /python3.9/
Pin: release n=bullseye
Pin-Priority: 100

What about conda? Allows you to have specific versions of python & ansible inside a nice, easy, contained virtual environment, very similar to pyenv but much nicer. Makes the underlying distro version of python irrelevant.

I'm typically targeting those who don't spend much time as 'Pythonic' devs—if you do a lot of python work, then tools like conda or pyenv would be pretty essential in your day-to-day work.

If not, it's annoying to have an extra environment abstraction tool running that you run Ansible from within (IMO).

Funnily enough, hit this exact roadblock when trying to install internet-pi just received a starlink dish and started following your work on Youtube a week or so ago. Spent 24 hours head scratching. Haven't tried yet but will and report back. In the UK BTW with Starlink. Thanks again, keep up the good work.