
Pythonのパッケージ管理ツール「uv」を試してみた

IT技術

概要
Pythonのパッケージ管理ツールuvを使ってみたので、使い心地をざっくり書いてみます。
記事の要約
- 趣味プロジェクトのパッケージ管理ツールをuvへ移行させた
- 使ってみたらとても便利だったので、普段の開発ユースケースでどう運用するのが良さそうか整理したい
- uvはいいぞ
環境
- Python: 3.13.2
- uv: 0.7.8
背景もとい前置き
Pythonは主に趣味で触っていましたが、パッケージ管理で苦戦することが多かったです。
Dockerを使うとIDEと噛み合わせが悪かったり、いろんなツールを試すと仮想環境とパッケージ管理が複雑になってきて
メンテナンスが大変になったりと、色々迷走してきました。
Pythonパッケージをアプリケーションごとに隔離し、パッケージを開発・本番環境でシンプルに扱えるような
ツールを探し続けているので、最近評判のuvに手を出してみようと思います。
記事の構成
最初に公式ドキュメントから、uvの概要や基本的な使い方を押さえておきます。
全体像が見えてきたら、普段の開発でよくあるユースケースをuvでどう実現するのか整理してみます。
やりたいことをuvで実現する方法から、uvの使い心地はどんなものか見ていきたいです。
uvを知る
特徴
まずは公式ドキュメントで特徴が紹介されているので、ざっと触ってみて良いと思ったものを並べてみます。
- 仮想環境を意識しなくてよい
- 高速
- 操作感はnpmに近く扱いやすい
uvを使うことで、Pythonアプリケーションを取り巻くパッケージ管理をシンプルにしてくれそうです。
プロジェクト
基本的なコマンドはユースケースから見ていきますが、最初にuvで頻出するプロジェクトについて軽く触れておきます。
uvにおけるプロジェクトは、npmのプロジェクトに近い構造を持ちます。
より具体的には、パッケージ情報とパッケージ本体を管理するディレクトリがプロジェクトを指します。
プロジェクトのディレクトリ構成のサンプルは以下のようになります。
1$ tree -aL 1
2.
3├── .git
4├── .gitignore
5├── .python-version
6├── .venv
7├── README.md
8├── main.py
9├── pyproject.toml
10├── src
11└── uv.lock
アプリケーションで扱うパッケージの情報は、pyproject.tomlファイルに・パッケージ本体は.venvディレクトリに記録されています。
uvを触ってみる
ここからは、実際に手を動かしながら開発でよくあるユースケースをたどることで、uvの使い心地を見ていきます。
最初の一歩
まずはパッケージを管理するプロジェクトをつくります。
uv init <プロジェクト名>
コマンドを実行することで、プロジェクトが作成されます。
プロジェクトをつくると、プロジェクト名で指定したディレクトリに以下のファイルがつくられます。
1$ tree -aL 1
2.
3├── .git
4├── .gitignore
5├── .python-version
6├── README.md
7├── main.py
8└── pyproject.toml
pyproject.tomlがパッケージ管理を担うファイルで、ここにインストールしたいパッケージ情報を追記していきます。
パッケージを追加したい
パッケージはuv add
コマンドで追加することができます。
例えばDjangoパッケージを加えると、以下のように動作します。
1$ uv add django
2# 中略...
3Creating virtual environment at: .venv
4Resolved 5 packages in 21ms
5Installed 3 packages in 63ms
6 + asgiref==3.8.1
7 + django==5.2.1
8 + sqlparse==0.5.3
1$ tree -aL 1
2.
3├── .git
4├── .gitignore
5├── .python-version
6├── .venv
7├── README.md
8├── main.py
9├── pyproject.toml
10└── uv.lock
仮想環境をつくると同時に、パッケージを追加してくれます。
パッケージ管理に関わるファイルがどのように変わったのか見てみます。
pyproject.toml
1[project]
2name = "sample"
3version = "0.1.0"
4description = "Add your description here"
5readme = "README.md"
6requires-python = ">=3.13"
7dependencies = [
8 "django>=5.2.1",
9]
重要なのは、キー dependenciesにパッケージが追加されていることです。
基本的には最新版を追加してくれます。
特定のバージョンを指定したい場合は、uv add "django==5.0.0"
のように明示的にバージョンを記述します。
uv.lock
pyproject.tomlに記述したパッケージバージョンの制約を満たす、実際にインストールされた
バージョン情報を記述したファイルです。
このファイルを共有することで、ほかの開発者・本番環境など異なる場所で同じ環境をつくれるようになります。
.venv
パッケージの本体を保管しています。
詳細は後述しますが、uvが提供しているコマンドを使うことで、仮想環境を意識することなくパッケージを扱えるようになります。
ほかの人のつくったプロジェクトから環境をつくりたい
前述の通り、環境を共有するための情報はuv.lock
に記録されています。
これをもとにuv sync
コマンドを実行することで、ほかの開発者と同じ環境が手に入ります。
IDEと連携させたい
ここでは、普段使いしているIDEのPyCharmを題材にします。
Pythonインタープリターからタイプにuvを指定すれば、あとは自動でよしなに設定してくれました。
Dockerに始まり、ほかのパッケージ管理ツールと変遷してきましたが、とてもシンプルに設定できてよきでした。
これなら快適に開発できそうです。
Pythonアプリケーションを動かしたい
仮想環境で管理されるパッケージを参照しながらPythonアプリケーションを実行したい場合、
uv run <コマンド名>
から動かすことができます。
仮想環境を明示的に起動しなくても良いので、シンプルに運用できそうです。
スクリプトを実行したい
uvではCLIコマンドを実行するためのインタフェースも用意されています。
しかし、Djangoの開発コマンドなど、ディレクトリを移動してコマンドを実行するのには向いてなさそうでした。
ですので、CLIコマンドを実行したいときは、Taskなどのタスクランナーに任せるのが良さそうです。
パッケージを更新したい
追加するときと同じようにuv add
コマンドが使えます。
バージョン制約を改めて指定することで、制約を満たす最新のパッケージに更新してくれます。
本番環境向けDockerコンテナをつくりたい
最近では、本番環境はクラウドサービスを活用し、Dockerコンテナから配信することが多いです。
そこで、uvを活用してPythonアプリケーションのDockerコンテナをつくりたいです。
pythonコマンドを実行するだけのシンプルなDockerfileから、uvで管理されたパッケージをどう連携するのか見ていきます。
1# ベースとなるビルドステージ
2FROM python:3.13-slim AS base
3ENV PYTHONDONTWRITEBYTECODE=1
4
5FROM base AS build
6# 環境変数 UV_PROJECT_ENVIRONMENTがuvを理解するのに重要(後述)
7ENV UV_PYTHON=python3.13 \
8 UV_PROJECT_ENVIRONMENT=/app
9
10RUN apt-get update
11# uvを導入
12COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
13# パッケージをインストール
14RUN --mount=type=bind,source=uv.lock,target=uv.lock \
15 --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
16 uv sync \
17 --locked \
18 --no-dev \
19 --no-editable
20
21# 実行に必要なファイルのみで構成されるビルドステージ
22FROM base AS runtime
23RUN apt-get update
24
25RUN useradd app
26
27# ソースコードとパッケージ本体をコピー
28ENV PATH=/app/bin:$PATH
29COPY --from=build --chown=app:app /app /app
30
31WORKDIR /app
32
33USER app
34
35ENTRYPOINT ["python"]
以降では、ポイントとなる部分を抜粋して見ていきます。
uv syncコマンド
最も重要なのはuv sync
コマンドです。
プロジェクトで管理されているpyproject.toml, uv.lockを配置し、本番環境向けのオプションを加えています。
具体的には、バージョンを完全に固定し、本番環境だけに必要なパッケージに絞ってインストールしています。
あとはパッケージ本体を実行環境へ配置し、アプリケーションから参照できるような仕組みを整えたいです。
環境変数 UVPROJECTENVIRONMENT
パッケージをインストールできたら、アプリケーションから見えるようにすることで動く環境が手に入りそうです。
これを実現するには、環境変数UV_PROJECT_ENVIRONMENT
が鍵を握っています。
ドキュメントいわく、役割はPythonの仮想環境の場所を決めることです。
デフォルト値は.venv
で、値を変えることで本番向けプロジェクトを構築することができます。
何が起きているかは、実際に出来上がったDockerコンテナを見てみるとわかりやすいです。
1$ which python
2/app/bin/python
3
4$ ls -l /app/bin/python
5... /app/bin/python -> /usr/local/bin/python3.13
まず、Pythonの実行ファイルがシンボリックリンクとなっています。環境変数UV_PROJECT_ENVIRONMENT
で指定した/app
ディレクトリが起点になっています。
さらに、Pythonのsys.path
周りを覗いてみます。
1>>> import sys
2>>> sys.prefix
3'/app'
4>>> sys.path
5['', '/usr/local/lib/python313.zip', '/usr/local/lib/python3.13', '/usr/local/lib/python3.13/lib-dynload', '/app/lib/python3.13/site-packages']
Pythonの実行ファイルをシンボリックリンクとすることで、Python本体が管理するprefix directory
の指す場所(sys.prefixの実行結果)が変わります。
つまり、prefix directory
以下をsys.path
に加えてくれます。
すると、パッケージを管理しているディレクトリがsys.path
に加わるので、アプリケーションからパッケージが参照できるようになります。
uvはシンプルながらスマートな解決策によって、本番向けPythonアプリケーション実行環境をつくってくれるようでした。
触ってみた感想
趣味プロジェクトにて、別のパッケージ管理ツールからuvに移行してみましたが、
npmに近い手触りでとても使いやすかったです。
uv add
・uv sync
・uv run
コマンドを覚えておけば、基本的なユースケースは対応できそうなのもうれしいです。シンプルに扱えそうで理想に近い触り心地でした。
これからPythonアプリケーションをつくるときは、uvの力を借りていきたいです。
まとめ
本記事では、uvの概要と簡単な使い方を紹介してきました。
ここで紹介しきれなかった機能以外にも便利なものがたくさんあるので、ぜひ触ってみてください。
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ

強くなりたい。