開発者のためのSPDX実用編: pip-licensesでTransformersの依存ライセンスを確認する

2026年3月19日

PredNextの永井です。前回の記事では、SPDXライセンス識別子や式構文(AND/OR/WITH)の仕組みを紹介し、PEP 639への移行が進む中でもライセンス表記のばらつきが残る現状に触れました。

今回は Hugging Face Transformers を題材に、pip-licenses を使った依存ライセンスの確認を一通り試します。「一覧の把握」「禁止ライセンスのブロック」「許可リストによる制限」という3つのニーズに対してpip-licensesでどう対応できるかを紹介しつつ、表記ゆれやプラットフォーム差異の問題にも触れます。

セットアップ

今回は uv を使い、transformers[torch] を依存に持つプロジェクトを作成しました。

uv init hf-license-check --python 3.12
cd hf-license-check
uv add 'transformers[torch]' pip-licenses

Transformers の依存ライセンスを確認する

uv run pip-licenses で、インストール済みパッケージのライセンスを一覧表示できます。出力フォーマットは -f オプションで markdownjsoncsv などに変更でき、--with-urls でパッケージURLを、--with-license-file でライセンス全文も出力に含められます。ライセンス情報をまとめて提出する場合に役立ちます。

今回セットアップした transformers[torch] 環境のライセンス状況を、macOS(Python 3.12.7、pip-licenses 5.5.1)で確認し、ライセンスファミリーごとに集計した結果は次の通りです。

ファミリー件数
BSD 系15
MIT 系9
Apache 系7
MPL 系2
ISC1
PSF1

35パッケージのうち、GPL系ライセンスは0件UNKNOWN0件でした。すべてpermissive(寛容)なオープンソースライセンスです。

全35パッケージの一覧(クリックで展開)
NameVersionLicense
Jinja23.1.6BSD License
MarkupSafe3.0.3BSD-3-Clause
PyYAML6.0.3MIT License
Pygments2.19.2BSD License
accelerate1.13.0Apache Software License
annotated-doc0.0.4MIT
anyio4.12.1MIT
certifi2026.2.25Mozilla Public License 2.0 (MPL 2.0)
click8.3.1BSD-3-Clause
filelock3.25.1MIT
fsspec2026.2.0BSD-3-Clause
h110.16.0MIT License
hf-xet1.3.2Apache-2.0
httpcore1.0.9BSD-3-Clause
httpx0.28.1BSD License
huggingface_hub1.6.0Apache Software License
idna3.11BSD-3-Clause
markdown-it-py4.0.0MIT License
mdurl0.1.2MIT License
mpmath1.3.0BSD License
networkx3.6.1BSD-3-Clause
numpy2.4.3BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0
packaging26.0Apache-2.0 OR BSD-2-Clause
psutil7.2.2BSD-3-Clause
regex2026.2.28Apache-2.0 AND CNRI-Python
rich14.3.3MIT License
safetensors0.7.0Apache Software License
shellingham1.5.4ISC License (ISCL)
sympy1.14.0BSD License
tokenizers0.22.2Apache Software License
torch2.10.0BSD-3-Clause
tqdm4.67.3MPL-2.0 AND MIT
transformers5.3.0Apache 2.0 License
typer0.24.1MIT
typing_extensions4.15.0PSF-2.0

ライセンスの表記ゆれ

一覧を見ると、同じライセンスに対して複数の表記が混在していることがわかります。たとえばMITライセンスには「MIT License」と「MIT」、BSDライセンスには「BSD License」と「BSD-3-Clause」、Apacheライセンスには「Apache Software License」「Apache 2.0 License」「Apache-2.0」があります。

この表記ゆれは、PEP 639 への移行が進む過渡期の問題です。PEP 639 により、Pythonパッケージのライセンスメタデータは SPDX 式の License-Expression で記述する方向に移行が進んでいますが、2026年現在、従来の Classifier ベースの表記が残っているパッケージも多くあります。

この表記ゆれは、次のセクションで紹介するポリシーチェックに影響します。

pip-licenses でポリシーチェックする

pip-licensesには、ライセンスを自動で検証するためのオプションがあります。ここでは、よくある3つのニーズに対してpip-licensesでどう対応できるかを見ていきます。

ニーズ1:依存のライセンスをレポートにまとめたい

