CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: パッケージ・プロジェクトマネージャの uv を使ってみる

今回は Rust で書かれた Python のパッケージ・プロジェクトマネージャの uv を使ってみる。

これまで Python では複数のツールを組み合わせて開発のワークフローを構築するのが一般的だった。 そのような構成では、それぞれのツールは目的に特化しているので、単独ではシンプルに扱える。 一方で、目的ごとにツールをどのように組み合わせるかユーザ自身で考えなければいけない点は敷居が高かった。 そのような状況で、uv は以下のツール群を単独で置き換えることができるとしている。

  • pip
  • pip-tools
  • pipx
  • poetry
  • pyenv
  • twine
  • virtualenv

上記のツールを見ると、要するに Python の実行環境、仮想環境、パッケージ、プロジェクトの管理をひとつのツールで代替できそうなことがうかがえる。

使った環境は次のとおり。

$ sw_vers
ProductName:        macOS
ProductVersion:     15.4.1
BuildVersion:       24E263
$ uv -V
uv 0.6.14 (Homebrew 2025-04-09)

もくじ

下準備

uv をインストールする方法はいくつかある。 インストーラのシェルスクリプトを実行したり、pip でインストールしたり。 今回は macOS なので Homebrew を使うのが一番楽だろう。

$ brew install uv

インストールすると uv コマンドが使えるようになる。

$ uv -V
uv 0.6.14 (Homebrew 2025-04-09)

初期設定

使い始める前にやっておくと良さそうな設定について。

uv generate-shell-completion コマンドを使うと、シェルごとの補完 (Completion) 用の設定が得られる。

$ uv generate-shell-completion <shell>

たとえば zsh を使っているのであれば、設定ファイル (~/.zshrc など) に次のようなコードを追加しておけば良い。 uv コマンドが使える環境で補完用の設定が入るようになる。

if which uv >/dev/null 2>&1; then
  eval "$(uv generate-shell-completion zsh)"
fi

Scripts 機能

uv はいくつかの機能を提供している。 一番シンプルな機能として、まずは Scripts という機能を紹介する。 この機能を使うと、Python のスクリプトに実行環境や依存関係に関するメタデータを付与できる。 メタデータを付与したスクリプトは uv を使ってメタデータを解決した形で実行できる。

たとえば、次のようにサードパーティー製のパッケージである requests を使うスクリプトを用意する。

$ cat << 'EOF' > fetch.py
import requests


def main():
    response = requests.get("https://example.org")
    print(f"status code: {response.status_code}")


if __name__ == "__main__":
    main()
EOF

この状態でシステムの Python を使って実行してみる。 このとき、requests がインストールされていない環境であればエラーになる。

$ python3 fetch.py 
Traceback (most recent call last):
  File "/Users/amedama/Documents/temporary/uv/fetch.py", line 1, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

スクリプトに依存パッケージのメタデータを登録する

この状態で、uv add サブコマンドを使う。 このサブコマンドは uv が管理するプロジェクトやスクリプトに依存関係のパッケージを登録するのに使う。 ここでは、先ほど用意したスクリプトの依存パッケージに requests を登録する。 実行する際にはオプションとして --script をつけて、スクリプトと依存パッケージを続ける。

$ uv add --script fetch.py requests
Updated `fetch.py`

すると、スクリプトの先頭部分にコメントでメタデータが付与される。

$ head fetch.py                    
# /// script
# requires-python = ">=3.12"
# dependencies = [
#     "requests",
# ]
# ///
import requests


def main():

登録されたメタデータを解決してスクリプトを実行する

この状態で uv run サブコマンドを使ってスクリプトを実行する。 このとき、オプションとして --script をつける。

$ uv run --script fetch.py
Installed 5 packages in 5ms
status code: 200

すると、メタデータを読み取って依存パッケージをインストールした仮想環境上でスクリプトが実行される。

内部的にどんなことをやっているかは -v オプションをつけて実行すると分かりやすい。

