寝て起きたら忘れているuvを記録する。(Geminiを利用して執筆してます)
はじめに
Pythonには Anaconda や pip を始めとしたさまざまなパッケージ管理ツールが存在します。そのなかでも、最近デファクトスタンダードになりつつあるのが uv です。
本記事では uv の基本的なコマンドをまとめたのち、実際の使用例を紹介します。
実際の使用例は、自分が研究でuvを用いるときの手順です。我流な点もあるかもしれないのでご了承ください。「これが正攻法だよ」といったコメントも大歓迎です!
そもそもuvってな~に?
uv は、2024年にAstral社からリリースされた、Rust製のPythonパッケージ・プロジェクト管理ツールです。近年では Hugging Face のモデルカードや Gemini のデモ等々、パッケージ管理のツールとして先ずは uv が使われている印象です。
最大の強みは圧倒的な実行速度です。公式ドキュメントによると、従来の pip や pip-tools と比較して10〜100倍速いのだそう。
また、uv はパッケージ間の依存関係を高速に解消し、競合しないようにパッケージの追加を進めてくれます(厳密すぎて逆に不便になときもあったり)
さらに、普通はプロジェクト実行の前に手動で環境の activate をする必要がありますが、uv は ファイル実行時に実行位置から環境を自動で判断し、自動で activate して実行してくれる特徴があります。
activateとは?
パッケージ管理をする際、インストールしたパッケージは特定のディレクトリ(仮想環境)に保存されます。複数の環境がある中で、いま使う環境をPCへ指定する操作が activate です。
逆に、指定を解除するのにはdeactivateを使用します。
uvの使いかた
コマンド早見表
- 仮想環境の管理
| コマンド | 役割 |
|---|---|
uv init |
プロジェクトの新規作成 |
uv venv |
仮想環境(.venv)の新規作成 |
uv run |
パッケージを考慮した上でのPythonファイルの実行 |
uv add |
パッケージの追加(pyproject.tomlに記録される) |
uv remove |
パッケージの削除 |
uv sync |
記録された依存関係(uv.lock)をもとに環境を同期 |
uv lock |
依存関係を計算し、uv.lockファイルを更新 |
uv python系(Python自体のバージョン管理のためのコマンド)
| コマンド | 役割 |
|---|---|
uv python install |
指定したバージョンのPythonをダウンロード・インストール(例: uv python install 3.12) |
uv python pin |
現在のプロジェクトで使用するPythonバージョンを固定(.python-version が更新される) |
uv python list |
インストール済み・利用可能なPythonのバージョン一覧を表示 |
uv pip系(従来のpipと互換性のあるコマンド)
| コマンド | 役割 |
|---|---|
uv pip install |
仮想環境に直接パッケージをインストール |
uv pip list |
インストール済みのパッケージ一覧を表示 |
uv pip show |
特定のパッケージの詳細を表示 |
主要コマンドの解説
uv init
uvのプロジェクトを新規で作成するコマンドです。
uv-0.12.12では 「アプリケーション」 と 「ライブラリ」 の2つの基本テンプレートをサポートしており、デフォルトはアプリケーションです。
このコマンドによって、以下のような構成が作成されます。
$ uv init <project-name> #`<project-name>`には任意のプロジェクト名を指定します。
# project-nameのようにハイフン(-)を含む場合、
# 自動でアンダースコア(_)に正規化されるらしい
$ tree project_name
project_name/
├── .python-version # 使用するPythonのバージョンが記載される
├── README.md # プロジェクトの説明
├── pyproject.toml # パッケージやプロジェクトの設定ファイル
└── src
└── project_name
└── __init__.py #__init__.pyについてはツリーの記事を参照してください
__init__.pyそのものにも役割はありますが、今回は割愛します。詳しくはこちら1
このとき、pyproject.tomlには以下は以下のような構成になります。
[project]
name = "project_name"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[project.scripts]
example-app = "project_name:main"
[build-system]
requires = ["uv_build>=0.12.12,<0.13"]
build-backend = "uv_build"
上記はアプリケーションの場合です。
ライブラリモード(--lib)では、型情報のサポートを示すマーカーファイルである py.typed2が生成されます。これにより、パッケージ配布時に利用側の型チェッカー(mypyなど)が型定義を正しく認識できるようになります。ライブラリモードについては割愛。(よく知らない)
ふらっと登場したpyproject.tomlはパッケージの依存関係を記録するファイルで、uvは後述するuv addやuv remove時に本ファイルを参照したり、自動で編集したりします。ケースによりけり、自分でpyproject.tomlに書き込むこともあります。
uv initをした時点では仮想環境は作成されません。
uv venv
現在のディレクトリに仮想環境(デフォルトでは .venv フォルダ)を作成します。ただし、uvは uv run や uv add を実行した際に、仮想環境がなければ自動で作成してくれるため、明示的にコマンドを叩く必要はないです。
uv add
プロジェクトにパッケージを追加します。後述する pyproject.toml に依存関係として自動で書き込まれ、同時にインストールも行われます。
特定のバージョンを指定して追加したい場合は、以下のように記述します。
uv add "numpy==1.26.4"uv add "pandas>=2.0.0"
また、(個人的に)よく使う印象のオプションとして
--index--no-build-isolation
について紹介します。
-
--index
PyPI 以外のパッケージ配布元からaddしたいとき、インデックス URLを指定するためのオプションです。
【例: GPU版 PyTorch のインストール】
PyTorch の CUDA 版は通常の PyPI ではなく専用サーバーで wheel が配布されているため、URL を明示する必要があります。
#cuda12.4バージョンのtorchをインストールしたい場合
uv add torch torchvision torchaudio --index https://download.pytorch.org/whl/cu124
-
--no-build-isolation
パッケージのビルド時にクリーンな一時環境を作らず、現在の仮想環境にインストールされているライブラリを使ってビルドします。
【例: flash-attn のインストール】
C++/CUDA 拡張のコンパイルを伴う flash-attn は、ビルド時に環境内の torch や CUDA ツールチェーンを直接参照する必要があります。通常の隔離ビルドだと一時環境側に torch が存在せずエラーになるため、このフラグで既存環境を参照させます。
uv add flash-attn --no-build-isolation
導入にひと癖あるパッケージは、こうしたオプションを渡しながらインストールします。
uv run
構築した仮想環境を用いて、Pythonスクリプトを実行します。先述の通りuvが自動で実行環境を探すため、手動での activate は不要です。
通常のpythonコマンドと同様に、スクリプトに引数を渡したい場合は
uv run script.py arg1 arg2
のようにそのまま後ろに続けて記述するだけでOKです。
uvの使用例
本章では、uvまわりのユースケースをいくつかご紹介します。記事冒頭でお伝えの通り、我流な部分もあるかと思いますのでご了承ください。追記するかもしないかも。
1. プロジェクトを新規でつくる場合
# 1. プロジェクトの作成
$ uv init my_project
$ cd my_project
$ uv python pin 3.10 #pythonのバージョンを固定する
# 2. 必要なパッケージの追加(仮想環境が作られていない場合、始めに仮想環境が作られます)
$ uv add numpy pandas sl
# 3. なにかしら作成したプロジェクトの実行
$ uv run src/hello.py
#間違えてパッケージを追加しちゃって、消したいとき
$ uv remove sl
sl?
$ sl
( ) (@@) ( ) (@) () @@ O @ O @ O
(@@@)
( )
(@@@@)
( )
==== ________ ___________
_D _| |_______/ \__I_I_____===__|_________|
|(_)--- | H\________/ | | =|___ ___| _________________
/ | | H | | | | ||_| |_|| _| \_____A
| | | H |__--------------------| [___] | =| |
| ________|___H__/__|_____/[][]~\_______| | -| |
|/ | |-----------I_____I [][] [] D |=======|____|________________________|_
__/ =| o |=-O=====O=====O=====O \ ____Y___________|__|__________________________|_
|/-=|___|= || || || |_____/~\___/ |_D__D__D_| |_D__D__D_|
\_/ \__/ \__/ \__/ \__/ \_/ \_/ \_/ \_/ \_/
2. uvで環境構築されたGitリポジトリをクローンする場合
# 1. gitからリポジトリをクローン(リポジトリにuv関係のファイルが入っている想定です)
$ git clone https://github.com/example/example_rp.git
$ cd example_rp
# 2. パッケージの一括追加と環境構築
# (リポジトリ内にある pyproject.toml や uv.lock を読み込んで環境を同期)
$ uv sync
# 3. 実行
$ uv run script.py
おわりに
本記事では、デファクトスタンダードになりつつある uv の使い方や、実践的な具体例を紹介しました。
高速で快適なパッケージ管理は、開発や研究のストレスを大きく減らしてくれます。どなたかの参考になれば幸いですし、誤りや「もっといい使い方があるよ!」という点があれば、ぜひコメントでご指摘いただけるとありがたいです。
よき研究ライフを!