pip-licenses の基本機能で依存パッケージのライセンス一覧を取得できます。オプションを使えば、第三者への提出用レポートやSBOM作成の素材にも役立ちます。

uv run pip-licenses -f markdown --with-urls --with-license-file \
  --output-file=license-report.md

ニーズ2:GPLなどのcopyleftライセンスをブロックしたい(ブラックリスト)

商用プロジェクトで最も多いニーズは、GPL・AGPL等のcopyleftライセンスが依存に含まれていないことの確認でしょう。--fail-on--partial-match を組み合わせると、指定したライセンスが見つかった時点でエラー(終了コード1)にできます。

uv run pip-licenses --fail-on="GPL;AGPL;LGPL" --partial-match

--partial-match は部分文字列マッチを有効にするオプションです。GPL という文字列が GNU General Public License v3.0 にも GPL-3.0-only にもマッチするため、表記ゆれがあってもおおよそライセンスファミリー単位でブロックできます。

今回のTransformersの依存にはGPL系ライセンスが含まれていないため、このチェックは問題なくパスします。CIに組み込む場合も、このブロックリスト方式が最もシンプルで壊れにくいアプローチです。

ニーズ3:許可したライセンスだけに制限したい(ホワイトリスト)

より厳密なポリシー管理が必要な場合は、--allow-only で許可するライセンスのリストを指定し、それ以外が含まれていればエラーにできます。

ただし、--allow-only はデフォルトで文字列の完全一致でチェックするため、表記ゆれとSPDX複合式の両方に対応する必要があります。例えば、Apache-2.0CNRI-Python を個別に許可していても、Apache-2.0 AND CNRI-Python という文字列全体が許可リストになければ通りません。今回の依存には以下の複合式があります。

パッケージライセンス式意味
numpyBSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0コード部分ごとに5つのライセンスが適用される
packagingApache-2.0 OR BSD-2-Clause利用者がどちらかを選択できるデュアルライセンス
regexApache-2.0 AND CNRI-Python2つのライセンスが同時に適用される
tqdmMPL-2.0 AND MITMPL-2.0とMITの両方が適用される

表記ゆれと複合式の両方を考慮した許可リストで実行します。

uv run pip-licenses \
  --allow-only="MIT;BSD-3-Clause;Apache-2.0;ISC;PSF-2.0;0BSD;Zlib;CC0-1.0;CNRI-Python;\
MIT License;BSD License;Apache Software License;Apache 2.0 License;\
ISC License (ISCL);Mozilla Public License 2.0 (MPL 2.0);MPL-2.0;\
Apache-2.0 AND CNRI-Python;Apache-2.0 OR BSD-2-Clause;\
BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0;MPL-2.0 AND MIT"

これで全35パッケージがパスします。ただし、依存パッケージがSPDX式に移行したり新しいライセンス表記が追加されるたびにリストの更新が必要になるため、メンテナンスコストは高くなります。--partial-match--allow-only と組み合わせればリストを簡略化できますが、意図しないマッチのリスクもあるため、用途に応じて使い分けてください。

プラットフォームで結果が異なる

同じパッケージでも、プラットフォームによってライセンス構成は変わります。ここまでの結果はすべてmacOS上のものだったため、Dockerを使ってLinux環境でも同じ transformers[torch] をインストールし、pip-licensesを実行してみました。

Linux x86_64では、PyTorchの依存としてNVIDIA CUDAパッケージが16個追加でインストールされます。macOSでは全35パッケージがpermissiveなオープンソースライセンスでしたが、Linux x86_64では53パッケージ中16件(約30%)がプロプライエタリライセンスになります。

また、この16個のNVIDIAパッケージのライセンス表記も4種類に分かれています。

表記件数
Other/Proprietary License13nvidia-cublas-cu12 等
NVIDIA Proprietary Software1nvidia-cusparselt-cu12
LicenseRef-NVIDIA-Proprietary1nvidia-nvshmem-cu12
LicenseRef-NVIDIA-SOFTWARE-LICENSE1cuda-bindings

プロプライエタリライセンスにはSPDXの標準識別子が存在しないため、パッケージごとに異なる LicenseRef- 識別子が定義されています。上記16パッケージはすべて同じNVIDIA CUDA EULAに基づきますが、Classifierベース、旧メタデータ、SPDX LicenseRefの3方式が混在しています。