$ uv run -v --script fetch.py
DEBUG uv 0.6.14 (Homebrew 2025-04-09)
DEBUG Reading inline script metadata from `fetch.py`
DEBUG Acquired lock for `/Users/amedama/Documents/temporary/uv/fetch.py`
DEBUG Using Python request Python >=3.12 from `requires-python` metadata
DEBUG Checking for Python environment at `/Users/amedama/.cache/uv/environments-v2/fetch-e04e193531c37c15`
DEBUG The script environment's Python version satisfies `>=3.12`
DEBUG Released lock at `/var/folders/p2/g5ntz9vn46bbdvrl0pfkfpnm0000gn/T/uv-e04e193531c37c15.lock`
DEBUG All requirements satisfied: certifi>=2017.4.17 | charset-normalizer>=2, <4 | idna>=2.5, <4 | requests | urllib3>=1.21.1, <3
DEBUG Using Python 3.12.10 interpreter at: /Users/amedama/.cache/uv/environments-v2/fetch-e04e193531c37c15/bin/python3
DEBUG Running `python fetch.py`
DEBUG Spawned child 75859 in process group 75858
status code: 200
DEBUG Command exited with code: 0

上記から、以下の仮想環境上で実行されていることが確認できる。

$ /Users/amedama/.cache/uv/environments-v2/fetch-e04e193531c37c15/bin/python3 -V
Python 3.12.10

スクリプトに登録されている依存パッケージを確認する

スクリプトに登録されている依存関係は uv tree サブコマンドで確認できる。

$ uv tree --script fetch.py 
Resolved 5 packages in 2ms
requests v2.32.3
├── certifi v2025.1.31
├── charset-normalizer v3.4.1
├── idna v3.10
└── urllib3 v2.4.0

スクリプトに登録されている依存パッケージを削除する

なお、依存パッケージを削除したいときは uv remove サブコマンドを使う。

$ uv remove --script fetch.py requests
Updated `fetch.py`

Python versions 機能

続いては Python versions という機能について。 これは pyenv をイメージすると分かりやすい。 要するに異なるバージョンや実装の Python をインストールする機能になる。

インストール済みの Python 実行環境を確認する

まず、現在インストールされている Python は uv python list サブコマンドで確認できる。 --only-installed オプションをつけることでインストール済みのバージョンだけに絞られる。 以下を見て分かる通り、uv 以外でインストールした Python も PATH が通っていれば検出されるようだ。

$ uv python list 
cpython-3.12.10-macos-aarch64-none    /opt/homebrew/bin/python3.12 -> ../Cellar/python@3.12/3.12.10/bin/python3.12
cpython-3.9.6-macos-aarch64-none      /usr/bin/python3

--only-installed をつけずに実行すると、主要なマイナーバージョンについて最新パッチバージョンの結果が得られる。 また、--all-versions をつけると過去のすべてのバージョンを含んだ結果が得られる。

$ uv python list --all-versions | head
cpython-3.14.0a6-macos-aarch64-none                 <download available>
cpython-3.14.0a6+freethreaded-macos-aarch64-none    <download available>
cpython-3.13.3-macos-aarch64-none                   <download available>
cpython-3.13.3+freethreaded-macos-aarch64-none      <download available>
cpython-3.13.2-macos-aarch64-none                   <download available>
cpython-3.13.2+freethreaded-macos-aarch64-none      <download available>
cpython-3.13.1-macos-aarch64-none                   <download available>
cpython-3.13.1+freethreaded-macos-aarch64-none      <download available>
cpython-3.13.0-macos-aarch64-none                   <download available>
cpython-3.13.0+freethreaded-macos-aarch64-none      <download available>

Python の実行環境をインストールする

特定のバージョンをインストールしたいときは uv python install サブコマンドを使う。 ためしに Python 3.13 をインストールしてみよう。

$ uv python install 3.13
Installed Python 3.13.3 in 3.34s
 + cpython-3.13.3-macos-aarch64-none

以下のように Python 3.13 がインストールされた。

$ uv python list | grep 3.13
cpython-3.13.3-macos-aarch64-none                   /Users/amedama/.local/share/uv/python/cpython-3.13.3-macos-aarch64-none/bin/python3.13
cpython-3.13.3+freethreaded-macos-aarch64-none      <download available>

CPython だけでなく PyPy など異なる実装もインストールできる。

$ uv python list --all-platforms | grep ^pypy | head -n 5
pypy-3.11.11-windows-x86_64-none                       <download available>
pypy-3.11.11-macos-x86_64-none                         <download available>
pypy-3.11.11-macos-aarch64-none                        <download available>
pypy-3.11.11-linux-x86_64-gnu                          <download available>
pypy-3.11.11-linux-x86-gnu                             <download available>

たとえば PyPy のバージョン 3.11 を入れたいときは次のようにする。

$ uv python install pypy@3.11
Installed Python 3.11.11 in 4.61s
 + pypy-3.11.11-macos-aarch64-none

Python の実行環境がインストールされるディレクトリを確認する

