🐍

uvでライブラリをグルーピングして最小限の依存関係で起動できるようにする

に公開

始めに

Pythonに限らずアプリケーションを大規模で運用していくほどライブラリの依存関係が増えていきます。その時にAPIとバッチ等の用途に応じたアプリケーションごと分割する方法もありますが二重管理が面倒になります。JavaではGradleを使用してマルチプロジェクト構成にしておくことで、必要なライブラリだけで起動するようにできました。

今回の記事では、Pythonのuvを使用してライブラリをグルーピングすることで、必要なライブラリを最小限にする方法を記載します。

環境

  • Python
    • 3.13
  • uv
    • 0.7.2

実装

ライブラリのグルーピング

dependency-groupsに分割したい単位で集約します。今回の場合は、dependenciesで全アプリケーションに依存させたいライブラリを残し、他はapi, auth, worker, devに分割しました。

[project]
dependencies = [
    "sqlmodel>=0.0.21",
    "pydantic[email]>=2.9.2",
]

[dependency-groups]
api = [
    "fastapi[standard]>=0.115.12"
]

auth = [
    "pyjwt>=2.8.0",
    "pyotp>=2.9.0",
]

worker = [
    "celery>=5.5.2",
]

dev = [
    "ruff>=0.7.3"
]

なお、該当のグループにライブラリを追加するときは次のコマンドで入れられます。下手に手でpyproject.tomlをいじるより、uvに任せてグループを作ってから少しずつ移行するのがオススメです。

uv add --group dev pytest

使用方法

uv sync時に必要なグループだけ指定してください。なお、uvの仕様でdevは特に指定がない限りインストールされるので、明示的な除外が必要です。

# api (+dev)だけインストール
uv sync --group api

# api と auth (+dev)だけインストール
uv sync --group api --group auth

# dev を除外したい
uv sync --no-group dev

# 全部対象
uv sync --all-groups

なお、開発環境でグループを指定してインストールさせる指定をするのは面倒なので、pyproject.tomlにデフォルトインストール対象も記載しておくと便利だと思います。

[tool.uv]
# 全部指定する場合
default-groups = "all"
# インストール対象を絞りたいときに
#default-groups = ["api", "auth", "dev"]
uv sync

ソースコード

終わりに

Pythonはインストールイメージのサイズが大きくなりがちなので、こういうことでサイズを削減したいと考えています。ただ、ライブラリ管理を厳密にやったことで実行時に必要なライブラリが読み込まれていないエラーが発生する可能性もあるので、実際に本番運用に適用するかは悩んでいます。

ただ、バッチ処理ではFastAPIは不要ですし、少しでも起動が早いほうが正義だと思うので、CI/CDの管理工数も考えて本番にも取り入れていきたいです。

参考情報

Discussion