pip-compileでMetadataGenerationFailedの例外が起きる

pip-compileは、pip-toolsパッケージ(jazzband/pip-tools)に含まれるコマンドで、 Pythonパッケージのリストrequirements.inから、 依存ツリーのライブラリバージョンリストrequirements.txtを出力してくれる便利なツールである。

入力例 requirements.in
django
requests
gunicorn
mysqlclient
python-dateutil
requests-oauthlib
schedule
pip-compile requirements.in
出力例 requirements.txt
#
# This file is autogenerated by pip-compile with python 3.8
# To update, run:
#
# pip-compile requirements.in
#
asgiref==3.5.2
# via django
backports-zoneinfo==0.2.1
# via django
certifi==2022.6.15
# via requests
charset-normalizer==2.0.12
# via requests
django==4.0.5
# via -r requirements.in
gunicorn==20.1.0
# via -r requirements.in
idna==3.3
# via requests
mysqlclient==2.1.1
# via -r requirements.in
oauthlib==3.2.0
# via requests-oauthlib
python-dateutil==2.8.2
# via -r requirements.in
requests==2.28.0
# via
# -r requirements.in
# requests-oauthlib
requests-oauthlib==1.3.1
# via -r requirements.in
schedule==1.1.0
# via -r requirements.in
six==1.16.0
# via python-dateutil
sqlparse==0.4.2
# via django
urllib3==1.26.9
# via requests
# The following packages are considered to be unsafe in a requirements file:
# setuptools

ところでPythonパッケージは、システムパッケージの事前インストールを要求することがある。 以下、システムパッケージ名はDebian/Ubuntuを想定する。

依存先が動的ライブラリであれば、モジュールのimport時に例外を投げる作りになっている場合もあるが、 Pythonパッケージのインストールと同時にC言語コードからネイティブバイナリをコンパイルするような作りになっている場合には、 コンパイラや依存関係のヘッダファイルなどが必要になることがある。

このような依存関係が不足しているとき、pip-compileは以下のようなエラーログを出力する。

pip._internal.exceptions.MetadataGenerationFailed: metadata generation failed

ただし、このエラーログが出力されたとき、必ずしも原因が依存関係の不足とは限らない点は指摘しておく。 いまのところpip-compileには、パッケージのインストール処理が記述されたsetup.pyの実行時に例外が起きたとき、その例外の内容が隠されてしまう問題があり、他に原因がある可能性もある。 他に原因がありそうなときには、venvで仮想環境を作るなどして、一度通常のpip installを実行してみて、エラーログを確認して対処するとよいと思う。

ともあれ、このようなpipに管理されていない依存関係は、 ドキュメントが整備されている通常のPythonパッケージであれば、 PyPIやパッケージの公式ドキュメントに利用者向けの記載があるはずなので、 そちらを確認してインストールしてからpip-compileを実行すると解消するだろう。

例えば、PostgreSQLドライバのpsycopg2は、以下のようなパッケージの事前インストールが必要である。

  • Cコンパイラ
  • Pythonのヘッダ
  • Postgresライブラリlibpqのヘッダ
sudo apt install python3-dev libpq-dev build-essential

MySQLドライバのmysqlclientは、以下のようなパッケージの事前インストールが必要である。

sudo apt install python3-dev default-libmysqlclient-dev build-essential