複数のPython バージョンをupdate-alternativesで管理する (Ubuntu)

サードパーティーのライブラリを使い分ける必要があり、以下のことを達成したい。

- (1) 複数のPythonバージョンを使い分けたい（Python 2.7, 3.6, 3.8など）
- (2) Pythonバージョンごとにnumpy等のメインとなる(プロジェクト同士で共有されるような)ライブラリを別々にインストールしたい。
- (3) Pythonバージョン内で、プロジェクトごとにPython環境を作りたい。

(同時進行しているプロジェクトに悪影響を出さないために、VirtualBoxを用いてMac上でUbuntuを動かし、実験しながら上記の目標を達成したい。)

その第１段階として、(1) (2)を行います。

# (0) 環境
- Ubuntu 20.04 (Mac上でVirtualBox6.1を利用)

# (1) 複数のPythonバージョンを使い分ける（Python 2.7, 3.6, 3.8など）

```bash 

$ sudo apt update && apt upgrade -y

$ sudo apt-get install build-essential checkinstall
$ sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev \
    libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev

$ apt list --upgradable

$ sudo apt-get install build-essential checkinstall

$ sudo make altinstall 
```

```bash 
$ python3 --version
Python 3.8.2

```

この段階で入っているpython3は`python3.8` (python 3.8.2)であることがわかります。（調べると、 `/usr/bin/` においてあることがわかりました。）


次に、https://www.python.org/ftp/python/ にあるリストの中から、必要なPythonバージョンのリンクを探し、wgetを使って`/opt/`にダウンロードします。

```bash

# まずPython-3.8.0
$ cd /opt
$ sudo wget https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz 
$ sudo tar xzf Python-3.8.0.tgz 
$ cd Python-3.8.0
$ sudo ./configure --enable-optimizations
$ sudo make altinstall


# 次にPython-3.6.10
$ cd /opt
$ sudo wget https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tgz 
$ sudo tar xzf Python-3.6.10.tgz 
$ cd Python-3.8.0
$ sudo ./configure --enable-optimizations
$ sudo make altinstall

# ディレクトリを確認
$ cd /opt
$ ls -l
total 45884
drwxr-xr-x 18   501   501     4096 May  9 18:33 Python-3.6.10
-rw-r--r--  1 root  root  23019480 Dec 18 14:48 Python-3.6.10.tgz
drwxr-xr-x 18 kohei kohei     4096 May  9 17:48 Python-3.8.0
-rw-r--r--  1 root  root  23949883 Oct 14  2019 Python-3.8.0.tgz
drwxr-xr-x  8 root  root      4096 May  8 18:04 VBoxGuestAdditions-6.1.6


```

```bash
$ sudo update-alternatives --install /usr/bin/python python /opt/Python-3.6.10/python 1
$ sudo update-alternatives --install /usr/bin/python python /opt/Python-3.8.0/python 2
$ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 3
$ update-alternatives --list python
/opt/Python-3.6.10/python
/opt/Python-3.8.0/python
/usr/bin/python3.8


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

  Selection    Path                       Priority   Status
------------------------------------------------------------
  0            /usr/bin/python3.8          3         auto mode
* 1            /opt/Python-3.6.10/python   1         manual mode
  2            /opt/Python-3.8.0/python    2         manual mode
  3            /usr/bin/python3.8          3         manual mode

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


$ cd /usr/bin
$ ls -l pyt*
lrwxrwxrwx 1 root root      24 May  9 18:20 python -> /etc/alternatives/python
lrwxrwxrwx 1 root root       9 May  8 17:33 python3 -> python3.8
-rwxr-xr-x 1 root root 5457536 Apr 27 11:53 python3.8
lrwxrwxrwx 1 root root      33 Apr 27 11:53 python3.8-config -> x86_64-linux-gnu-python3.8-config
lrwxrwxrwx 1 root root      16 Mar 13 08:20 python3-config -> python3.8-config

$ ls -l /etc/alternatives/python
lrwxrwxrwx 1 root root 25 May  9 19:27 /etc/alternatives/python -> /opt/Python-3.6.10/python

$ which python
/usr/bin/python

$ python -V
Python 3.6.10

```

`/etc/alternatives/python`が、ユーザーの指定したPythonに対応するPath（この場合`/opt/Python-3.6.10/python`）へのsymbolic linkになっていることがわかる。

まとめると、

- (a) `python` を呼ぶと、
- (b) `/usr/bin/python`が呼び出される。
- (c)　しかし、`/usr/bin/python`は `/etc/alternatives/python` へのsymbolic linkなので、`/etc/alternatives/python` が呼び出される。
- (d)さらに、`/etc/alternatives/python`は(`update-alternatives`の現在の設定では) `/opt/Python-3.6.10/python`にリンクされている。 
- (e) 結局、 `/opt/Python-3.6.10/python`が呼び出される。


次に、以下の手順で`pip`をアップデートする。

```bash
# 確認
$ which python
/usr/bin/python
# 確認
$ python -V
Python 3.6.10

$ apt install python3-pip
$ python -m pip install --upgrade pip
$ pip --version
pip 20.1 from /usr/local/lib/python3.6/site-packages/pip (python 3.6)
```

# (2) Pythonバージョンごとにライブラリを別々にインストール

今後は、各バージョンのPythonについて、個別にライブラリを入れていくようにします。その手順は以下のとおりです。

