uvとは
Rust製のPythonのパッケージマネージャーで既存のパッケージマネージャーで有名なPoetryやpipと比べてパッケージのインストールや仮想環境の作成がかなり高速なことで知られています
インストール方法
以下のコマンドを実行するだけでインストールが完了します
curl -LsSf https://astral.sh/uv/install.sh | sh
初期設定
uv initコマンドで新規プロジェクトを作成できます
uv init application
Initialized project `application` at `/Users/shun198/Desktop/uv-practice/application`
以下のようにプロジェクトフォルダ内にファイル群が自動生成されます
tree
.
├── README.md
└── application
├── README.md
├── hello.py
└── pyproject.toml
パッケージの追加
パッケージの追加はuv addコマンドで行います
uv add flask
Using CPython 3.11.3 interpreter at: /Users/shun198/.pyenv/versions/3.11.3/bin/python3.11
Creating virtual environment at: .venv
Resolved 9 packages in 217ms
Prepared 7 packages in 123ms
Installed 7 packages in 57ms
+ blinker==1.9.0
+ click==8.1.7
+ flask==3.1.0
+ itsdangerous==2.2.0
+ jinja2==3.1.4
+ markupsafe==3.0.2
+ werkzeug==3.1.3
パッケージが追加されるとプロジェクトフォルダ内に
- .venv
- .python-version
- uv.lock
が自動生成されます
tree
.
├── README.md
└── application
├── .venv
├── .python-version
├── README.md
├── hello.py
├── pyproject.toml
└── uv.lock
pyproject.tomlのdependenciesにパッケージが追加されているのを確認できます
[project]
name = "application"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"flask>=3.1.0",
]
開発環境でのみ使用したパッケージがある場合は--devのオプションを付与することでdev用のグループにパッケージを追加できます
uv add ruff --dev
Resolved 10 packages in 26ms
Installed 1 package in 19ms
+ ruff==0.9.5
[project]
name = "application"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"flask>=3.1.0",
]
[dependency-groups]
dev = [
"ruff>=0.9.5",
]
また、Poetry以下のように各パッケージのオプションを追記することもできます
下記はruffのオプションです
[tool.ruff]
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
# Same as Black.
indent-width = 4
line-length = 88
# Assume Python 3.12
target-version = "py312"
[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
ignore = ["D100", "D101", "D102", "D103", "D104", "D107", "D202", "D203", "D205", "D212", "D213", "D400", "D406", "D407", "D413", "D415"]
select = ["E4", "E7", "E9", "F", "D"]
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[tool.ruff.format]
# Like Black, use double quotes for strings.
quote-style = "double"
# Like Black, indent with spaces, rather than tabs.
indent-style = "space"
# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false
# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"
パッケージの削除
uv removeコマンドでパッケージを削除できます
uv remove ruff
Resolved 9 packages in 67ms
Uninstalled 1 package in 4ms
- ruff==0.9.5
パッケージのインストール
pyproject.toml内のパッケージを全てインストールする時
uv syncコマンドを実行します
uv sync
Resolved 10 packages in 16ms
Prepared 8 packages in 4.32s
Uninstalled 8 packages in 67ms
Installed 8 packages in 42ms
~ blinker==1.9.0
~ click==8.1.7
~ flask==3.1.0
~ itsdangerous==2.2.0
~ jinja2==3.1.4
~ markupsafe==3.0.2
~ ruff==0.9.5
~ werkzeug==3.1.3
特定のグループを除外するとき
devのグループ内のパッケージ以外をインストールする場合は--no-devのオプションを付与することで実現できます
uv sync --no-dev
依存関係を解決させずにインストールしたいとき
uv syncコマンドだと依存関係を自動で解決してしまうため、CI/CDなど依存関係にあるパッケージが競合した際にインストールを中断させることができます
--frozenオプションを付与することで実現できます
uv sync --frozen
コマンドの実行
今回はFlaskの簡易的なプロジェクトを例に説明します
tree
.
├── README.md
└── application
├── .venv
├── .python-version
├── README.md
├── main.py
├── pyproject.toml
└── uv.lock
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return {"msg":"Hello!"}
Poetryみたいにuv runの後に実行したいコマンドを記載するとuv経由で実行できます
uv run flask --app main run -h 0.0.0.0 -p 8000
* Serving Flask app 'main'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8000
* Running on http://192.168.10.105:8000
Press CTRL+C to quit
Docker環境で実行したい場合は
uvをDocker環境で実行する方法について解説します
今回はFlask用のDockerfileと実行用のentrypoint.shを例に説明します
tree
.
├── .env
├── .gitignore
├── Makefile
├── README.md
├── application
│ ├── .python-version
│ ├── .venv
│ ├── README.md
│ ├── main.py
│ ├── pyproject.toml
│ └── uv.lock
├── containers
│ ├── flask
│ │ ├── Dockerfile
│ │ └── entrypoint.sh
│ └── postgres
│ └── Dockerfile
└── docker-compose.yml
今回はastralが用意した、uvが事前にインストールされたDockerfileを使用します
uv syncコマンドでuvが管理しているパッケージをインストールできます
# https://docs.astral.sh/uv/guides/integration/docker/#available-images
FROM ghcr.io/astral-sh/uv:python3.11-alpine
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY application/pyproject.toml /code/
RUN uv sync
COPY ./containers/flask/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
uv runコマンドでFlaskを実行できます
#!/bin/sh
set -eu
uv run flask --app main run --debug -h 0.0.0.0 -p 8000
Flaskを使ったDocker環境の構築方法について詳細に知りたい方は以下の記事を参考にしてください
CI/CD環境で実行したい時
GitHubが公式で出しているsetup-pythonとastralのsetup-uvを使ってワークフローを作成するのが一般的です
下記を記述することでPythonとuvの環境を用意することができます
steps:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version
- name: Setup uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: uv.lock
まとめ
uvを使うとパッケージのインストールがかなり早くなって開発体験が向上することを感じました
今後uvを使用した際に得た新たな知見を本記事に定期的に書いていきたいと思います
参考