ライセンスチェックはデプロイ先と同じプラットフォームで実行するのが確実です。

GitHub Actions での自動化

CIにライセンスチェックを組み込む方法を紹介します。以下は、pyproject.tomluv.lock に変更があった際に自動でライセンスチェックを実行する設定例です。ここでは、シンプルで壊れにくいブラックリスト(--fail-on)方式を採用しています。

GitHub Actions のワークフロー例(クリックで展開)
name: License Check

on:
  pull_request:
    paths:
      - 'pyproject.toml'
      - 'uv.lock'

jobs:
  license-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: astral-sh/setup-uv@v4

      - name: Install dependencies
        run: uv sync

      - name: Check licenses
        run: |
          uv run pip-licenses \
            --fail-on="GPL;AGPL;LGPL;EUPL;SSPL" \
            --partial-match

      - name: Generate license report
        if: always()
        run: uv run pip-licenses -f markdown --with-urls > license-report.md

      - name: Upload license report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: license-report
          path: license-report.md

何も設定しなければCIは ubuntu-latest(Linux x86_64)で動くため、前のセクションで見たとおりNVIDIA CUDAパッケージなどが追加される可能性があります。プロプライエタリライセンスのパッケージを許容する場合はそのまま、除外したい場合は --fail-on にライセンス表記を追加するか、--ignore-packages で特定パッケージを除外してください。より厳密に --allow-only で管理する場合は、前述の表記ゆれ・複合式への対応が必要です。

pip-licenses 以外のツール

pip-licensesはPythonのパッケージメタデータのみを対象としています。コンテナイメージを配布する場合は、イメージ全体のファイルシステムをスキャンできるツールが有用です。ここでは syft(Anchore社のSBOMジェネレータ)と trivy(Aqua Security社のセキュリティスキャナ)を使い、前述のDockerイメージをスキャンした結果を比較します。

3ツールの比較概要

項目pip-licensessyfttrivy
アプローチPython メタデータ参照イメージ全体をスキャン → SBOM 生成イメージ全体をスキャン → ライセンス分類
Python パッケージ検出数537070
OS パッケージ検出不可可能(173パッケージ)可能(624ライセンスエントリ)
ライセンス表記Classifier / SPDX 混在そのままSPDX 識別子に正規化(一部 LicenseRef)SPDX 識別子に正規化
重大度分類なしなしあり(notice / reciprocal / restricted)

Pythonパッケージの検出数に差があるのは、ツールの検出対象が異なるためです。Dockerイメージ内で pip list に登録されているパッケージは58件です。pip-licensesはここからシステムパッケージ(pip、setuptools)と自身の依存(pip-licenses、prettytable、wcwidth)の計5件をデフォルトで除外するため、53件になります。syft・trivyはファイルシステムを直接スキャンし、setuptools内部のvendoredパッケージ12件も検出するため70件になります。

ライセンス表記の正規化

syft・trivyはライセンス表記をSPDX識別子に正規化します。pip-licensesとの比較を以下に示します。

パッケージpip-licensessyfttrivy
PyYAMLMIT LicenseMITMIT
PygmentsBSD LicenseBSD-2-ClauseBSD-3-Clause
httpxBSD LicenseBSD-3-ClauseBSD-3-Clause
Jinja2BSD LicenseNOASSERTIONBSD-3-Clause
accelerateApache Software LicenseLicenseRef-ApacheApache-2.0
transformersApache 2.0 LicenseLicenseRef-Apache-2.0-LicenseApache-2.0
certifiMozilla Public License 2.0 (MPL 2.0)MPL-2.0MPL-2.0

trivyは正規化の一貫性に優れ、Classifierベースの Apache Software LicenseApache-2.0 のようにSPDX識別子へ変換しています。syftは一部を LicenseRef-* にフォールバックする傾向があり、Jinja2では NOASSERTION になるケースもありました。

ただし、正規化が常に正確とは限りません。上の表でPygmentsはtrivyが BSD-3-Clause、syftが BSD-2-Clause と判定していますが、Pygmentsの実際のライセンスはBSD-2-Clauseであり、syftのほうが正確です。trivyは BSD License を一律に BSD-3-Clause へ変換する傾向があります。

