7 ポイント 投稿者 GN⁺ 2025-06-25 | 2件のコメント | WhatsAppで共有
  • uv に移行すると、Python 依存関係のインストール速度が pip 比で 約10倍 高速化し、別途 venv を用意しなくても非rootユーザーで実行可能
  • pyproject.toml ベースで上位依存関係だけを記述すれば、uv が自動で lock ファイルを管理し、依存関係ツリーと正確なバージョン管理は pip freeze より優れている
  • Dockerfile では uv および uvx バイナリのコピー、pyproject.toml/uv.lock ファイルの使用、環境変数の設定 など、段階的な変更が必要
  • uv sync/add/remove、uv:outdated などのコマンドで、依存関係の追加・削除・更新やパッケージの最新バージョン確認などを簡単に管理できる
  • lock ファイルを継続的に管理し依存関係を更新できるため、協業やデプロイ環境で一貫性を確保しやすい利点がある

10倍高速な依存関係インストール、venv 不要、非root環境の構成

  • uv は従来の pip と比べて、Python プロジェクトの依存関係インストール速度を大きく改善するツール
  • uv 導入により、Flask/Django などさまざまなプロジェクトで、従来の pip 比 約10倍速いインストール速度を体験できる
  • 別途仮想環境(venv)を作らなくても、コンテナ内で 非rootユーザーとして安全に実行できる

pyproject.toml vs requirements.txt

  • 従来の requirements.txt の代わりに pyproject.toml ファイルへ上位依存関係だけを記述すれば、uv が自動で uv.lock ファイルを生成する
    • pyproject.toml に [project] dependencies 項目を追加
    • 既存の requirements.txt を削除
  • uv の lock ファイルは pip freeze の結果に似ているが、正確な依存関係ツリーとバージョン情報を備えている

