pip install(自作パッケージや、setuptools_scm を使うライブラリをソースから入れるとき)の途中で、ビルドに入り、次のエラーで止まることがあります。
LookupError: setuptools-scm was unable to detect version for /path/to/pkg.
続けて、setuptools_scm 自身がヒントを出します。
Make sure you're either building from a fully intact git repository or PyPI tarballs. Most other sources (such as GitHub's tarballs, a git checkout without the .git folder) don't contain the necessary metadata and will not work.
このエラーの上には、pip の傘のメッセージ(error: subprocess-exited-with-error や error: metadata-generation-failed)が出ます。ただしこの傘の行は pip の版や落ちた段で変わり、それ自体は原因を教えてくれません。原因を名指ししているのは、その内側の setuptools-scm was unable to detect version の行です。まずここを読んでください。
これは、そのパッケージが バージョン番号を git(タグや履歴)から自動で決める設定になっていて、ビルドしている場所に .git が無いために、版を決められずに止まったものです。
なぜ git を見に行くのか
setuptools_scm は、pyproject.toml に版番号を直書きする代わりに、SCM(git など)のタグや履歴から版を導出するツールです。[project] の version を dynamic にし、[tool.setuptools_scm] を置くと有効になります。
[build-system]
requires = ["setuptools>=61", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"
[project]
name = "demo-scm"
dynamic = ["version"]
[tool.setuptools_scm]
pip がこのパッケージをビルドするとき、メタデータを作る段で setuptools_scm が呼ばれ、版を計算しようとします。その材料が git のタグや履歴です。だから .git ディレクトリが見当たらないと、材料が無く、unable to detect version で止まります。PyPI からダウンロードした sdist(ソース配布物)には版が静的な情報として同梱されているので、そちらは git が無くても通ります。
なぜ .git が無いと出るのか
手元では、リポジトリを git clone した中で作業しているので、.git があり版が決まります。エラーになるのは、ソースは持っているのに .git がそこに無いときです。次のような場面で起きます。
- GitHub の「Download ZIP」や、
codeloadの tarball からビルドしている:これらは.gitを含みません。ヒント文が名指しするとおりです。 - Docker の
COPY . .で.gitが入っていない:.dockerignoreが.gitを除外していると、ビルドコンテキストに履歴が届かず、コンテナ内のビルドだけで出ます。手元のpip install .は通るのに CI・イメージビルドで落ちる、の典型です(.gitignoreは Docker のビルドコンテキストには関係しません。参照されるのは.dockerignoreです)。 git archiveで作った tarball からビルドしている:git archiveは既定で.gitを含まないアーカイブを作るので、版の材料が残りません。- sdist を展開し直した、コピーしただけのソース:
.gitを伴わないコピーは同じ症状になります。
いずれも「手元では出ないのに、別の環境でだけ出る」形で、.git がビルド地点に届いているかどうかが分かれ目です。
直し方1:版を明示する(.git を用意できない CI・コンテナ向け)
.git を持ち込めない環境では、版を環境変数で直接与えるのが応急手当になります。setuptools_scm が推奨するのは、対象パッケージ名を含む形です。
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DEMO_SCM=0.1.0 pip install .
DEMO_SCM の部分は、パッケージ名(demo-scm)を PEP 503 に従って正規化した形です。大文字にし、.・-・_ の連続を単一の _ にまとめます(demo-scm → DEMO_SCM、my.pkg-name → MY_PKG_NAME)。名前ごとに版を指定できるので、複数の setuptools_scm パッケージを同時にビルドしても取り違えません。パッケージを問わず一律に適用したいときは、名前を含まない SETUPTOOLS_SCM_PRETEND_VERSION も使えますが、そのビルドで走るすべての setuptools_scm パッケージに同じ版を与える点に注意してください。
Docker なら、ビルド段でこの環境変数を渡します。
ENV SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DEMO_SCM=0.1.0
RUN pip install .
これで版が確定し、git は要りません。ただし与える版は自分で管理することになります(タグと自動で同期はしません)。
直し方2:.git を届ける/配布物から入れる(恒久)
版を git 由来に保ったままにするなら、ビルドする場所に .git を届けるのが本筋です。
- Docker では
.gitを除外しない:.dockerignoreから.gitを外すか、.gitを含む段でビルドします。マルチステージなら、SCM 情報を持つ段でpip install .(または wheel を作成)して成果物だけ後段へ渡す形にできます。 - 第三者のパッケージを GitHub の ZIP から入れている場合:ZIP ではなく、PyPI のリリース(
pip install <パッケージ名>)か、git+URL(pip install "git+https://github.com/user/[email protected]")から入れます。PyPI の sdist には版が同梱され、git+は履歴ごと取得するので、どちらも setuptools_scm が版を決められます。 - 自作パッケージを配る側なら、タグを打ってから sdist/wheel をビルドし、それを配布します。利用者はビルドし直さないので、この問題を踏みません。
切り分け(うまくいかないとき)
- 傘のメッセージ(
subprocess-exited-with-error/metadata-generation-failed)しか見ていない:その内側までスクロールしてsetuptools-scm was unable to detect versionを探してください。傘の文言は pip の版や落ちる段で変わることがありますが、内側の原因行を読めば切り分けられます。 - 手元では通るのに CI・Docker だけで落ちる:まず
.gitがビルド地点に届いているかを疑います。.dockerignoreの.git除外、Download ZIP、git archive、.gitを伴わないコピーのいずれかであることがほとんどです。 SETUPTOOLS_SCM_PRETEND_VERSION_FOR_...を設定したのに、まだ同じエラーが出る:接尾辞の綴りを確認します。パッケージ名を PEP 503 で正規化した形(大文字化し、.・-・_の連続を単一の_に)と合っているかを見てください(名前を含まないSETUPTOOLS_SCM_PRETEND_VERSIONで切り分けるのも手です)。.gitはあるのに版が意図しない値になる:これは版を導出できない本エラーとは別で、リリースタグを打っていないケースです。既定ではタグからの距離を含む開発版(0.1.dev5+g<hash>のような形)になります。素の0.0.0はfallback_versionを設定しているときの値です。タグを打つか、明示的に版を与えてください。- shallow clone や worktree で版がずれる:これらは
.gitを保持するので本エラーは出ませんが、タグが履歴に見えないと版がずれることがあります。GitHub Actions のactions/checkoutは既定が浅い取得(fetch-depth: 1)なので、タグが要るならfetch-depth: 0を指定します。 - 内側が
error: command 'gcc' failedやcan't find Rust compilerになっている:これは版検出でなく、ソースビルドに要るコンパイラやビルド道具が無い別問題です。対処は error: command ‘gcc’ failed と can’t find Rust compiler を参照してください。
検証環境
python:3.12-slim、ネットワーク有り- 再現:
setuptools_scmを使う最小パッケージ(上のpyproject.toml)を、.gitの無いディレクトリでpip installすると、setuptools-scm was unable to detect versionを出して終了コード 1 - 修正:
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_DEMO_SCM=0.1を与えて同じpip installを実行すると、終了コード 0
再現から修正までは errfix の検証ハーネスが機械的に確認しています。ここでは書き込み可能なディレクトリへソースを写してからビルドし(実環境の pip install . と同じ条件にするため)、.git が無いと版を決められないこと、版を環境変数で与えると同じインストールが通ることを、再現から消滅まで通しました。エラー文言とヒント文は実機出力から引用しています。Docker の COPY や GitHub の ZIP、環境変数名の正規化規則については、機械検証の対象は上記の1点に限り、一般的な引き金として setuptools_scm のドキュメント(版の上書きと正規化)に沿って書いています。