インストール先のディレクトリは uv python dir サブコマンドで確認できる。

$ uv python dir
/Users/amedama/.local/share/uv/python

使用する Python のバージョンを指定する

デフォルトで使用したい Python のバージョンを指定したいときは uv python pin サブコマンドを使う。

$ uv python pin 3.13
Pinned `.python-version` to `3.13`

とはいえ、これは単に .python-version というファイルをカレントワーキングディレクトリに作成するだけ。

$ cat .python-version    
3.13

uv は、ディレクトリのファイルを読んでデフォルトの Python を選択するようだ。 つまり、特定のディレクトリで使う Python を指定していることになる。

$ uv run python -V
Python 3.13.3
$ uv python pin 3.12
Updated `.python-version` from `3.13` -> `3.12`
$ uv run python -V  
Python 3.12.10

ディレクトリ単位ではなく、ユーザが使用するデフォルトを指定したいときは --global オプションをつける。 すると、~/.config/uv 以下にファイルが作られる。

$ uv python pin 3.12 --global
Pinned `/Users/amedama/.config/uv/.python-version` to `3.12`

上記はユーザのデフォルトなので、もしディレクトリに .python-version があるときはそちらが優先される。

$ uv python pin 3.13         
Updated `.python-version` from `3.12` -> `3.13`
$ uv run python -V  
Python 3.13.3

インストール済みの Python インタプリタへのパスを取得する

uv が認識している各バージョンの Python インタプリタへのパスは uv python find サブコマンドで得られる。

$ uv python find 3.13
/Users/amedama/.local/share/uv/python/cpython-3.13.3-macos-aarch64-none/bin/python3.13
$ uv python find 3.12
/opt/homebrew/opt/python@3.12/bin/python3.12

Python の実行環境をアンインストールする

Python の実行環境をアンインストールしたいときは uv python uninstall サブコマンドを使う。

$ uv python uninstall 3.13
Searching for Python versions matching: Python 3.13
Uninstalled Python 3.13.3 in 74ms
 - cpython-3.13.3-macos-aarch64-none
$ rm .python-version

Projects 機能

続いては Projects 機能について。 uv のユースケースとしては、この機能を使う場面が一番多そう。 この機能は poetry をイメージすると分かりやすい。 プロジェクトは、Python を使って開発する何らかのアプリケーションやパッケージになる。

プロジェクトを作成する

まずは uv init サブコマンドでプロジェクトを作成する。 以下では helloworld という名前でプロジェクトを作っている。 --vcs none をつけているのは、デフォルトではプロジェクトに空の Git リポジトリを作成するため。 今回はバージョン管理の部分が不要なので明示している。

$ uv init helloworld --vcs none
Initialized project `helloworld` at `/Users/amedama/Documents/temporary/uv/helloworld`

なお、上記ではコマンドの後ろにプロジェクト名を指定している。 この場合はプロジェクト名でサブディレクトリが作られる。 これ以外に、自分でディレクトリを作った上で、そこで uv init するやり方もある。

$ mkdir helloworld
$ cd helloworld
$ uv init  --vcs none

uv init を実行すると、次のようにプロジェクトに必要な最低限のファイルが用意される。

$ cd helloworld
$ ls -1a
.
..
.python-version
main.py
pyproject.toml
README.md

デフォルトで用意された Python のモジュール main.py は uv run コマンドで実行できる。

$ uv run main.py    
Using CPython 3.12.10 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtual environment at: .venv
Hello from helloworld!

実行するとプロジェクト用の仮想環境がディレクトリの配下に作られる。

$ ls -1a .venv
.
..
.gitignore
bin
CACHEDIR.TAG
lib
pyvenv.cfg

また、依存パッケージなどのバージョンやハッシュの情報を記載する uv.lock というファイルも用意される。

$ cat uv.lock        
version = 1
revision = 1
requires-python = ">=3.12"

[[package]]
name = "helloworld"
version = "0.1.0"
source = { virtual = "." }

.python-version は先述したとおり uv が読み取って実行する際のバージョンに使われる。

$ cat .python-version 
3.12

pyproject.toml は言わずとしれた Python でパッケージやプロジェクトを管理するメタデータを記載するファイルになっている。

$ cat pyproject.toml 
[project]
name = "helloworld"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

プロジェクトに依存パッケージを追加する

プロジェクトに依存パッケージを追加するときは uv add サブコマンドを使う。 この点は Scripts 機能を試したときと同じで、違いは --script <module> オプションの指定がないだけ。

