98

The other day I decided that I wanted the command python to default to firing up python3 instead of python2.

So I did this:

$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 2

$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 3

$ sudo update-alternatives --config python

$ 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.5   3         auto mode
  1            /usr/bin/python2.7   2         manual mode
  2            /usr/bin/python3.5   3         manual mode

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

And that all worked. Great! :)

$ python -V
Python 3.5.2

But it wasn't long before I realised I had broken apt/aptitude when it comes to installing and removing python packages because apt was expecting python2 it transpired.

This is what happened.

$ sudo apt remove  python-samba
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  samba-libs
Use 'sudo apt autoremove' to remove it.
The following packages will be REMOVED:
  python-samba
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 5,790 kB disk space will be freed.
Do you want to continue? [Y/n] 
(Reading database ... 187285 files and directories currently installed.)
Removing python-samba (2:4.3.11+dfsg-0ubuntu0.16.04.5) ...
  File "/usr/bin/pyclean", line 63
    except (IOError, OSError), e:
                             ^
SyntaxError: invalid syntax
dpkg: error processing package python-samba (--remove):
 subprocess installed pre-removal script returned error exit status 1
Traceback (most recent call last):
  File "/usr/bin/pycompile", line 35, in <module>
    from debpython.version import SUPPORTED, debsorted, vrepr, \
  File "/usr/share/python/debpython/version.py", line 24, in <module>
    from ConfigParser import SafeConfigParser
ImportError: No module named 'ConfigParser'
dpkg: error while cleaning up:
 subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
 python-samba
E: Sub-process /usr/bin/dpkg returned an error code (1)

Eventually I guessed it wanted python2 as the default, so I undid my changes as follows:

$ 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.5   3         auto mode
  1            /usr/bin/python2.7   2         manual mode
  2            /usr/bin/python3.5   3         manual mode

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

$ python -V
Python 2.7.12

And then apt worked again

$ sudo apt remove  python-samba
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following package was automatically installed and is no longer required:
  samba-libs
Use 'sudo apt autoremove' to remove it.
The following packages will be REMOVED:
  python-samba
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
1 not fully installed or removed.
After this operation, 5,790 kB disk space will be freed.
Do you want to continue? [Y/n] 
(Reading database ... 187285 files and directories currently installed.)
Removing python-samba (2:4.3.11+dfsg-0ubuntu0.16.04.5) ...

So I have had to leave it as defaulting to python 2 but I develop in python 3 and so would like my system to default to python 3 for when I run python and idle.

Can anyone tell me how I can achieve this without breaking apt?

My system is a Raspberry Pi 3B running Ubuntu:

Linux mymachine 4.4.38-v7+ #938 SMP Thu Dec 15 15:22:21 GMT 2016 armv7l armv7l armv7l GNU/Linux

