nikkie-ftnextの日記

イベントレポートや読書メモを発信

2024年10月に採択された「PEP 735 – Dependency Groups in pyproject.toml」を読む。Dependency Groupsとな?

はじめに

やけにカラスが騒がしいな... nikkieです

シェイクス丸🐦‍⬛に告げられ、uv 0.4.27のリリースを機に、PEP 735 (2024/10/10 Accepted🎉)を知りました。
uvはもうサポートしたそうで、まずはこのPEPが何を提案しているかを掴みます。

目次

PEP 735 – Dependency Groups in pyproject.toml

Dependency Groups」なるものを導入しました。
pyproject.tomlに以下のように書けるようになります1(執筆時点ではuvのみがサポート。増えていくはずです)

[dependency-groups]
test = ["pytest>7", "coverage"]

PEPにはrequirements.txtを使う方法とextraを使う方法との違いが述べられています。
私はこのうちextraを使う方法との違いを以下のように理解しました2
このあと詳しく見ていきます

  • extraを使う方法は再配布するプロジェクトにしか適用できないが、Dependency Groupsは再配布しないプロジェクトでも利用できる3
    • 上の例のpyproject.tomlを、データサイエンスプロジェクトやDjangoで作るWebアプリにも設けられます!
  • extraを使う方法と違って、Dependency Groupsはプロジェクトをインストールせずに、指定したGroupだけをインストールできる
    • 上の例では、プロジェクト自体をインストールせずに、pytestとcoverageだけをインストールするように指定できます

※PEP 735はガッツリ読み込めているわけではないので、誤解しているようでしたらお知らせください🙏

nikkieの理解

PEP 735より前(extraを使う方法)

既存のライブラリを例にします。
メンテナしているSpeechRecognitionですが、PyPIで左カラムのメタデータにご注目!

Provides-Extra: audio, dev, whisper-api, whisper-local

これがextraです。
このライブラリはpyproject.tomlに移行しきれていなくてsetup.cfgなのですが4
https://github.com/Uberi/speech_recognition/blob/3.11.0/setup.cfg#L6-L16
pyproject.tomlで表すと以下のように定義しています

[project.optional-dependencies]
dev = ["flake8", "rstcheck"]
audio = ["PyAudio>=0.2.11"]
whisper-local = ["openai-whisper", "soundfile"]
whisper-api = ["openai"]
  • ライブラリのユーザが、オプションの機能を有効にするために指定
    • マイクを使いたい:pip install SpeechRecognition[audio]
    • OpenAIのWhisper APIを使いたい:pip install SpeechRecognition[whisper-api]
    • ローカルPCでWhisperのモデルを使いたい:pip install SpeechRecognition[whisper-local]
    • ちなみに複数指定できます(例:マイクに話した音声をWhisper APIへ):pip install SpeechRecognition[audio,whisper-api]
  • ライブラリの開発者が、環境構築のために指定
    • 静的解析ツール一式をインストールしたい:pip install -e SpeechRecognition[dev]
      • -eはeditable install(ソースコードをsite-packages下にコピーしないことで、コードの変更を再インストール無しで反映できるインストールです)

extraとして並んでいますが、実は対象者が違っていることを今回のPEPを機に知りました

PEP 735以後

今の私の理解では、以下のようにできると思われます

[project.optional-dependencies]
audio = ["PyAudio>=0.2.11"]
whisper-local = ["openai-whisper", "soundfile"]
whisper-api = ["openai"]

[dependency-groups]
dev = ["flake8", "rstcheck"]

extra(project.optional-dependencies)とDependency Groupsを分けました

  • extraはライブラリのユーザに、ライブラリのオプション機能の選択肢として見せたいので残した
    • PEP 735はextra(project.optional-dependencies)をdeprecateするものではないと理解しています
  • devをDependency Groupsとすることで、ライブラリの開発者の環境構築をライブラリのユーザに見せずに済む
    • ライブラリの開発者はdev groupだけのインストールも可能

(書いてみたことでより分かったのですが、)Dependency Groupsはprojectとは無関係ですから、再配布しないプロジェクトの場合も書くことができますし5、groupだけをインストールできるのでありがたいです。

終わりに

PEP 735提案で採択されたDependency Groupsを完全に理解しました。
私は再配布できるプロジェクトの経験が多く「別にextraでいいのでは」と思っていたクチです。
PEPを読んでextraには対象者が2通りいたことに気づき、再配布しないプロジェクトのpyproject.tomlにも書けることを知り、妥当な提案と思えています。
もしかして各種パッケージマネージャでプルリクチャンスですか!?!?(例えばpipはいつサポートするんだろう?)

PEP 735はAppendixで他の言語の状況にも触れていますし、Deferred Ideasもありますから、もう少し読んでみたい感はあります。
採択に至る議論も気になるところです


  1. https://peps.python.org/pep-0735/#rationale の例です
  2. https://peps.python.org/pep-0735/#limitations-of-extras を参照しています
  3. 私見6の2と3のことです
  4. 全部pyproject.tomlの例は sphinx-new-tab-link ですが、こちらはどのextraもライブラリの開発者向けです(dev, lint, testing, typecheck) ref: https://github.com/ftnext/sphinx-new-tab-link/blob/v0.6.1/pyproject.toml#L29-L33
  5. PEPには「Dependency Groups are not Hidden Extras」とあり、この記事でこの点も伝わっていたらいいなと思っています
  6. uvの言葉だとそれぞれ「ライブラリ」と「アプリケーション」です(ただしuvには再配布できるアプリケーションもあります)