$ uv add requests                  
Resolved 6 packages in 86ms
Prepared 5 packages in 162ms
Installed 5 packages in 5ms
 + certifi==2025.1.31
 + charset-normalizer==3.4.1
 + idna==3.10
 + requests==2.32.3
 + urllib3==2.4.0

パッケージの使用時ではなく開発のタイミングで必要になるものを追加するときは --dev をつける。

$ uv add --dev pytest    
Resolved 11 packages in 169ms
Prepared 4 packages in 117ms
Installed 4 packages in 5ms
 + iniconfig==2.1.0
 + packaging==24.2
 + pluggy==1.5.0
 + pytest==8.3.5

なお、--dev--group dev のエイリアスに過ぎない。 別の名称を使いたいときは --group オプションを使えば良い。 たとえば以下では testing というグループ名を使っている。

$ uv add --group testing pytest
Resolved 11 packages in 3ms
Audited 9 packages in 0.01ms

プロジェクトの依存パッケージを削除する

依存パッケージを削除したいときは uv remove を使う。 この点も Scripts 機能を試したときと変わらない。

$ uv remove --group testing pytest
Resolved 11 packages in 2ms
Audited 9 packages in 0.01ms

コマンドを実行すると pyproject.toml や uv.lock が更新される。 必要に応じて手動で編集すると良い。

$ cat pyproject.toml 
[project]
name = "helloworld"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "requests>=2.32.3",
]

[dependency-groups]
dev = [
    "pytest>=8.3.5",
]
testing = []

プロジェクトの環境を同期する

プロジェクトのリポジトリをチェックアウトした直後など、環境が整っていないときは uv sync サブコマンドを実行する。 試しに仮想環境を削除した上で実行してみよう。 すると、改めて仮想環境が作成されてパッケージがインストールされる。

$ rm -rf .venv 
$ uv sync                         
Using CPython 3.12.10 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtual environment at: .venv
Resolved 11 packages in 0.51ms
Installed 9 packages in 6ms
 + certifi==2025.1.31
 + charset-normalizer==3.4.1
 + idna==3.10
 + iniconfig==2.1.0
 + packaging==24.2
 + pluggy==1.5.0
 + pytest==8.3.5
 + requests==2.32.3
 + urllib3==2.4.0

プロジェクトの依存パッケージを確認する

プロジェクトが依存しているパッケージは uv tree サブコマンドで確認できる。 この点も Scripts 機能と変わらない。

$ uv tree                   
Resolved 11 packages in 0.56ms
helloworld v0.1.0
├── requests v2.32.3
│   ├── certifi v2025.1.31
│   ├── charset-normalizer v3.4.1
│   ├── idna v3.10
│   └── urllib3 v2.4.0
└── pytest v8.3.5 (group: dev)
    ├── iniconfig v2.1.0
    ├── packaging v24.2
    └── pluggy v1.5.0

コマンドの入るパッケージの扱いについて

なお、パッケージによっては仮想環境の bin ディレクトリにコマンドがインストールされることがある。 たとえば Ruff であれば ruff コマンドが入る。

$ uv add --dev ruff
Resolved 12 packages in 455ms
Prepared 1 package in 1.66s
Installed 1 package in 8ms
 + ruff==0.11.5

インストールされたコマンドを呼びたいときは uv run 経由で実行できる。

$ uv run -- ruff -V               
ruff 0.11.5

あるいは、単純に仮想環境をアクティベートすることで PATH を通してしまっても良い。

$ source .venv/bin/activate
(helloworld) $ ruff -V         
ruff 0.11.5

仮想環境から抜けるときは deactivate する。

(helloworld) $ deactivate

パッケージの配布物をビルドして公開する

プロジェクトの pyproject.toml を元にパッケージの配布物をビルドして公開できる。 配布物を公開する部分は twine をイメージすると分かりやすい。

まずは uv build サブコマンドを使って配布物をビルドする。

$ uv build

これで、ソース配布物 (sdist) や Wheel ファイルができる。

$ ls -1 dist
helloworld-0.1.0-py3-none-any.whl
helloworld-0.1.0.tar.gz

そして、uv publish すると PyPI に公開できる。 デフォルトではインタラクティブにアカウントの情報を入力する。

$ uv publish

とはいえ、ここらへんは手作業でやるよりも CI/CD の仕組みを作り込むのが一般的だろう。

Tools 機能

先ほどの Projects 機能では、プロジェクトに紐づいた依存パッケージの管理について学んだ。 とはいえ、プロジェクトに紐づかない普段遣いのツールをグローバルに入れたい場合もあるはず。 そのようなときは Tools 機能を用いる。

