uvはどのようにPythonのバージョンやパッケージを管理しているのか?初心者から上級者まで使えるPythonの環境構築ツールのしくみ
はじめに
uvはPythonの環境構築を非常にシンプルにしてくれます。
これまで、Pythonのパッケージ管理とPython本体そのものの管理を同時に行うことができる決定打がなかったのですが、uvはその両方を同時に満たしてくれます。
しかもRustで書かれているので、非常にサクサクと動作します。
これまでpyenvやvirtualenv、pipenv、anaconda、poetry、rye[^uvと同じ作者が開発していた前身rのツールです]など様々なツールが開発されてきましたが、これらの上位互換として使うことができます。インストールも使い方も簡単ですので、これからPythonを始める方にもおすすめです。
uvそのものは別の記事で紹介しています。
この記事では、uvがどのようにPythonのバージョンやパッケージを管理しているのかを紹介します。
uv initすると作成されるファイル
uv init
を実行すると、カレントディレクトリ内に以下のようなファイルが生成されます。
(uv init my-project-dir
)とプロジェクト名を指定した場合には、my-project-dir
ディレクトリ内に生成されます。
.
├── .git/ # ⑤
├── .gitignore # ⑤
├── .python-version # ④
├── README.md # ②
├── main.py # ①
└── pyproject.toml # ③
①から番号順に説明します。
①main.py
はuvで管理するプロジェクトのメインのPythonファイルのテンプレートです。簡単なサンプルコードが入っています。
def main():
print("Hello from my-project-dir!")
if __name__ == "__main__":
main()
uv run main.py
で実行することができます。uvを使用している場合には、python main.py
の代わりのこのコマンドでpythonを実行します。このようにすることで、uvが管理しているPythonのバージョンとパッケージ環境下でmain.py
が実行されることになります。
このとき下で説明する.python-version
で指定されたPython本体がもしインストールされていない場合には、自動でそのバージョンのPythonがインストールされます。数分時間ががかかるかもしれませんが気長に待ちます。
②README.md
はプロジェクトの説明を記載するためのファイルです。初期状態では何も書かれていません。
③pyproject.toml
はuvがプロジェクトのパッケージや依存関係を管理するための設定ファイルです。以下のような内容になっています。(以降で行うnumpyをインストールした場合の例です。)
[project]
name = "uv-test"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
pyproject.toml
はPythonのパッケージ管理の標準的なファイルで、プロジェクトの設定が記述されています。簡単なプロジェクトで関係するのは、requires-python
とdependencies
の部分です。
requires-python
はプロジェクトが必要とするPythonのバージョンを指定します。ここではPython 3.12以上が必要であることを示しています。
dependencies
はプロジェクトが依存するパッケージを指定します。まだ何もパッケージをインストールしていないので、空になっています。
④.python-version
はuvが使用するPythonのバージョンを指定するためのファイルです。uvはこのファイルを参照して、プロジェクトで使用するPythonのバージョンを決定します。初期状態では以下のようになっています。
3.12
⑤.git/
と.gitignore
はgitでプロジェクトを管理するためのファイルです。gitはコードのバージョン管理システムで、プロジェクトの履歴を管理するために使用されます。すでに使っている方も多いと思いますが、初心者の方もご覧になっているかもしれないので簡単に説明します。
.git/
gitリポジトリの管理用ディレクトリです。(ドットで始まるディレクトリは環境によっては隠しディレクトリになっていて見れません。ls -a
などで確認できます。)
.gitignore
の中身は以下のようになっています。
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv
このファイルは、gitで管理しないファイルやディレクトリを指定するためのものです。例えば、Pythonのキャッシュファイルやビルド成果物、この後に説明する仮想環境のディレクトリ.venv
などをgitで管理しないように指定しています。
パッケージをインストールしてみる
ここで試しに、uvを使ってパッケージ(Numpy)をインストールしてみましょう。
uv add numpy
このコマンドを実行すると、以下のように表示され、Numpyがインストールされます。(執筆時点の最新バージョンである2.2.6がインストールされました。)
パッケージのインストールといえばpip install
を思い浮かべる方も多いと思いますが、uv add
はその上位互換だと思っていただければ結構です。インターネット上でパッケージをインストールするコマンドとしてpip install
と書かれている部分は全てuv add
に置き換えていただければ、問題ありません。
Using CPython 3.12.3
Creating virtual environment at: .venv
Resolved 2 packages in 235ms
Installed 1 package in 30ms
+ numpy==2.2.6
'uv addコマンドを実行すると、まず、
pyproject.toml`が以下のように更新されます。
[project]
name = "uv-test"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"numpy>=2.2.6",
]
dependenciesにnumpy>=2.2.6
が追加されました。これで、プロジェクトがNumpyに依存していることが明示されました。注意したいのはインストールされているバージョンではなく、このプロジェクトを実行するために必要なバージョンが記載されていることです。現時点では2.2.6をインストールしましたが、少なくとも今後、このプロジェクトを他の環境で実行する場合は2.2.6以上のバージョンであれば、動作するはずですので、numpy>=2.2.6
と記載されています。もし、2.2.6を必ず使いたければ、numpy==2.2.6
と記載することもできます。
pipをを使ってパッケージをインストールしたときには、インストールされたパッケージやバージョンはどこにも記載されません。したがって、新しい環境で同じパッケージをインストールするためには、requiements.txt
などのファイルを作成して、そこにインストールされたパッケージとバージョンを記載する必要がありました。しかし、uvではpyproject.toml
に必要なパッケージがバージョンとともに記載されるため、同じプロジェクトを他の環境で実行する際にも、同じパッケージがインストールされることが保証されます。
また、uv.lock
というファイルも作成されます。このファイルは、実際にインストールされたパッケージのバージョンを記録するためのものです。以下のような内容になっています。
name = "numpy"
version = "2.2.6"
source = { registry = "https://pypi.org/simple" }
...長いので略...
このファイルは、プロジェクトが依存するパッケージのバージョンを固定するために使用されます。これにより、プロジェクトを他の環境で実行する際に、完全に同じバージョンのパッケージがインストールされます。
なお、逆にパッケージを削除したい場合は、uv remove numpy
のようにremove
コマンドを使います。これにより、pyproject.toml
とuv.lock
から該当のパッケージが削除されます。
パッケージはどこにインストールされるのか?
uvはパッケージをプロジェクトごとに.venv
ディレクトリ内(ls -a
で見ることができる隠しディレクトリです)にインストールします。これにより、プロジェクトごとに異なるバージョンのパッケージを使用することができます。これを仮想環境といいます。実際に.venv
の中身を見てみます。
ls .venv/lib/python3.12/site-packages
と実行すると、以下のようにNumpyがインストールされていることが確認できます。
_virtualenv.pth _virtualenv.py numpy numpy-2.2.6.dist-info
コード内でimport numpy
と記述すると、この.venv/lib/python3.12/site-packages
内のNumpyがインポートされることになります。また、.venv
ディレクトリはプロジェクトごとに作成されるため、他のプロジェクトで使用しているパッケージやバージョンとは干渉しません。
.venv
ディレクトリはuv sync
によって自動的に作成・更新されるので、このフォルダごと削除してしまっても、再度uv sync
を実行すれば、必要なパッケージが再インストールされます。したがって、gitなどでプロジェクト管理している場合には、.gitignore
に.venv
を追加してパッケージはgitで管理しないようにするのが一般的です。
なお、この.venv
ディレクトリで仮想環境を管理するという方法は、venvというPython標準の仮想環境構築モジュールと互換性があります。実際に. .venv/bin/activate
と入力すると、仮想環境内に入ることができます。uvはこのvenvを拡張してよりプロジェクトを管理しやすくしているということもできます。
Python本体はどこにあるのか?
先ほど、.python-version
に使用するPython本体のバージョンが指定されていると書きましたが、uv python pin
コマンドを使用すると、使用するPython本体のバージョンを変更することができます。例えば、uv python pin 3.13
と実行すると、.python-version
が3.13に更新され、さらに指定されたバージョンがインストールされていなければ、uvが自動でそのバージョンのPythonをインストールします。
それではインストールされたPython本体はどこにあるのでしょうか?実際に確認してみましょう。
ls -l .venv/bin/
...途中略...
lrwxr-xr-x 1 hoge staff 87 Jun 1 16:21 python -> /Users/hoge/.local/share/uv/python/cpython-3.12.3-macos-aarch64-none/bin/python3.12
...途中略...
/Users/hoge/.local/share/uv/python/
以下にインストールされていることがわかります(ディレクトリは環境によって異なります)。ここには、Pythonのバージョンごとにディレクトリが作成され、その中にPython本体が格納されています。そして.venv/bin/
内には、Python本体へのシンボリックリンクが作成されます。これにより、uvは指定されたバージョンのPythonを参照することができます。
uv python dir
コマンドでもインストールされているPython本体のディレクトリを確認することができます。
もし、指定したバージョンがたまたまHomebrewなどでシステムにインストールしたPythonのものと一致する場合にはuvは新しくPythonをインストールせずに、Homebrewでインストールしたものをへのシンボリックリンクを~/.local/share/uv/python/
に作成します。これにより、uvはシステム全体でインストールされているPythonを参照することができます。
uv python list --only-installed
コマンドを実行すると、システムにインストールされていてuvが使用することができるPythonのバージョン一覧を確認することができます。
まだまだあるuvの便利機能
uv pip 〜
uv環境内でpipコマンドのようなことをすることができます。例えばuv pip freeze
と実行すると、pip freeze
のように現在のプロジェクトでインストールされているパッケージの一覧を表示することができますし、pip pip sync requirements.txt
のようにuv pip sync requirements.txt
と実行すると、requirements.txt
に記載されたパッケージをインストールすることができます。これまでパッケージ管理をrequirements.txt
に頼っていた方は、これですぐにuvに移行することができます。
uv tool
共通で使うコマンドを管理することができます。flake8やblack、最近ではruffなどのリンター(コードを解析してエラーを未然に防ぐツール)やフォーマッター(コードを読みやすく整形する)等のツールを使っている方もいらっしゃると思います。これらはどのプロジェクトでも共通して使うものですので、それぞれのプロジェクト内の.envv
インストールするのは非効率です。
uvにはそのようなツールをまとめて管理するしくみがあります。uv tool install
でパッケージをインストールすると、どの仮想環境下でもそのパッケージを使用することができます。パッケージは/Users/hoge/.local/share/uv/tools
にインストールされます。実行する際にはuv tool run 〜
のようにします。
ちなみにruffもuvを開発しているAstralが開発しているツールで、リンター兼フォーマッターです。Rustで書かれているので非常に動作が速く、インストールも簡単なのでおすすめです。
uv build / uv publish
パッケージをビルドして、PyPI (The Python Package Index) 等に公開することができます。
PyPIに公開すると、世界中からpip
コマンド(もちろんuv add
でも!)でインストールすることができます。
まとめ
本記事ではuvがどのようにPythonのバージョンやパッケージを管理しているのかを紹介しました。uvはプロジェクトごとにPythonのバージョンとパッケージを管理するための強力なツールです。それと同時に、Pythonの標準的なツールであるvenv
やpip
と互換性があり、既存のPythonプロジェクトにも簡単にもスムーズに導入することができます。
Python本体そのものの管理もシンプルになります。もはや他の管理ツールをつかう理由がなくなったといってもよいでしょう。
詳しい使い方やドキュメントは公式サイトを参照してください。
Discussion