Dockerfile 構成の変更

  • uv および uvx バイナリをコンテナへコピーして使用する(静的コンパイルされた Rust バイナリを使用)
  • 既存の requirements*.txt の代わりに pyproject.toml、uv.lock* ファイルをコピー
  • 環境変数を追加:
    • UV_COMPILE_BYTECODE=1: ビルド段階でバイトコードに事前コンパイル
    • UV_PROJECT_ENVIRONMENT="/home/python/.local": 別途 venv を作成せず、特定のパスにパッケージをインストール
  • 依存関係インストールのコマンドも既存の pip3-install から uv-install に変更
    • 例: RUN chmod 0755 bin/* && bin/uv-install

依存関係の追加、削除、更新などの管理

  • 別途 run スクリプトでコンテナ内の uv コマンドを実行できる
    • ./run deps:install: イメージをビルドした後、lock ファイルをホストへ書き出しながらインストール
    • ./run deps:install --no-build: ビルドせず lock ファイルだけを更新
    • ./run uv add mypackage --no-sync: pyproject.toml と lock ファイルだけを更新し、実際のインストールは別途実行
    • ./run uv remove mypackage --no-sync: パッケージを削除
    • ./run uv:outdated: 現在の依存関係の最新バージョンを確認

動画と実践ガイドを提供

  • uv 導入、pyproject.toml の作成、Dockerfile の変更、lock/sync コマンド、依存関係の追加/削除、最新バージョン確認など、実際のデモと git diff の例を提供
  • Flask、Django 2つのプロジェクトのマイグレーション diff も参考にできる

2件のコメント

 
yangeok 2025-06-26

ちょうどPoetryでデプロイしていたものを移行しようと思っていたところだったので、安定していてシンプルそうですね^^

 
GN⁺ 2025-06-25
Hacker News のコメント
  • uv は、pyenv、virtualenv、pip を直接置き換えるワークフローをサポートしている点に注目する必要がある。lockfile や pyproject.toml によって強制される方式ではない。uv python pin <version> コマンドで現在のディレクトリに .python-version ファイルを生成し、uv virtualenv で pyenv のようにそのバージョンの Python をダウンロードして .venv 仮想環境を作成し、uv pip install -r requirements.txt で requirements.txt のパッケージをインストールし、uv run <command>.env ファイルの環境変数も含めてコマンドを実行できる。ただし、環境変数の優先順位の問題には注意が必要(関連 issue

    • uv の柔軟性は本当に驚くべきレベル。pip で 10 分かかる作業を uv なら 20〜30 秒で処理できる体験がある
    • uv を使うきっかけはまさにこの点。とても便利。ただし uv pip が遅い場合があり、原因は分からないが、会社のネットワーク環境の問題かもしれない
    • Python のバージョン情報は pyproject.toml にも保存される認識だが、.python-version ファイルは本当に必要なのか気になる
  • # 常に最新の lock file を保証するスクリプト
    if ! test -f uv.lock || ! uv lock --check 2>/dev/null; then
      uv lock
    fi
    

    このやり方は lock file の存在意義を薄れさせてしまう。ファイルがないか無効な場合、lock file に深刻な問題が起きている状態なので、そのプロジェクトに詳しい人が直接対応するのが望ましい。そうでなければ lock file を置く意味がない。CI で lock file を自動的に置き換えて混乱を招く可能性がある

    • (筆者の返信)lock file が無効な場合、黙って新しいファイルを作るわけではない。uv lock で親切なメッセージとともに失敗し、シェルスクリプトの errexit によって即座に中断される。uv lock --check のエラーリダイレクトは、同じエラーが 2 回表示されるのを防ぐため。lock file を意図的に壊してスクリプトを実行すると、具体的なエラーメッセージとともにビルドが停止する。スクリプトは if-else に変えてより明確に修正した。lock file がない場合は新たに生成するのが正しい流れで、そのとき生成してコミットすればよい
    • uv sync --locked オプションでこの点はカバーされる。lock file がないか古くなっていれば明確に失敗する。常に --locked オプション付きでビルドすることを勧める
    • Python の世界では lock file をバージョン管理にあまり入れず、インストール過程の「奇妙な手順」として扱うことが多い
    • このやり方には深刻なバグがある。--frozen フラグを使うと lock file が更新されないのが正しい動作のはずだが、実際には逆に動く。lock file がないか一致しない場合は人が介入すべきという点には同意する
    • それでも lock file がないなら初回実行か、どうせ git upstream 経由で上書きされる。壊れている場合は誰かがインストールでミスしたのであり、新しく作る方法が事実上唯一合理的だと思う。まれな例外だが、簡単な処理としては十分だ
  • Python ツールが Python 以外の言語で開発されることには完全に反対の立場。C がすでにあり、CPython が標準化されているのに、わざわざ新しい言語(例: Rust)は必要ない。Pendulum パッケージが 3.13 対応を 7 か月以上遅らせたのも、Rust ネイティブ部分のためにその問題を修正できる人が不足していたからだと見ている。もし C だったなら自分で直していただろう。(関連 issue)理想的には、Rust のような外部言語で高速な datetime を作りたいなら、複数言語から使える FFI 形式で作るべきだ。Rust ベースにはまだあまり好感が持てず、Linux コミュニティが嫌がるのも理解できるようになった

    • この観点は尊重するが、uv のようなツールを Rust で作るのは良いアイデアだと思う。Python 管理ツールを Python で作ると「鶏が先か卵が先か」の状況になる。Python ツールを使うには Python 自体が先にインストールされていなければならず、どの Python バージョンが使われるのか、ツールが使うライブラリと実際のアプリの衝突可能性、環境変数管理、デバッグなど、すべてが複雑になる。一方、Rust などでビルドされたバイナリツールなら、ただ受け取って使えばよく、こうしたことを気にせず即座に動作する。ユーザーはツールがどの言語で作られているかをそれほど気にする必要はない
    • Python は好きだが、uv の手軽さと速さは比べものにならない。EOL 済みサーバーで最新の Python が必要なときや、小さなスクリプトに依存関係だけを素早く入れたいときには、どちらも uv がベストだと思う。同意する部分もあるが、以前は pure Python だけで書いていて、徐々に C extension を使い、限界を感じるといっそほぼ全部を C で書きたくなった。C は難しいので最近は Rust へリファクタリング中。外部コードが内部より多くなるなら、いっそ全部別言語にしたほうがよい
    • ツールは Python だけで作るべきだという考えが強いなら、遅い Pylint を待っている間、自分は散歩に行っているだろう
    • さまざまな言語のサポートはユーザーにとって大きな負担ではない。ツールは速く、問題をうまく解決してくれれば十分。実際、速度ははるかに速い。管理ツールは開発者向けであり、利用対象のためのツールだ
    • どの言語で作られていても、機能さえ果たせばよいと思う。Python ユーザーがツールに貢献できるという利点はあるが、ツールが目的をきちんと果たすなら言語は関係ない。むしろ環境問題に直面したとき、Python で作られたツールはその問題の影響まで受けてしまうことがある
  • pip の代わりに uv を使うときは注意が必要。デフォルトでは pyc ファイルを生成しないので、サービス起動が遅くなる可能性がある(参考

    • コンテナで uv を使うなら、ガイド文書のほうが参考になる(Docker ガイド
  • uv を flask コンテナで使ってみると、ビルド時間の差が退屈に感じるほど大きいだけでなく、インストール過程が非常に予測可能になる。pip で依存関係のバージョンが変わる戸惑いがない。pyproject.toml を使い、uv lock すれば終わり。docker では pyproject.tomluv.lock ファイルだけをコピー(HOT COPY)して uv sync --frozen --no-install-project を実行すれば、アプリコードを飛ばしてインストールレイヤーをキャッシュできる。パッケージ 1 つだけ変わってもレイヤー全体を再ビルドしなければならない苦しさを知っていれば、この機能がなぜ重要か分かる。環境変数 UV_PROJECT_ENVIRONMENT=/home/python/.local を使えば、venv なしでベースイメージを pre-warm してビルド共有やインフラコスト削減が可能。UV_COMPILE_BYTECODE=1 オプションでビルド時に .pyc ファイルを生成できる。mutable environment を排除し、reproducibility を強制できるので、今ではビルドが失敗したら lockfile に原因があると明確に分かる

  • 2025 年になっても Python パッケージングと依存関係管理は相変わらず混乱している

    • みんなが uv を使っていないから混乱が続いているのだと思う
    • 言語設計の初期からこうした部分をきちんと整えることが重要だという教訓だ。v2.0 以降に先送りしてはいけないし、metadata を実行スクリプトに入れる前によく考えるべきで、ある言語には合っていても Python には向かない方式かもしれない
    • 自分は依存関係の問題を一度も経験したことがない。requirements.txt と venv だけで十分だ
    • 依存関係管理は今でもひどく、今度は Rust まで追加された
  • uv、pip、conda など Python パッケージマネージャーの安全性比較が気になる。速度も良いが、パッケージマネージャーの安全性のほうがはるかに重要だと思う

    • uv は pip より安全寄りだ。任意コード実行なしで dependency を解析し、デフォルトでパッケージハッシュを検証し、typosquatting などさまざまなリスクを回避する。速度と再現性にも優れる(技術紹介互換性ドキュメント
    • ただし本質的には、すべてのパッケージマネージャーは検証されていないサードパーティコードをダウンロードして実行することになる。uv と pip の実装上の安全性の違いよりも、そもそも外部コードに対するポリシーを整備していないことのほうが重要なリスク要因だ
  • PyPI にパッケージを公開する立場としては、個人的には速度の速さから uv を使いたいが、pip と完全に同じように動く保証がないなら簡単には切り替えられない。ユーザーが pip install xxx でエラーに遭遇したら、自分も同じ環境で再現・デバッグしなければならないからだ

    • pip と 100% 同じ方式ではない。大きな違いは 互換性ドキュメント で扱われている。一部は標準に合わせる過程での違いであり、一部は uv 固有の設計選択だ
  • UV は、実行するだけでうまく結果を出してくれる、近年の Python パッケージングにおける最も前向きな変化の 1 つだと思う

  • 本番環境コンテナ構築に uv を使う優れたガイド文書も紹介されている(ガイドを見る