ツールをインストールする

たとえば black が使いたいなーと思ったときは uv tool install サブコマンドを使う。 すると、Tools 機能用の仮想環境にパッケージがインストールされる。

$ uv tool install black
Resolved 6 packages in 174ms
Prepared 5 packages in 282ms
Installed 6 packages in 6ms
 + black==25.1.0
 + click==8.1.8
 + mypy-extensions==1.0.0
 + packaging==24.2
 + pathspec==0.12.1
 + platformdirs==4.3.7
Installed 2 executables: black, blackd
warning: `/Users/amedama/.local/bin` is not on your PATH. To use installed tools, run `export PATH="/Users/amedama/.local/bin:$PATH"` or `uv tool update-shell`.

コマンドは $HOME/local/bin にデフォルトでインストールされる。 もし、ここに PATH が通っていない場合には上記のように警告が出る。

警告にあるとおり、手動でシェルの設定を投入するか、あるいは uv tool update-shell サブコマンドを使う。

$ uv tool update-shell
Created configuration file: /Users/amedama/.zshenv
Restart your shell to apply changes

uv tool update-shell サブコマンドを使うとシェルにあわせて設定ファイルを作ってくれる。 普段使いする環境なら、手動で設定を投入する方が挙動をコントロールできて良いかな。

$ cat ~/.zshenv 
# uv
export PATH="/Users/amedama/.local/bin:$PATH"

ツールを実行する

インストールしたツールは uv tool run サブコマンドで実行できる。

$ uv tool run black main.py 
All done! ✨ 🍰 ✨
1 file left unchanged.

あるいは uvx というエイリアスもあるようだ。

$ uvx black main.py    
All done! ✨ 🍰 ✨
1 file left unchanged.

もちろんコマンドに PATH が通っていれば、シェルでそのまま実行しても構わない。

$ which black 
/Users/amedama/.local/bin/black
$ black --version
black, 25.1.0 (compiled: yes)
Python (CPython) 3.12.10

インストール済みのツールを確認する

インストール済みのパッケージは uv tool list サブコマンドで確認できる。

$ uv tool list        
black v25.1.0
- black
- blackd

実行時の Python のバージョンを指定したいときは --python オプションを使うと良い。

$ uv tool run --python 3.11 black main.py

インストール済みのツールを更新する

インストール済みのパッケージのバージョンを上げるときは uv tool upgrade を使う。 --all オプションをつけるとすべてのパッケージを更新できる。

$ uv tool upgrade --all

ツールをアンインストールする

パッケージをアンインストールするときは uv tool uninstall サブコマンドを使う。

$ uv tool uninstall black
Uninstalled 2 executables: black, blackd

pip Interface 機能

uv には pip Interface という機能がある。 この機能を使うことで、既存の pip や venv / virtualenv を使った開発の中でも uv の恩恵を得ることができる。

仮想環境を作成する

まず、uv venv サブコマンドを使うと仮想環境を作成できる。 デフォルトではカレントワーキングディレクトリに .venv という名前で仮想環境ができる。

$ cd ../
$ uv venv                         
Using CPython 3.12.10 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate

もし名前を指定して作成したいときはサブコマンドに続けて仮想環境の名前を指定する。

$ uv venv myvenv
Using CPython 3.12.10 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtual environment at: myvenv
Activate with: source myvenv/bin/activate

作成した仮想環境は、一般的な venv / virtualenv を使った仮想環境と同様に source でアクティベートする。

$ source .venv/bin/activate

uv の pip Interface は、仮想環境を次の優先順位で探索する。

  • VIRTUAL_ENV 環境変数
    • uv / venv / virtualenv で作成した環境をアクティベートすると自動で設定される
  • CONDA_PREFIX 環境変数
    • Conda で作成した環境をアクティベートすると自動で設定される
  • カレントワーキングディレクトリの .venv ディレクトリ

今回は明示的にアクティベートしたので一番上のルールに該当する。

$ echo $VIRTUAL_ENV
/Users/amedama/Documents/temporary/uv/.venv

uv の pip Interface は、pip の操作方法の一部を移植している。 内部的に pip を利用しているわけではないらしい。

パッケージをインストールする

たとえば uv pip install を使って環境にパッケージをインストールできる。