```bash
# 確認
$ which python
/usr/bin/python
# 確認
$ python -V
Python 3.6.10
$ sudo python -m pip install numpy
Collecting numpy
  Downloading https://files.pythonhosted.org/packages/03/27/e35e7c6e6a52fab9fcc64fc2b20c6b516eba930bb02b10ace3b38200d3ab/numpy-1.18.4-cp36-cp36m-manylinux1_x86_64.whl (20.2MB)
    100% |████████████████████████████████| 20.2MB 2.3MB/s 
Installing collected packages: numpy
Successfully installed numpy-1.18.4

$ sudo python -m pip install scipy
Collecting scipy
  Downloading scipy-1.4.1-cp36-cp36m-manylinux1_x86_64.whl (26.1 MB)
     |████████████████████████████████| 26.1 MB 5.8 MB/s 
Requirement already satisfied: numpy>=1.13.3 in /usr/local/lib/python3.6/site-packages (from scipy) (1.18.4)
Could not build wheels for numpy, since package 'wheel' is not installed.
Installing collected packages: scipy
Successfully installed scipy-1.4.1

# 結果を確認する。
$ python -c 'import sys; print(sys.version); import numpy; print(numpy.__file__); import scipy; print(scipy.__file__)'
3.6.10 (default, May  9 2020, 18:32:23) 
[GCC 9.3.0]
/usr/local/lib/python3.6/site-packages/numpy/__init__.py
/usr/local/lib/python3.6/site-packages/scipy/__init__.py
```

参考までに、`/usr/local/lib/python3.6/site-packages/`の中に何があるのかを見てみる。

```bash
$ ls -l /usr/local/lib/python3.6/site-packages/
total 52
-rw-r--r--  1 root root  126 May  9 18:34 easy_install.py
drwxr-xr-x 17 root root 4096 May 10 18:45 numpy
drwxr-xr-x  2 root root 4096 May 10 18:45 numpy-1.18.4.dist-info
drwxr-xr-x  2 root root 4096 May 10 18:45 numpy.libs
drwxr-xr-x  5 root root 4096 May 10 18:46 pip
drwxr-xr-x  2 root root 4096 May 10 18:46 pip-20.1.dist-info
drwxr-xr-x  5 root root 4096 May  9 18:34 pkg_resources
drwxr-xr-x  2 root root 4096 May  9 18:34 __pycache__
-rw-r--r--  1 root root  119 May  9 18:33 README.txt
drwxr-xr-x 23 root root 4096 May 10 18:46 scipy
drwxr-xr-x  2 root root 4096 May 10 18:46 scipy-1.4.1.dist-info
drwxr-xr-x  6 root root 4096 May  9 18:34 setuptools
drwxr-xr-x  2 root root 4096 May  9 18:34 setuptools-40.6.2.dist-info
```

さらに参考までに、今回のnumpy scipyのインストールが（狙い通り）Python 3.6.10だけに影響していることを見てみる。Python 3.8.0には触っていないので当然だが、下記のようになる。

```bash
$ /opt/Python-3.8.0/python -c 'import sys; print(sys.version); import numpy; print(numpy.__file__); import scipy; print(scipy.__file__)'
3.8.0 (default, May  9 2020, 17:47:23) 
[GCC 9.3.0]
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
```

少し仰々しいが、同じことは`update-alternatives`でPythonを切り替えても確かめられる。

```bash
$ sudo update-alternatives --config python
[sudo] password for kohei: 
There are 3 choices for the alternative python (providing /usr/bin/python).

  Selection    Path                       Priority   Status
------------------------------------------------------------
  0            /usr/bin/python3.8          3         auto mode
* 1            /opt/Python-3.6.10/python   1         manual mode
  2            /opt/Python-3.8.0/python    2         manual mode
  3            /usr/bin/python3.8          3         manual mode

Press <enter> to keep the current choice[*], or type selection number: 2
update-alternatives: using /opt/Python-3.8.0/python to provide /usr/bin/python (python) in manual mode
kohei@kohei-VirtualBox:~$ 
kohei@kohei-VirtualBox:~$ which python
/usr/bin/python
kohei@kohei-VirtualBox:~$ python -V
Python 3.8.0
kohei@kohei-VirtualBox:~$ 
kohei@kohei-VirtualBox:~$ python -c 'import sys; print(sys.version); import numpy; print(numpy.__file__); import scipy; print(scipy.__file__)'
3.8.0 (default, May  9 2020, 17:47:23) 
[GCC 9.3.0]
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
kohei@kohei-VirtualBox:~$ 
```

もちろん、最後にもとのPythonバージョンに戻すことを忘れないようにする。

```bash 
kohei@kohei-VirtualBox:~$ sudo update-alternatives --config python
There are 3 choices for the alternative python (providing /usr/bin/python).

  Selection    Path                       Priority   Status
------------------------------------------------------------
  0            /usr/bin/python3.8          3         auto mode
  1            /opt/Python-3.6.10/python   1         manual mode
* 2            /opt/Python-3.8.0/python    2         manual mode
  3            /usr/bin/python3.8          3         manual mode

Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /opt/Python-3.6.10/python to provide /usr/bin/python (python) in manual mode

kohei@kohei-VirtualBox:~$ which python
/usr/bin/python
kohei@kohei-VirtualBox:~$ python -V
Python 3.6.10

```



# 参考文献

- I mainly followed the instruction in
 https://hackersandslackers.com/multiple-versions-python-ubuntu/
- Official documentation for pip  https://pip.pypa.io/en/stable/installing/
- How to install pip on Ubuntu 18.04 https://linuxize.com/post/how-to-install-pip-on-ubuntu-18.04/
- Install a module using pip for specific python version  https://stackoverflow.com/questions/10919569/install-a-module-using-pip-for-specific-python-version
- update-alternativesコマンドの使い方 https://graziegrazie.hatenablog.com/entry/2015/11/14/101050
- VirtualBox + Ubuntu https://www.youtube.com/watch?v=3AnlvTgsoYM&frags=pl%2Cwn