Python3.12のpipがバグってる件&とりあえずの修正方法

始めに

2023/10/2に約一年ぶりのメジャーアップデートであるPython3.12.0が公開されました。 昨日から使おうとインストールしたところ、pythonパッケージ管理用アプリのpipでエラーが発生し、 そのエラーの対応方法も発見しましたので、まとめておきます。

検証した環境

その1

OS: Windows10 CPU: core i5-11600KF MEM: DDR4-3200 32GB GPU: GTX1660Ti

その2

上記マシン上にインストールしたwsl OS: Ubuntu 20.04-LTS

仮想環境

共にvirtualenvを用いた仮想環境を用意して検証しています。

発生している現象

Python3.12.0の環境で、pipを使うとエラーが発生する。

pip list

pip install numpy

Traceback (most recent call last):
  File "/root/pythonproject/test/bin/pip", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/cli/main.py", line 70, in main
    return command.main(cmd_args)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/cli/base_command.py", line 101, in main
    return self._main(args)
           ^^^^^^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/cli/base_command.py", line 216, in _main
    self.handle_pip_version_check(options)
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/cli/req_command.py", line 179, in handle_pip_version_check
    session = self._build_session(
              ^^^^^^^^^^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/cli/req_command.py", line 125, in _build_session
    session = PipSession(
              ^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/network/session.py", line 343, in __init__
    self.headers["User-Agent"] = user_agent()
                                 ^^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/network/session.py", line 175, in user_agent
    setuptools_dist = get_default_environment().get_distribution("setuptools")
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py", line 188, in get_distribution
    return next(matches, None)
           ^^^^^^^^^^^^^^^^^^^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py", line 183, in <genexpr>
    matches = (
              ^
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/metadata/base.py", line 612, in iter_all_distributions
    for dist in self._iter_distributions():
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py", line 176, in _iter_distributions
    for dist in finder.find_eggs(location):
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py", line 144, in find_eggs
    yield from self._find_eggs_in_dir(location)
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py", line 111, in _find_eggs_in_dir
    from pip._vendor.pkg_resources import find_distributions
  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py", line 2164, in <module>
    register_finder(pkgutil.ImpImporter, find_on_path)
                    ^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pkgutil' has no attribute 'ImpImporter'. Did you mean: 'zipimporter'?

のようなエラーが発生。

pip -V

は普通に動きました。

修正方法

この方法は正式な方法ではありません。利用する際には自己責任で実行してください。

一段階目

pipのコードを二種類編集します。
pipはpythonによって実装されており、pythonベースのエラーが出てくるため、それに従って修正すればOKです。 見るべきはエラー出力下4行です。

  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py", line 2164, in <module>
    register_finder(pkgutil.ImpImporter, find_on_path)
                    ^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pkgutil' has no attribute 'ImpImporter'. Did you mean: 'zipimporter'?

VScodeでは、エラーが出ているファイル名にカーソルを合わせるとそこからファイルへアクセスできます。 pip/_vendor/pkg_resources/__init__.pyのファイルの

register_finder(pkgutil.ImpImporter, find_on_path)

register_finder(pkgutil.zipimporter, find_on_path)

に変更します。
その後、もう一度

pip list

でエラーを確認します。すると、少し出力が変化し、以下のようになっているはずです。

  File "/root/pythonproject/test/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py", line 2315, in <module>
    register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)
                               ^^^^^^^^^^^^^^^^^^^
AttributeError: module 'pkgutil' has no attribute 'ImpImporter'. Did you mean: 'zipimporter'?

下4行が以上のようになっていたら、pip/_vendor/pkg_resources/__init__.pyのファイルの

register_namespace_handler(pkgutil.ImpImporter, file_ns_handler)

 register_namespace_handler(pkgutil.zipimporter, file_ns_handler)

に変更します。 この状態で、

pip list

を実行すると、エラーが出ずに正常に動くはずです。 これで第一段階目が完了です。 これでも一応動くのですが、正常なコードではないためpipをアップグレードすることを推奨します。

第二段階目

pip list

を実行すると、モジュールが並んだ後に

[notice] A new release of pip is available: 23.0.1 -> 23.3.1
[notice] To update, run: pip install --upgrade pip

といった表示が出ると思います。この二行目の指示通り、

pip install --upgrade pip

を実行することで、pipが最新版にアップグレードされ、正常に動くようになります。
また、windows環境の場合は、アップグレード用のコマンドは

python -m pip install --upgrade pip

のようになります。

想定されるバグの原因

python3.12でpkgutilに変更がかかったことが問題だと考えられます。

終わりに

最後までお読みいただきありがとうございました。 今回の手法で修正できなかった・もっと簡単な修正法が見つかったという方はぜひコメントをよろしくお願いします。