PythonのパッケージのアップデートをしようとしたらPIPが古いと相手にしてもらえなかった話

「見たことがないエラーはqiitaのネタになる」とは
古くから伝わる格言らしいです。嘘だけど。

cronで動かしているpythonのスクリプトがエラーを吐くようになり、
直そうとしたところ目にしたエラーです。

# やろうとしたこと
エラーの一部がhttpsに関係するところだったので、
もしかしたらパッケージのアップデートでお茶を濁せるんじゃないか、
なんて考えまして、とりあえず入ってるパッケージのリストを出力しようとしたところ、
次のようなエラーが出ました

```
$ sudo pip3 list -o
Exception:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/_internal/cli/base_command.py", line 143, in main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 138, in run
    packages = self.get_outdated(packages, options)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 149, in get_outdated
    dist for dist in self.iter_packages_latest_infos(packages, options)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 150, in <listcomp>
    if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'
```



## 対処
最近のpipではインスタンスの比較が厳密になったらしく、
それが原因でエラーを吐いているらしいとのこと。
そもそもRaspberryPiをセットアップした時
pip3を入れたまま手を入れてなかったので、
諸々古くなった弊害なんだろうと、PIPをインストールしました。

```bash
$ sudo pip3 install --upgrade pip
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pip
  Downloading https://files.pythonhosted.org/packages/47/6a/453160888fab7c6a432a6e25f8afe6256d0d9f2cbd25971021da6491d899/pip-23.3.1-py3-none-any.whl (2.1MB)
    100% |████████████████████████████████| 2.1MB 42kB/s
Installing collected packages: pip
  Found existing installation: pip 18.1
    Not uninstalling pip at /usr/lib/python3/dist-packages, outside environment /usr
    Can't uninstall 'pip'. No files were found to uninstall.
Successfully installed pip-23.3.1
```
動いていたのが18.1でアップデート後が23.3.1と
かなり時代遅れなパッケージで動いていたことがわかりました。

その結果、Warningは出ているものの、
期待通りの動きをしてくれるようになりました。

```bash
$ sudo pip list -o
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/pip-review/
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/urllib3/
Package       Version   Latest     Type
------------- --------- ---------- -----
asn1crypto    0.24.0    1.5.1      wheel
certifi       2018.8.24 2023.11.17 wheel
chardet       3.0.4     5.2.0      wheel
cryptography  2.6.1     41.0.5     wheel
entrypoints   0.3       0.4        wheel
idna          2.6       3.6        wheel
keyring       17.1.1    24.1.1     wheel
keyrings.alt  3.1.1     4.2.0      wheel
PyGObject     3.30.4    3.44.2     wheel
pyxdg         0.25      0.28       wheel
requests      2.21.0    2.31.0     wheel
RPi.bme280    0.2.3     0.2.4      wheel
SecretStorage 2.3.1     3.3.3      wheel
setuptools    40.8.0    68.0.0     wheel
six           1.12.0    1.16.0     wheel
smbus2        0.3.0     0.4.3      wheel
speedtest-cli 2.0.2     2.1.3      wheel
ssh-import-id 5.7       5.11       wheel
urllib3       1.24.1    2.0.7      wheel
wheel         0.32.3    0.41.3     wheel
```


### 参考
Ubuntu 18.04 で pip list -o がエラーになる｜Junf / Jade
https://note.com/junf/n/n0e460749fe66

# パッケージをまとめてアップデート
スクリプト内で利用しているパッケージを個別にアップデートしても良かったのですが、
```pip-review```という便利なツールを見つけたので、
それをインストールして一気にやっつけてしまうことにしました。

## インストール
```bash
$ sudo pip install pip-review
```
```sudo``` をつけないでもインストール自体はできますが、
パスが通っていないところにファイルが置かれるので、
コマンドとして使いにくくなります。
コマンドとして使うのにsudoとして
ファイルのアクセス権限を付与している形です。


## 全パッケージのアップデート
コマンド一つで実行可能です。
```pip-review --auto```で新しいパッケージがある場合、
アップデートしてくれるという優れものです。

```bash
$ sudo pip-review --auto
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/pip-review/
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/urllib3/
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Requirement already satisfied: asn1crypto in /usr/lib/python3/dist-packages (0.24.0)
Collecting asn1crypto
  Downloading https://www.piwheels.org/simple/asn1crypto/asn1crypto-1.5.1-py3-none-any.whl (110 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 110.1/110.1 kB 43.6 kB/s eta 0:00:00
Requirement already satisfied: certifi in /usr/lib/python3/dist-packages (2018.8.24)
Collecting certifi
  Downloading https://www.piwheels.org/simple/certifi/certifi-2023.11.17-py3-none-any.whl (162 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 162.5/162.5 kB 68.6 kB/s eta 0:00:00
Requirement already satisfied: chardet in /usr/lib/python3/dist-packages (3.0.4)
Collecting chardet
  Downloading https://www.piwheels.org/simple/chardet/chardet-5.2.0-py3-none-any.whl (199 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.4/199.4 kB 71.1 kB/s eta 0:00:00
Requirement already satisfied: cryptography in /usr/lib/python3/dist-packages (2.6.1)
Collecting cryptography
  Downloading https://www.piwheels.org/simple/cryptography/cryptography-41.0.5-cp37-cp37m-linux_armv6l.whl (2.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.2/2.2 MB 799.4 kB/s eta 0:00:00
Requirement already satisfied: entrypoints in /usr/lib/python3/dist-packages (0.3)
Collecting entrypoints
  WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/entrypoints/entrypoints-0.4-py3-none-any.whl
  Downloading https://www.piwheels.org/simple/entrypoints/entrypoints-0.4-py3-none-any.whl (5.3 kB)
Requirement already satisfied: idna in /usr/lib/python3/dist-packages (2.6)
Collecting idna
  Downloading https://www.piwheels.org/simple/idna/idna-3.6-py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.6/61.6 kB 137.4 kB/s eta 0:00:00
Requirement already satisfied: keyring in /usr/lib/python3/dist-packages (17.1.1)
Collecting keyring
  Downloading https://www.piwheels.org/simple/keyring/keyring-24.1.1-py3-none-any.whl (37 kB)
Requirement already satisfied: keyrings.alt in /usr/lib/python3/dist-packages (3.1.1)
Collecting keyrings.alt
  Downloading https://www.piwheels.org/simple/keyrings-alt/keyrings.alt-4.2.0-py3-none-any.whl (20 kB)
Requirement already satisfied: PyGObject in /usr/lib/python3/dist-packages (3.30.4)
Collecting PyGObject
  Downloading https://www.piwheels.org/simple/pygobject/PyGObject-3.44.2-cp37-cp37m-linux_armv6l.whl (510 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 510.7/510.7 kB 60.0 kB/s eta 0:00:00
Requirement already satisfied: pyxdg in /usr/lib/python3/dist-packages (0.25)
Collecting pyxdg
  Downloading https://www.piwheels.org/simple/pyxdg/pyxdg-0.28-py2.py3-none-any.whl (40 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.8/40.8 kB 77.2 kB/s eta 0:00:00
Requirement already satisfied: requests in /usr/lib/python3/dist-packages (2.21.0)
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/requests/
Collecting requests
  Downloading https://www.piwheels.org/simple/requests/requests-2.31.0-py3-none-any.whl (62 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.6/62.6 kB 151.8 kB/s eta 0:00:00
Requirement already satisfied: RPi.bme280 in /usr/local/lib/python3.7/dist-packages (0.2.3)
Collecting RPi.bme280
  Downloading https://www.piwheels.org/simple/rpi-bme280/RPi.bme280-0.2.4-py2.py3-none-any.whl (10 kB)
Requirement already satisfied: SecretStorage in /usr/lib/python3/dist-packages (2.3.1)
Collecting SecretStorage
  Downloading https://www.piwheels.org/simple/secretstorage/SecretStorage-3.3.3-py3-none-any.whl (15 kB)
Requirement already satisfied: setuptools in /usr/lib/python3/dist-packages (40.8.0)
Collecting setuptools
  Downloading https://www.piwheels.org/simple/setuptools/setuptools-68.0.0-py3-none-any.whl (804 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 804.0/804.0 kB 220.9 kB/s eta 0:00:00
Requirement already satisfied: six in /usr/lib/python3/dist-packages (1.12.0)
Collecting six
  Downloading https://www.piwheels.org/simple/six/six-1.16.0-py2.py3-none-any.whl (11 kB)
Requirement already satisfied: smbus2 in /usr/local/lib/python3.7/dist-packages (0.3.0)
Collecting smbus2
  Downloading https://www.piwheels.org/simple/smbus2/smbus2-0.4.3-py2.py3-none-any.whl (11 kB)
Requirement already satisfied: speedtest-cli in /usr/lib/python3/dist-packages (2.0.2)
Collecting speedtest-cli
  Downloading https://www.piwheels.org/simple/speedtest-cli/speedtest_cli-2.1.3-py2.py3-none-any.whl (23 kB)
Requirement already satisfied: ssh-import-id in /usr/lib/python3/dist-packages (5.7)
Collecting ssh-import-id
  Downloading https://www.piwheels.org/simple/ssh-import-id/ssh_import_id-5.11-py3-none-any.whl (8.9 kB)
Requirement already satisfied: urllib3 in /usr/lib/python3/dist-packages (1.24.1)
Collecting urllib3
  Downloading https://www.piwheels.org/simple/urllib3/urllib3-2.0.7-py3-none-any.whl (124 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 124.2/124.2 kB 82.3 kB/s eta 0:00:00
Requirement already satisfied: wheel in /usr/lib/python3/dist-packages (0.32.3)
Collecting wheel
  Downloading https://www.piwheels.org/simple/wheel/wheel-0.41.3-py3-none-any.whl (65 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 65.8/65.8 kB 137.1 kB/s eta 0:00:00
Collecting cffi>=1.12 (from cryptography)
  Downloading https://www.piwheels.org/simple/cffi/cffi-1.15.1-cp37-cp37m-linux_armv6l.whl (219 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 219.9/219.9 kB 53.3 kB/s eta 0:00:00
Collecting jaraco.classes (from keyring)
  Downloading https://www.piwheels.org/simple/jaraco-classes/jaraco.classes-3.2.3-py3-none-any.whl (6.0 kB)
Collecting importlib-metadata>=4.11.4 (from keyring)
  Downloading https://www.piwheels.org/simple/importlib-metadata/importlib_metadata-6.7.0-py3-none-any.whl (22 kB)
WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProtocolError('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))': /simple/importlib-resources/
Collecting importlib-resources (from keyring)
  Downloading https://www.piwheels.org/simple/importlib-resources/importlib_resources-5.12.0-py3-none-any.whl (36 kB)
Collecting jeepney>=0.4.2 (from keyring)
  Downloading https://www.piwheels.org/simple/jeepney/jeepney-0.8.0-py3-none-any.whl (48 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 48.4/48.4 kB 62.6 kB/s eta 0:00:00
Collecting pycairo>=1.16.0 (from PyGObject)
  Downloading https://www.piwheels.org/simple/pycairo/pycairo-1.23.0-cp37-cp37m-linux_armv6l.whl (190 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 190.2/190.2 kB 37.7 kB/s eta 0:00:00
Collecting charset-normalizer<4,>=2 (from requests)
  Downloading https://www.piwheels.org/simple/charset-normalizer/charset_normalizer-3.3.2-py3-none-any.whl (48 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 48.5/48.5 kB 107.0 kB/s eta 0:00:00
Collecting pytz (from RPi.bme280)
  Downloading https://www.piwheels.org/simple/pytz/pytz-2023.3.post1-py3-none-any.whl (502 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 502.5/502.5 kB 103.9 kB/s eta 0:00:00
Collecting distro (from ssh-import-id)
  Downloading https://www.piwheels.org/simple/distro/distro-1.8.0-py3-none-any.whl (20 kB)
Collecting pycparser (from cffi>=1.12->cryptography)
  Downloading https://www.piwheels.org/simple/pycparser/pycparser-2.21-py2.py3-none-any.whl (119 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 119.7/119.7 kB 49.7 kB/s eta 0:00:00
Collecting zipp>=0.5 (from importlib-metadata>=4.11.4->keyring)
  Downloading https://www.piwheels.org/simple/zipp/zipp-3.15.0-py3-none-any.whl (6.8 kB)
Collecting typing-extensions>=3.6.4 (from importlib-metadata>=4.11.4->keyring)
  Downloading https://www.piwheels.org/simple/typing-extensions/typing_extensions-4.7.1-py3-none-any.whl (33 kB)
Collecting more-itertools (from jaraco.classes->keyring)
  Downloading https://www.piwheels.org/simple/more-itertools/more_itertools-9.1.0-py3-none-any.whl (54 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 54.2/54.2 kB 127.0 kB/s eta 0:00:00
Installing collected packages: speedtest-cli, smbus2, pyxdg, pytz, asn1crypto, zipp, wheel, urllib3, typing-extensions, six, setuptools, RPi.bme280, pycparser, pycairo, more-itertools, jeepney, idna, entrypoints, distro, charset-normalizer, chardet, certifi, ssh-import-id, requests, PyGObject, jaraco.classes, importlib-resources, importlib-metadata, cffi, keyrings.alt, cryptography, SecretStorage, keyring
  Attempting uninstall: speedtest-cli
    Found existing installation: speedtest-cli 2.0.2
    Uninstalling speedtest-cli-2.0.2:
      Successfully uninstalled speedtest-cli-2.0.2
  Attempting uninstall: smbus2
    Found existing installation: smbus2 0.3.0
    Uninstalling smbus2-0.3.0:
      Successfully uninstalled smbus2-0.3.0
  Attempting uninstall: pyxdg
    Found existing installation: pyxdg 0.25
ERROR: Cannot uninstall 'pyxdg'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
```

ちなみに、前段のPIPのアップデート前では次のような結果が出ました。
```bash
$sudo pip-review --auto
Exception:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/_internal/cli/base_command.py", line 143, in main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 138, in run
    packages = self.get_outdated(packages, options)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 149, in get_outdated
    dist for dist in self.iter_packages_latest_infos(packages, options)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/list.py", line 150, in <listcomp>
    if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'
Traceback (most recent call last):
  File "/usr/local/bin/pip-review", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/dist-packages/pip_review/__main__.py", line 240, in main
    outdated = get_outdated_packages(list_args)
  File "/usr/local/lib/python3.7/dist-packages/pip_review/__main__.py", line 222, in get_outdated_packages
    output = check_output(command).decode('utf-8')
  File "/usr/local/lib/python3.7/dist-packages/pip_review/__main__.py", line 21, in check_output
    raise error
    subprocess.CalledProcessError: Command '['/usr/bin/python3', '-m', 'pip', 'list', '--outdated', '--disable-pip-version-check', '--format=json']' returned non-zero exit status 2.
```
これを解決するために調べていたところPIPのアップデートの件にたどり着いたという経緯があります。