Error [No module named 'pkg_resources']

ModuleNotFoundError: No module named 'pkg_resources' の直し方(setuptools が削除した)

FIX SUMMARY verified
Applies when
python:3.12-slimsetuptools (removed pkg_resources in 82.0.0)import pkg_resources with setuptools>=82 (removed) or without setuptools

Verified: reproduced in python:3.12-slim, then the No module named 'pkg_resources' signature was gone after the fix (exit 0).

これまで動いていたスクリプトやツールが、import pkg_resources の行で次のエラーを出して止まることがあります。

ModuleNotFoundError: No module named 'pkg_resources'

pkg_resources は、パッケージの情報を調べるために古くから使われてきたモジュールで、setuptools に同梱されて提供されてきました。このエラーは、その setuptools 側の事情で pkg_resources が手に入らなくなったために出ています。

そして、このエラーで検索すると多くのページが勧める pip install setuptools では、いまはもう戻りませんsetuptoolspkg_resources削除したからです。正しい直し方は、標準ライブラリの importlib.metadata に移行することです。

なぜ出るのか:setuptools が pkg_resources を削除した

pkg_resources が読み込めなくなる理由は2つあります。

  • setuptools がそもそも入っていないpython:3.12-slim のような軽量イメージや、setuptools を明示的に入れていない仮想環境では、pkg_resources も存在しません。
  • 新しい setuptoolspkg_resources を削除したsetuptools82.0.0 で pkg_resources を取り除きました(errfix の実測では、81.0.0 には入っていて、82.0.0 以降では ModuleNotFoundError になります)。そのため、新しい setuptools が入っていても pkg_resources は手に入りません。

2番目が、このエラーでいちばん誤解されやすいところです。No module named 'distutils'(Python 3.12 で標準ライブラリから消えた)は pip install setuptools で戻せますが、pkg_resources は逆で、82.0.0 以降の setuptools には含まれないので、新しい版を入れても戻りません。同じ「setuptools 由来のモジュールが無い」でも、直し方が反対になります。

直し方:importlib.metadata に移行する

pkg_resources がしていたことの多くは、標準ライブラリの importlib.metadata(Python 3.8 以降に同梱)で置き換えられます。追加のインストールは要りません。よくある書き換えは次のとおりです。

# 旧:インストール済みパッケージの版を取る
import pkg_resources
v = pkg_resources.get_distribution("requests").version

# 新:標準ライブラリで
from importlib.metadata import version
v = version("requests")

用途ごとの対応は次のようになります。

pkg_resources(旧)置き換え
get_distribution(name).versionimportlib.metadata.version(name)
parse_version(s)packaging.version.parse(s)packaging パッケージ。標準ライブラリではない)
iter_entry_points(group)importlib.metadata.entry_points(group=...)(Python 3.10 以降。3.9 以前は entry_points()[group]
resource_filename / resource_stringimportlib.resourcesfiles() など)
working_set の列挙importlib.metadata.distributions()

いくつか注意点があります。entry_points() は引数なしで呼ぶと全グループを返すので、グループで絞るなら上記のように group= を渡してください(Python 3.10 で API が変わり、3.9 以前は戻り値の辞書から [group] で引きます)。parse_version の移行先は importlib.metadata ではなく packaging.version.parse で、これは第三者の setup.pyfrom pkg_resources import parse_version している経路でよく踏みます。resource_filename のように実ファイルのパスが要る用途では、importlib.resources.files()Traversable を返すため、with importlib.resources.as_file(files(pkg).joinpath(name)) as path: の形でパスを取り出します(files() は Python 3.9 以降)。

importlib.metadata は標準ライブラリなので、setuptools の有無に左右されません。軽量イメージでも、新しい setuptools の環境でも、同じように動きます。読み込んでいるコードが自分のものなら、上の対応で書き換えるのが恒久的な直し方です。

応急処置:setuptools を古い版に固定する

依存している第三者ライブラリが pkg_resources を使っていて、自分では直せない場合は、当面 setuptools を削除前の版に固定して動かせます。

pip install "setuptools<82"

ただし、これは据え置きにすぎません。pkg_resources は非推奨で、これから使えなくなっていく方向です。固定したままにすると、setuptools の新しい版から取り残されます。そのライブラリが pkg_resources を使わない新しい版を出していないかを先に確認し、あれば上げるほうが後を引きません。無いなら、この固定は「対応版が出るまで」の一時的な逃げ道と考えてください。

切り分け(うまくいかないとき)

  • pip install setuptools したのに直らない:それがこのエラーの特徴です。setuptools 82.0.0 以降は pkg_resources を含みません。pip show setuptools で版を確認し、importlib.metadata への移行か、setuptools<82 への固定に切り替えてください。
  • 自分では pkg_resources を import していないのに出る:依存している第三者ライブラリやツールが内部で使っています。エラーのスタックトレースをたどると、どのパッケージが import pkg_resources しているかが分かります。そのパッケージを新しい版に上げるか、上記の setuptools<82 で当面しのぎます。
  • pkg_resources が非推奨だという DeprecationWarning が出るが動いてはいる:まだ pkg_resources が残っている(setuptools が 82.0.0 より前)状態です。動いてはいますが、上げると消えるので、いまのうちに importlib.metadata へ移しておくと、setuptools を上げたときにこのエラーを踏みません。
  • importlib.metadataPackageNotFoundError になる:これは別の問題で、指定した名前のパッケージがインストールされていない、あるいは配布名とインポート名が違う(例:scikit-learn を入れて sklearn で調べようとした)ことが原因です。version() に渡すのは、インポート名ではなく pip で入れた配布名です。

検証環境

  • python:3.12-slim、ネットワーク有り
  • 再現:setuptools==83.0.0 を入れた状態で pkg_resources.get_distribution("pip")ModuleNotFoundError: No module named 'pkg_resources' を出して終了コード 1
  • 修正:from importlib.metadata import version; version("pip") が終了コード 0

再現から修正までは errfix の検証ハーネスが機械的に確認しています。新しい setuptools(83.0.0)が入っていても pkg_resources が読み込めないこと、importlib.metadata に移すと同じ処理が通ることを、再現→修正→シグネチャ消滅として通しました。setuptools が 82.0.0 で pkg_resources を削除したことは実測(81.0.0 には存在・82.0.0 以降で消失)で、詳細は setuptools の変更履歴に拠ります。

検証(machine-verified)

この修正は python:3.12-slim のバージョン固定コンテナ内で再現し、修正後に No module named 'pkg_resources' のシグネチャが消えることを機械で確認しています。

verify — run-case.mjs
$ node run-case.mjs python/pkg-resources-not-found
● reproduce No module named 'pkg_resources' present ✓
● apply fix exit 0
● re-run No module named 'pkg_resources' gone ✓
PASS verified · python:3.12-slim · signature gone