NVIDIAパッケージではさらに大きな差異が見られます。たとえばnvidia-nccl-cu12は、pip-licenses・trivyでは Other/Proprietary License ですが、syftは BSD-3-Clause と報告します。NCCLのソースコードは実際にはApache-2.0(一部BSD)で公開されており、いずれのツールも正確ではありません。NVIDIA CUDA関連パッケージのライセンスは複雑なため、個別確認を推奨します。

このように、同じパッケージでもツールによって判定結果が食い違うことがあります。単一ツールの出力を鵜呑みにせず、クロスチェックやライセンス原文の確認が必要です。

trivy の重大度分類

trivyはライセンスをカテゴリと重大度で自動分類するため、ポリシー設計に直接活用できます。

カテゴリ重大度該当ライセンス例
noticeLOWMIT, BSD-3-Clause, Apache-2.0, ISC 等
reciprocalMEDIUMMPL-2.0(certifi, tqdm)
restrictedHIGHLGPL-3.0-only(autocommand)
unknownUNKNOWNNVIDIA プロプライエタリ, PSF-2.0 等

pip-licenses では見えない vendored パッケージ

pip-licensesでは検出できないLGPLv3パッケージが、syft・trivyで発見されました。setuptoolsの _vendor/ ディレクトリにvendoringされた autocommand です(syft: LicenseRef-LGPLv3、trivy: LGPL-3.0-only、重大度: HIGH)。

transformers[torch]
  └→ torch
       └→ setuptools  (Python 3.12以上で必須依存)
            └→ _vendor/autocommand  (vendored, LGPLv3)

vendoredパッケージは pip list に現れないため、pip-licensesの --fail-on="GPL;AGPL;LGPL" でも検出できません。setuptoolsがvendoringしている12件のうち、autocommandだけがLGPLv3(コピーレフト系)です。

autocommandは実行時には読み込まれません。importしているのはsetuptools内部の開発支援ユーティリティのみで、transformers / torchのワークフローとは無関係です。ただし、コンテナイメージへの同梱が「配布」に該当するかは解釈が分かれうるため、厳格なライセンス監査では指摘対象になりえます。

OS レベルのライセンス

コンテナイメージの配布では、OSパッケージのライセンスも考慮が必要です。trivyはコンテナ内のDebianパッケージ(bash, coreutils, tar等)もスキャンし、624件のライセンスエントリを報告しました。Pythonパッケージだけでは「GPLなし」でも、OSパッケージにはGPL-2.0 / GPL-3.0が多数含まれています。

ツールの使い分け

目的推奨ツール理由
開発時のライセンス確認pip-licensespipの依存ツリーに沿った見やすい出力。CIに組み込みやすい
コンテナイメージの配布syft / trivy物理的に同梱される全ファイルのライセンスを網羅
ライセンス監査・コンプライアンス複数ツールの併用pip-licensesだけではvendoredパッケージを見落とす

まとめ

pip-licensesを使えば、Pythonプロジェクトの依存ライセンスを手軽に一覧できます。ポリシーチェックの方法はニーズに応じて選べます。

  • レポート生成-f markdown --with-urls):依存ライセンスを把握する
  • 禁止ライセンスのブロック--fail-on + --partial-match):GPL等のcopyleftを排除したい場合に最もシンプルで壊れにくい
  • 許可リストによる制限--allow-only):最も厳密だが、表記ゆれやSPDX複合式への対応が必要でメンテナンスコストが高い

依存ライセンスの管理には、以下の点に注意してください。

  • 表記ゆれ:ClassifierベースとSPDX式の混在により、同じライセンスに複数の表記がある
  • プラットフォーム差異:プラットフォームによりライセンス構成も変わるため、デプロイ先と同じ環境でチェックすべき
  • vendoredパッケージ:pip-licensesでは検出できないvendoredパッケージが存在する。コンテナ配布時はsyft・trivyの併用が有効

pip install の1行にどれだけのライセンスが関わっているかをまず把握し、そこからライセンス管理を始めてみましょう。

お仕事募集中です

PredNextでは現在、お仕事のご依頼を募集しています。自然言語処理や画像処理などのAI技術が得意で、特に軽量化・高速化を強みにしています。ご興味のある方はお問い合わせフォームからご連絡ください。

シェアする: