Python: Setting the preferred Python version on Bionic 18 and Focal 20

python-logoEven though Python2 reached EOL in January 2020, there are still lagging applications and modules that force its continued use on certain systems.  If that is your situation, you need the ability to force preference to Python3 unless a program explicitly invokes Python2.

If you are using Ubuntu Focal 20, then you have an easy way of managing this for Python with the package ‘python-is-python3‘.  This has the distinct advantage of keeping in sync with the latest Python 3.x version even if upgraded.

sudo apt-get install python-is-python3 -y

However, if you are on Ubuntu Bionic 18 or Xenial 16, this package is not available in the Ubuntu package repository even though you are much more likely to be in a transitional Python2/3 mode given the timeframe of these Ubuntu releases.  For this situation, use the standard update-alternatives utility which can help manage the symlinks necessary to implement your preference.

The output below is from an Ubuntu Bionic 18 host with both python2.7 and 3.6 installed.  You can see ‘python’ invokes Python2.7 because that is where the symlink is pointed.

# shows preference for 'python' is Python2
/usr/bin/env python --version
Python 2.7.17

# shows symlinks currently in /usr/bin
$ ls -l /usr/bin/python /usr/bin/python
lrwxrwxrwx 1 root root 9 Apr 16 2018 /usr/bin/python -> python2.7
lrwxrwxrwx 1 root root 9 Apr 16 2018 /usr/bin/python2 -> python2.7
lrwxrwxrwx 1 root root 9 Oct 25 2018 /usr/bin/python3 -> python3.6

# shows expected responses for 'python', 'python2', and 'python3'
$ python --version
Python 2.7.17
$ python2 --version
Python 2.7.17
$ python3 --version
Python 3.6.9

What we want is for ‘python’ to invoke Python3.6 so that all Python applications use this version unless they explicitly request otherwise.  And we could do this by simply repointing the symlink manually.  But the update-alternatives utility has the advantage of being a common admin task for many different functions (editor preferences, compilers, java versions, etc).  A manual one-off change might be unexpected to another system administrator, especially since the /usr/bin directory is not typically modified directly.

Here is how you would create a preferred usage of Python3 for ‘python’.

# create 'python' choice for Python2, low preference
sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 10

# create 'python' choice for Python3, highest preference
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 20

# show preferences, Python3 is listed as best choice
$ sudo update-alternatives --query python
Name: python
Link: /usr/bin/python
Status: auto
Best: /usr/bin/python3.6
Value: /usr/bin/python3.6

Alternative: /usr/bin/python2.7
Priority: 10

Alternative: /usr/bin/python3.6
Priority: 20

# internally, link was added to /etc/alternatives
ls -l /etc/alternatives/pytho*
lrwxrwxrwx 1 root root 18 Feb 27 22:41 /etc/alternatives/python -> /usr/bin/python3.6

Now validate the change:

# 'python' now prefers Python3
$ python --version
Python 3.6.9

And if you need to change the preference, you could use:

$ sudo update-alternatives --config python
There are 2 choices for the alternative python (providing /usr/bin/python).

Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/bin/python3.6 20 auto mode
1 /usr/bin/python2.7 10 manual mode
2 /usr/bin/python3.6 20 manual mode

Press <enter> to keep the current choice[*], or type selection number:

 

REFERENCES

askubuntu.com, using update-alternatives (bionic 18) and python-is-python3 (focal 20)

manpages ubuntu, updates-alternatives man page

patrickmartin gist, ubuntu16 update-alternatives for ‘python’

GrowtopiaJaw, update-alternatives for ‘python2’ and ‘python3’

linuxhint.com, update-alternatives for Ubuntu saying /usr/local/bin is more appropriate location for alternatives because it is a user-space program.  /usr/local/bin typically comes first in PATH to override any dpkg installations

refspecs.linuxfoundation.org, Linux filesystem hierarchy standard (e.g. use of /usr/local/bin versus /usr/bin)

askubuntu.com, fixing symlink to python3 after upgrade of python using python3-minimal

NOTES

removing an alternative, for example on a binary “/usr/local/bin/helm3” with name “helm”

$ sudo update-alternatives --query helm
Name: helm
Link: /usr/local/bin/helm
Status: auto
Best: /usr/local/bin/helm3
Value: /usr/local/bin/helm3

Alternative: /usr/local/bin/helm3
Priority: 20

# remove alternative
$ sudo update-alternatives --remove helm /usr/local/bin/helm3