(It's actually an arm v8)

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
tnagy.adam
  • 117
  • 6
Will
  • 1,509
  • 1
  • 13
  • 16
  • 11
    leave `python` pointing to python2 or you are in for *lots* of trouble – Corey Goldberg Mar 28 '17 at 15:13
  • Yeah, thanks, I thought as much. :) – Will Apr 02 '17 at 19:49
  • 2
    This question needs new updates in its answers. I'm currently running Debian with python3 as default (through update-alternatives) and I'm experiencing no problems. I'll comment if something breaks in the future, but the tendency is that it will became the new default. – DrBeco Sep 09 '19 at 17:38
  • On a Debian Bookworm system any attempts at changing python version yields in **update-alternatives: error: no alternatives for python**. Running `update-alternatives --get-selections | grep python` also shows no alternatives are available. Neither for _python_ or _python3_. According to [#901512](https://bugs.debian.org/901512) handling python version selection through the alternatives system is tagged [wontfix](https://www.debian.org/Bugs/Developer#tags), although the discussion there only covers selection of 2 vs. 3, nothing is explicitly written about minor versions. – sampi Apr 01 '22 at 10:16

7 Answers7

48

replace

[bash:~] $ sudo update-alternatives --install /usr/bin/python python \
/usr/bin/python2.7 2

[bash:~] $ sudo update-alternatives --install /usr/bin/python python \
/usr/bin/python3.5 3

with

[bash:~] $ sudo update-alternatives --install /usr/local/bin/python python \
/usr/bin/python2.7 2

[bash:~] $ sudo update-alternatives --install /usr/local/bin/python python \
/usr/bin/python3.5 3

e.g. installing into /usr/local/bin instead of /usr/bin.

and ensure the /usr/local/bin is before /usr/bin in PATH.

i.e.

[bash:~] $ echo $PATH
/usr/local/bin:/usr/bin:/bin

Ensure this always is the case by adding

export PATH=/usr/local/bin:$PATH

to the end of your ~/.bashrc file. Prefixing the PATH environment variable with custom bin folder such as /usr/local/bin or /opt/<some install>/bin is generally recommended to ensure that customizations are found before the default system ones.

Dmitry
  • 2,989
  • 2
  • 24
  • 34
jonrobm
  • 641
  • 5
  • 4
  • 7
    I'm abstaining from downvoting this because it *might* work in some situations; but really, **don't do this.** – tripleee Jun 12 '18 at 04:12
  • 2
    @tripleee Why not? I would hope that system level python doesn't reference the user's $PATH to pick the python executable. Surely those are just using /usr/bin/python and /usr/bin/python3, right? I can't see how introducing user level changes and adding symlinks to /usr/local/bin would cause a problem. – medley56 Dec 07 '18 at 18:23
  • Because `update-alternatives` is wrong, you really mustn't use this to replace `python` version 2 with `python3`, ever. The question describes some of the, well-documented, symptoms. – tripleee Dec 07 '18 at 18:28
  • 1
    So, this depends on how software inside Ubuntu looks for the `python` executable. My assumption is that system processes don't simply look at $PATH since it's user-dependent. And the only thing `update-alternatives` does is create a symlink at `/usr/local/bin/python`. Nothing at all changes in `/usr/bin`. As long as `apt` (or similar) is looking for `/usr/bin/python` and not just `python`, it should be fine. I have tested this with apt and it seems fine. This is not a guarantee that it will work with all system software though! – medley56 Dec 07 '18 at 18:50
  • I doubt it will work portably. You are installing a symlink from `/usr/local/bin/python` to `/etc/alternatives/python` but the latter is already used to point to the system Python, and changing its link destination will also change the system Python. (Not in a place where I can verify this, though.) Ubuntu's `update-alternatives` is a reimplementation so it might not work the same as Debian's. In any event, i don't see why you would use the system-wide `alternatives` system to manage a symlink in `/usr/local/bin` anyway; just create the symlink manually. – tripleee Dec 07 '18 at 19:58
  • In Ubuntu 18.04 I had to use slightly different command: `sudo update-alternatives --install /usr/local/bin/python python /usr/bin/python3.6 3` – Dmitry Dec 05 '19 at 14:57
44

Per Debian policy, python refers to Python 2 and python3 refers to Python 3. Don't try to change this system-wide or you are in for the sort of trouble you already discovered.

Virtual environments allow you to run an isolated Python installation with whatever version of Python and whatever libraries you need without messing with the system Python install.

With recent Python 3, venv is part of the standard library; with older versions, you might need to install python3-venv or a similar package.

$HOME~$ python --version
Python 2.7.11

$HOME~$ python3 -m venv myenv
... stuff happens ...

$HOME~$ . ./myenv/bin/activate

(myenv) $HOME~$ type python   # "type" is preferred over which; see POSIX
python is /home/you/myenv/bin/python

(myenv) $HOME~$ python --version
Python 3.5.1

A common practice is to have a separate environment for each project you work on, anyway; but if you want this to look like it's effectively system-wide for your own login, you could add the activation stanza to your .profile or similar.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 4
    This is now slightly obsolescent; different distros have slightly different versions of this. For example, on Ubuntu, `python` can now refer to either `python2` or `python3` (or, I guess, neither) and the system utilities must spell out `python2` or `python3`. – tripleee Dec 07 '20 at 06:19
  • Actually `python3-venv` is deliberately split out into a separate package on Debian. It is part of the standard library in Python, but Debian decided to make it optional. – tripleee May 11 '21 at 04:10
  • 2
    This is not an answer to the question but rather an _alternative_ . There are solid reasons for and against using a venv. My team chooses not to – WestCoastProjects Jul 24 '21 at 23:00
18

For anyone finding this question now in 2021, pretty much all of the earlier answers are obsolete.

It is perfectly fine, and expected now, for /usr/bin/python to point to Python 3. Python 2 is not being updated with security fixes, so any system still using it should be upgraded to use Python 3 as the system Python. Any modern distribution should already have solved potential incompatibilities in upgrading the system Python to Python 3.

Daira Hopwood
  • 2,264
  • 22
  • 14
  • The problem is about multiple versions of python3 and there is a lack of proper answers. For instance, gnome-terminal can break at any point after installing newer version of Python3. – Martin G Aug 01 '21 at 08:15
  • 2
    The question as asked isn't about differences between versions of Python 3; it's specifically about getting `python` to run Python 3 *without* upgrading the system from Python 2. It's unsurprising that there are no "proper answers" here to a different question. – Daira Hopwood Aug 09 '21 at 11:13
  • Raspberry Pi OS (Debian) still has python2 (Python 2.7.16) as the system default on my newest system: Raspbian GNU/Linux 10 (buster) – Will Nov 15 '21 at 16:26
  • You should report that as a security bug. – Daira Hopwood Dec 03 '21 at 19:09
  • 1
    This is not correct (and you can still break working and supported operating systems by redirecting the symlinks). [FWIW: Canonical still maintains and ships Python 2 security updates for Ubuntu 18.04 LTS](https://askubuntu.com/questions/1065593/will-it-be-safe-to-use-python-2-7-on-ubuntu-18-04-after-python-2-eol). Example: https://ubuntu.com/security/notices/USN-4754-4 – moooeeeep Jan 11 '22 at 10:27
  • 2
    The fact is that the first sentence of the top-voted answer is wrong, and most of the answers will break modern systems. My answer is basically correct now, and will only get more pedantically correct as time passes. – Daira Hopwood Jan 22 '22 at 17:19
  • 1
    Thank you@DairaHopwood, it's good knowing that things have (finally)(mostly) moved on. – J. Gwinner Mar 21 '22 at 21:30
7

As I didn't want to break anything, I did this to be able to use newer versions of Python3 than Python v3.4 :

$ sudo update-alternatives --install /usr/local/bin/python3 python3 /usr/bin/python3.6 1
update-alternatives: using /usr/bin/python3.6 to provide /usr/local/bin/python3 (python3) in auto mode
$ sudo update-alternatives --install /usr/local/bin/python3 python3 /usr/bin/python3.7 2
update-alternatives: using /usr/bin/python3.7 to provide /usr/local/bin/python3 (python3) in auto mode
$ update-alternatives --list python3
/usr/bin/python3.6
/usr/bin/python3.7
$ sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/local/bin/python3).

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

Press enter to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/bin/python3.6 to provide /usr/local/bin/python3 (python3) in manual mode
$ ls -l /usr/local/bin/python3 /etc/alternatives/python3 
lrwxrwxrwx 1 root root 18 2019-05-03 02:59:03 /etc/alternatives/python3 -> /usr/bin/python3.6*
lrwxrwxrwx 1 root root 25 2019-05-03 02:58:53 /usr/local/bin/python3 -> /etc/alternatives/python3*
SebMa
  • 4,037
  • 29
  • 39
3

Somehow python 3 came back (after some updates?) and is causing big issues with apt updates, so I've decided to remove python 3 completely from the alternatives:

root:~# python -V
Python 3.5.2

root:~# update-alternatives --config python
There are 2 choices for the alternative python (providing /usr/bin/python).

  Selection    Path                Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.5   3         auto mode
  1            /usr/bin/python2.7   2         manual mode
  2            /usr/bin/python3.5   3         manual mode


root:~# update-alternatives --remove python /usr/bin/python3.5

root:~# update-alternatives --config python
There is 1 choice for the alternative python (providing /usr/bin/python).

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

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


root:~# python -V
Python 2.7.12

root:~# update-alternatives --config python
There is only one alternative in link group python (providing /usr/bin/python): /usr/bin/python2.7
Nothing to configure.
Will
  • 1,509
  • 1
  • 13
  • 16
  • 2
    Indeed, `python3` is not a valid alternative for `python` because it *needs* to refer to Python 2. – tripleee Sep 07 '17 at 11:43
  • 1
    When you originally set it up, you told the system that python3 was a higher priority than python2. Then you manually set it to python 2. It appears that something put it back into auto mode, so picked python3. So, removing python3 was probably the right thing to do, but setting it to a lower priority would have had a similar effect. If it was me, I'd probably remove both entries from update-alternatives to put it back to the way the system started, actually. Less chance of confusion or problems in the future. – cds Sep 22 '20 at 23:27
2

I've edited /home/user/.bashrc with

alias python27=/usr/bin/python2.7
alias python31=/usr/bin/python3.10

on linux ubuntu 20.xx. I've added it to the very end of the document.

this binds python27 to the version you want.

python27 pythonscrypt.py

Test the sample with

python27 --version

but I was wondering if python and python3 should be pointing to the /usr/local/python3.9?

I thought it was customary to have 2.7-2.8 as python and 3.9.x as python3.

Updating the alternatives from above post has it a bit wonky for me so have to backtrack some by setting defaults to normal. Also was trying anaconda and some parts were getting a bit confusing between python and anaconda versions.

But I think editing the .bashrc then exiting terminal and logging back in is the best solution in 2021.

Don't forget to exit terminal and log back in after saving changes!

Another technique would be using envs in python3.

2

Complementary to the full explications above, here is a small script to add all python versions so that you can just copy paste this.

i=0 ; for p in /usr/bin/python*.* ; do
  update-alternatives --install /usr/bin/python python $p $((5 + i))
  i=$((i+1))
done
update-alternatives --config python
le_top
  • 445
  • 3
  • 12
  • End of the python3-config file? python3.10-config? both? Before or after esac? – ShefSam Sep 01 '22 at 19:33
  • Not sure what you mean. python3-config is surely nice when you setup a virtual environment, etc. `esac` makes me think of what ends a `case` statement which I can't relate to my proposal. The need is not so much what version is used in a virtual environment, but what version is used when running a script without firing up a virtual enviroment, especially when I install a module to use for "devops" tasks - for instance `python -m pip install beautysh`. – le_top Sep 01 '22 at 21:47