$ uv pip install pylint
Resolved 7 packages in 209ms
Prepared 6 packages in 196ms
Installed 7 packages in 6ms
 + astroid==3.3.9
 + dill==0.4.0
 + isort==6.0.1
 + mccabe==0.7.0
 + platformdirs==4.3.7
 + pylint==3.3.6
 + tomlkit==0.13.2

インストール済みのパッケージを確認する

uv pip list サブコマンドでインストール済みのパッケージ一覧を確認できる。

$ uv pip list          
Package      Version
------------ -------
astroid      3.3.9
dill         0.4.0
isort        6.0.1
mccabe       0.7.0
platformdirs 4.3.7
pylint       3.3.6
tomlkit      0.13.2

パッケージの依存関係を確認する

それぞれのパッケージの依存関係は uv pip tree の方が見やすい。

$ uv pip tree       
pylint v3.3.6
├── astroid v3.3.9
├── dill v0.4.0
├── dill v0.4.0
├── isort v6.0.1
├── mccabe v0.7.0
├── platformdirs v4.3.7
└── tomlkit v0.13.2

パッケージのバージョンに矛盾がないか確認する

インストールしたパッケージが要求するバージョンに矛盾がないか uv pip check で確認できる。

$ uv pip check
Checked 7 packages in 0.39ms
All installed packages are compatible

インストール済みのパッケージのバージョンを確認する

インストールしたパッケージのバージョンは uv pip freeze で確認する。

$ uv pip freeze
astroid==3.3.9
dill==0.4.0
isort==6.0.1
mccabe==0.7.0
platformdirs==4.3.7
pylint==3.3.6
tomlkit==0.13.2

インストールしたパッケージの詳細を確認する

uv pip show サブコマンドでインストールしたパッケージの詳細を確認できる。

$ uv pip show pylint
Name: pylint
Version: 3.3.6
Location: /Users/amedama/Documents/temporary/uv/.venv/lib/python3.12/site-packages
Requires: astroid, dill, isort, mccabe, platformdirs, tomlkit
Required-by:

パッケージをアンインストールする

パッケージをアンインストールしたいときは uv pip uninstall を使う。

$ uv pip uninstall pylint
Uninstalled 1 package in 11ms
 - pylint==3.3.6

pyproject.toml でインストールされるパッケージの詳細を確認する

uv pip compile を使うと pyproject.toml から入るパッケージとバージョンを確認できる。 これは pip にはない機能かな。 似たようなことをするならまっさらな環境に pip install . した上で pip freeze するのかな。

$ cd helloworld
$ uv pip compile pyproject.toml 
Resolved 5 packages in 65ms
# This file was autogenerated by uv via the following command:
#    uv pip compile pyproject.toml
certifi==2025.1.31
    # via requests
charset-normalizer==3.4.1
    # via requests
idna==3.10
    # via requests
requests==2.32.3
    # via helloworld (pyproject.toml)
urllib3==2.4.0
    # via requests

pyproject.toml からパッケージをインストールする

uv pip sync を使うことで、pyproject.toml などから仮想環境にパッケージをインストールできる。 こちらも本来の pip にはない機能で、似たようなことがしたいときは pip install -U . とかするかな。

$ uv pip sync pyproject.toml 
Using Python 3.12.10 environment at: /Users/amedama/Documents/temporary/uv/.venv
Resolved 1 package in 1ms
Uninstalled 6 packages in 14ms
Installed 1 package in 2ms
 - astroid==3.3.9
 - dill==0.4.0
 - isort==6.0.1
 - mccabe==0.7.0
 - platformdirs==4.3.7
 + requests==2.32.3
 - tomlkit==0.13.2

その他

uv のキャッシュしているデータを削除したいときは uv cache cleanuv cache prune が使える。

$ uv cache clean            
Clearing cache at: /Users/amedama/.cache/uv
Removed 1527 files (56.1MiB)

キャッシュのあるディレクトリ自体は uv cache dir サブコマンドで得られる。

$ uv cache dir  
/Users/amedama/.cache/uv

uv をインストール用のスクリプトを使って入れた場合には uv self update サブコマンドで uv 自体を更新できる。 今回のように Homebrew などのパッケージマネージャ経由で入れたときはエラーになっておわり。

$ uv self update
error: uv was installed through an external package manager, and self-update is not available. Please use your package manager to update uv.

まとめ

今回は Python のパッケージおよびプロジェクトマネージャの uv を使ってみた。 様々なツールを uv だけで代替できるところは便利に感じられる。 一方で、動作する際に内部的な振る舞いが予想しにくく感じられる場面もあった。 今後は Projects 機能を中心に、適材適所で使っていきたい。