「Pythonライブラリのバージョンアップ」と「pipコマンド」

# はじめに
先日、Pythonライブラリのバージョンアップに取り組みました。
その際、pipコマンドを使って、あれこれ作業をしたので、その内容をまとめました。

# 目次
- [下準備](#下準備)
- [インストールされているライブラリの確認](#インストールされているライブラリの確認)
- [旧バージョンの削除](#旧バージョンの削除)
- [バージョンアップ](#バージョンアップ)


# 下準備
:::note info
こちらの下準備をしていただければ、以下の内容をハンズオンできます。
内容のみ確認したい方は飛ばしてください。
:::

### virtualenvで検証環境を作成
検証用の環境をvirtualenvを使って準備します。
virtualenvが入っていない方は以下のコマンドでインストールしてください。

```bash
$ pip install virtualenv
```

それでは、検証用環境を作成します。
環境適用後、コマンドラインの先頭に`(${環境名})`と表示されていればOKです。
（私の場合は`(pip_test)`）

```bash
# pip_testという名前でPython3.11の環境を作成する
$ virtualenv -p python3.11 pip_test

# pip_testをカレントディレクトリに適用する
$ source pip_test/bin/activate
```
:::note warn
`source pip_test/bin/activate`でpip_testが有効化されるのは、このセッション限りです。
永続化したい場合は「pyenvを利用」「.bashrcで設定」などをしてみてください。
:::

### ライブラリをインストール
検証用に[requests](https://pypi.org/project/requests/)をインストールしてみます。
まずはバージョンアップ前ということで適当な古いバージョンを指定します。

```bash
$ pip install requests==2.27.1
```

これで下準備は完了です！


# インストールされているライブラリの確認
現在のリストを`pip freeze`を利用してrequirements.txtに出力します。
```bash
$ pip freeze > requirements.txt
```

```tex:requirements.txt
certifi==2023.11.17
charset-normalizer==2.0.12
idna==3.6
requests==2.27.1
urllib3==1.26.18
```

先ほどインストールしたrequests以外にもライブラリが入っています。
これらは依存関係により、インストールされたライブラリたちです。

ちなみに依存関係は`pip show`で確認することができます。

```bash
$ pip show requests
Name: requests
Version: 2.27.1
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache 2.0
Location: xxxxxxxxxxxxxxxx
Requires: certifi, charset-normalizer, idna, urllib3
Required-by:
```
Requiresがrequests**が利用する**ライブラリ、Required-byがrequests**を利用する**ライブラリです。

# 旧バージョンの削除
現在インストールされているライブラリを削除してから、新たにバージョンアップ後のライブラリをインストールするという流れで進めていきます。
（他にも方法がありそうですが。。。）

先ほど出力したrequirements.txtを利用して、ライブラリを削除します。
`-y`オプションは、削除のたびに確認されるのが面倒なので付けています。
```bash
$ pip uninstall -y -r requirements.txt
```

念のため、キャッシュも削除しておきます。
```bash
$ pip cache purge
```
:::note warn
不要かもしれないので、ここは任意で。
キャッシュ周りでエラーが発生することもあるようなので、削除しています。
:::

# バージョンアップ
### 全てのライブラリを最新バージョンに上げる場合
requirements.txtから以下のようにバージョンを削除し、`pip install -r requirements.txt`を実行することで可能です。
```tex:requirements.txt
certifi
charset-normalizer
idna
requests
urllib3
```

### 特定のライブラリのみバージョンを指定したい場合
「脆弱性が見つかった」など、至急で特定のライブラリのみに対応するケースを想定しています。
今回はurllib3のバージョンを`1.26.18`から`2.1.0`に上げる場合を試してみます。
requirements.txtを以下のように編集して、`pip install -r requirements.txt`を実行します。

```diff_te_x:requirements.txt
certifi==2023.11.17
charset-normalizer==2.0.12
idna==3.6
requests==2.27.1
- urllib3==1.26.18
+ urllib3==2.1.0
```

実は、この状態だと次のようなエラーが発生します。
```bash
$ pip install -r requirements.txt     
Collecting certifi==2023.11.17 (from -r requirements.txt (line 1))
  Using cached certifi-2023.11.17-py3-none-any.whl.metadata (2.2 kB)
Collecting charset-normalizer==2.0.12 (from -r requirements.txt (line 2))
  Using cached charset_normalizer-2.0.12-py3-none-any.whl (39 kB)
Collecting idna==3.6 (from -r requirements.txt (line 3))
  Using cached idna-3.6-py3-none-any.whl.metadata (9.9 kB)
Collecting requests==2.27.1 (from -r requirements.txt (line 4))
  Downloading requests-2.27.1-py2.py3-none-any.whl (63 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.1/63.1 kB 1.5 MB/s eta 0:00:00
Collecting urllib3==2.1.0 (from -r requirements.txt (line 5))
  Using cached urllib3-2.1.0-py3-none-any.whl.metadata (6.4 kB)
INFO: pip is looking at multiple versions of requests to determine which version is compatible with other requirements. This could take a while.
ERROR: Cannot install -r requirements.txt (line 4) and urllib3==2.1.0 because these package versions have conflicting dependencies.

The conflict is caused by:
    The user requested urllib3==2.1.0
    requests 2.27.1 depends on urllib3<1.27 and >=1.21.1

To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip attempt to solve the dependency conflict

ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts
```

これはrequestsの2.27.1が、urllib3の1.21.1以上、1.27未満でなければ利用できないため、発生したエラーです。

このような場合、依存関係にあるライブラリについてもバージョンアップできるかどうか、個別に調査し、判断する必要があります。

requestsのバージョンを上げても問題なさそうであれば、以下のようにバージョンを上げてやれば、無事インストールできます。
（バージョンを指定せずに、最新バージョンをインストールすることも可能です。）

```diff_te_x:requirements.txt
certifi==2023.11.17
charset-normalizer==2.0.12
idna==3.6
- requests==2.27.1
+ requests==2.31.0
urllib3==2.1.0
```
バージョンアップは以上です。
あとは、各プロジェクトで行なっている動作検証をして、問題なければ完了です！