Python Monthly Topics

Rust製のPythonパッケージ管理ツール「uv」使ってみよう

門脇@satoru_kadowakiです。3月の「Python Monthly Topics」は、Rust製のパッケージ管理ツールuvについて紹介します。

はじめに

どのようなプログラミング言語においても、仮想環境の構築やパッケージ管理は重要です。本記事でいう「仮想環境」とは、仮想マシン(VM)やDockerのような仮想化技術ではなく、プロジェクトごとにパッケージのインストール先を分離することで管理を容易にするための仕組みを指します。

Pythonの場合、使用するサードパーティライブラリがそれほど多くないケースではpipやvenvだけで十分ですが、プロジェクトが大きくなるとパッケージ同士の依存関係が複雑になったり、インストールに時間がかかったりします。このような問題を解決するため、Pythonにはさまざまなパッケージ管理ツールがあります。

まずはPythonでよく使用されるパッケージ管理ツールと、uvの特徴について簡単に説明します。

パッケージ管理ツール

Pythonでよく使用されるパッケージ管理、仮想環境管理ツールには以下があります。

ツール名 役割
pyenv Pythonのバージョン管理
venv 仮想環境の管理
pip パッケージの管理
pipenv パッケージ・仮想環境の管理
Conda パッケージ・仮想環境の管理
Poetry パッケージ・仮想環境の管理
Rye Pythonバージョン・パッケージ・仮想環境の管理

それぞれのツールに関する詳しい説明は本記事では行いません。詳しく知りたい方は、ツール名のリンクから公式ドキュメント等を参照してみてください。

上記の表に挙げたツール群にはそれぞれに特徴があります。pyenv、venv、pipのように単一機能に特化したものから、Condaのようにデータサイエンスや機械学習プロジェクトで使用される複雑なパッケージの依存関係や環境管理をサポートするツール、PoetryのようにPythonパッケージインデックスPyPIへの公開をサポートするツールなど、開発シーンに合わせて選択することができます。

uvとは

uvは2024年の2月中旬に発表されたばかりの新しいパッケージ管理ツールです。Rustで書かれており、ここ最近で飛躍的に使用されるようになったRust製のPythonリンター&フォーマッターRuffを開発しているAstral社によって提供されています[1]

RustのパッケージマネージャであるCargoをPythonにもたらすという意味で、⁠Cargo for Python」になることを追求しており、高速で信頼性が高いパッケージ管理ツールになることを掲げています。

uvのインストールと使い方

実際にuvをインストールして使ってみましょう。uvの開発はかなり活発に行われています。執筆時点でも1週間もしないうちにマイナーバージョンが5つも上がってしまうほどでしたので、この記事が公開される頃にはさらにバージョンが上がっていることが予想されます。

執筆時点での最終バージョンは「0.1.21」です。

インストール方法

uvはPythonと依存関係がないため、Python自体とは別にインストールできます。したがって、システムに複数のPythonバージョンが存在していても、それぞれにインストールする必要はありません。

もちろん、pipコマンドで手っ取り早くインストールすることもできます。ひとまず試してみたい方には以下がおすすめです。

$ pip install uv
Collecting uv
     |████████████████████████████████| 20.3 MB 422 kB/s
Installing collected packages: uv
Successfully installed uv-0.1.21

pipを使用せず、LinuxやmacOSのシステム全体で使用したい場合は以下のように行います。

$ curl -LsSf https://astral.sh/uv/install.sh | sh
installing to /Users/kadowaki/.cargo/bin
  uv
everything's installed!

To add $HOME/.cargo/bin to your PATH, either restart your shell or run:

    source $HOME/.cargo/env

システム全体にインストールした場合は、パスを通す必要があります。出力メッセージに従いsource $HOME/.cargo/envを実行して、環境変数(PATH)にuvのパスを追加します。

なお、Windowsなどその他のインストール方法について知りたい方は、以下のREADMEに記載がありますので、参照してみてください。

仮想環境の作成

次に仮想環境を作成します。ここでは、速度の違いを確認するためにtimeコマンドを使用して実行時間を計測してみます。

最初にPython標準のvenvで仮想環境を作成します。今回はPythonは3.12を使用し、仮想環境を作成するディレクトリは「std-env」としました。

$ time python3.12 -m venv std-env
python3.12 -m venv std-env  3.56s user 0.63s system 83% cpu 5.068 total

仮想環境の作成に約5秒かかっています。

続いてuvで仮想環境を作成します。uvで仮想環境を作成する場合は、以下のように、uvコマンドにvenv引数を指定して実行します。デフォルトではuvコマンドを実行したディレクトリ内に「.venv」ディレクトリが自動的に作成されます。

$ time uv venv
Using Python 3.12.2 interpreter at: /usr/local/bin/python3.12
Creating virtualenv at: .venv
Activate with: source .venv/bin/activate
uv venv 0.01s user 0.01s system 88% cpu 0.023 total

なんと、uv venvの実行は0.1秒以下で完了しました! 驚きの速さです!

デフォルトの.venvディレクトリではなく、ディレクトリ名を指定したい場合はuv venv {ディレクトリ名}のように実行します。また、--python {Pythonのインストールパス}のように、オプションで仮想環境のPythonのバージョンを指定できます。

以下の例では、Python 3.11を使用して「uvenv-test」ディレクトリに仮想環境を作成しています。

$ uv venv uvenv-test --python /usr/local/bin/python3.11
Using Python 3.11.2 interpreter at: /usr/local/opt/[email protected]/bin/python3.11
Creating virtualenv at: uvenv-test
Activate with: source uvenv-test/bin/activate

仮想環境のアクティベート

LinuxやmacOS環境で仮想環境をアクティベートする方法はPython標準のvenvと同じです。仮想環境ディレクトリにあるbin/activatesourceコマンドで実行します。アクティベートされると、Python標準のvenvと同じくプロンプトに仮想環境のフォルダ名が表示されます。仮想環境ディレクトリを指定せず、デフォルトの.venvディレクトリで作成した場合は、上位のフォルダ名が表示されます。

$ source .venv/bin/activate
(work_dir) $   # プロンプトに上位のフォルダ名が表示されている

パッケージインストールの前に、アクティベートされた環境について少し確認してみます。Pythonの実行パスやバージョンが以下のように設定されています。

  • 作成した仮想環境ディレクトリ(例: .venv)にあるPythonが使用されている
  • 仮想環境を作成する際に使用したPythonと同じバージョンで作成されている
# 作成した仮想環境ディレクトリ(.venv)にあるPythonが使用されていることを確認
(work_dir) $ which python
/Users/kadowaki/work_dir/.venv/bin/python

# pythonコマンドを使用してバージョンを確認
(work_dir) $ python --version
Python 3.12.2

続いて、標準でインストールされるパッケージを確認します。uvコマンドにpip listを引数として実行します(間違えてuvコマンドをつけずpip listだけを実行すると、システム全体にインストールされているパッケージのリストが表示されますので注意してください⁠⁠。

(work_dir) $ uv pip list
(work_dir) $

uv pip listコマンドの結果は何も出力されずに終了するはずです。Python標準のvenvでは以下のようにデフォルトでpipがインストールされますが、uvが作成する仮想環境にはpipやsetuptoolsはインストールされません。つまり、uvが提供するpipによってパッケージ管理が行われます。この点も標準とは少し異なりますが、仮想環境ごとにpip自体のバージョンを上げる手間を省くことができるのはありがたい仕様です。

# Python標準のvenvで標準インストールされているパッケージ
$ pip list
Package Version
------- -------
pip     24.0

パッケージのインストール

それでは、パッケージのインストールを行ってみましょう。今回はpandasを試しにインストールしてみます。今回も仮想環境の作成と同様にtimeコマンドを使用して時間を計測してみます。また、--no-cacheオプションを使用してキャッシュがパフォーマンスに影響しないようにして比較します。

まずは先ほど作成した、Python標準のvenvで作った仮想環境上(std-env)にインストールします。

(std-env) $ time pip install pandas --no-cache
Collecting pandas
  Downloading pandas-2.2.1-cp312-cp312-macosx_10_9_x86_64.whl.metadata (19 kB)
(省略)
Installing collected packages: pytz, tzdata, six, numpy, python-dateutil, pandas
Successfully installed numpy-1.26.4 pandas-2.2.1 python-dateutil-2.9.0.post0 pytz-2024.1 six-1.16.0 tzdata-2024.1
pip install pandas --no-cache  10.94s user 2.90s system 75% cpu 18.267 total

インストールに約18秒かかりました。続いて、uvの仮想環境にインストールしてみます。uv pip install {パッケージ名}のように、uvコマンドに続けてpip installを実行します。

(work_dir) $ time uv pip install pandas --no-cache
Resolved 6 packages in 579ms
Downloaded 6 packages in 1.87s
Installed 6 packages in 80ms
 + numpy==1.26.4
 + pandas==2.2.1
 + python-dateutil==2.9.0.post0
 + pytz==2024.1
 + six==1.16.0
 + tzdata==2024.1
uv pip install pandas --no-cache  0.94s user 1.62s system 82% cpu 3.090 total

なんとpandasのインストールが約3秒で終了しました。あまりにも爆速すぎて唖然とするほどですが、この速度で信頼できる仮想環境を構築できるということだけで、新たなパッケージ管理ツールの選択肢の1つになり得ると思ってしまいます。

pipとuv pipの違い

Python標準のpipとuv pipの比較を簡単にまとめると以下のようになります。

  1. uv pipはPython標準のpipと比較して数倍から数十倍速い
  2. pipが持つ機能のすべてを網羅しているわけではないが、必要な機能は備わっている
  3. パッケージ間の依存関係解決についてはPython標準のpipと動作が異なる場合がある

それぞれについて簡単に説明します。

「1.」uv pipの速度については、Rustの恩恵によりベンチマークでは10〜100倍速いと謳っています。筆者が試した環境でも、nightlyのTensorFlowのように比較的重めのパッケージインストールを試してみても、2倍以上uvが速い結果になりました。

「2.」については、基本的にpipを置き換えると言って過言ではありません。以下のuv pipコマンドがPython標準のpipと同様に使用できます。

  • uv pip install
    • uv pip install -r requirements.txt
  • uv pip uninstall
  • uv pip list
  • uv pip freeze

また、uvでは以下のような、pyproject.tomlを使用したパッケージのインストールがサポートされていたり、pip-toolsの機能にある、仮想環境にインストールされているパッケージバージョンの情報をrequirements.txtに同期したりする機能など、便利な機能もあります。

  • uv pip install -r pyporject.toml
  • uv pip sync requirements.txt

「3.」については、Python標準のpipと大きく異なる注意点とも言えます。uvではパッケージ間の依存関係の解決方法が異なり、pipでインストールされるパッケージとバージョンが異なる場合がありました。互換性に関するドキュメントにも記載がありますが、uvは依存関係のあるパッケージはステーブルリリースのバージョンが選択されます。

ただし、以下の条件を満たす依存関係は非ステーブルでもインストールされます。

  • 依存関係のあるパッケージについて、ベータ版などのプレリリースバージョンが直接指定されている場合
  • 公開されているパッケージのバージョンが全てプレリリースバージョンである場合

試しにmatplotlibのnightlyパッケージをインストールしてみたところ、以下のようにmatplotlib自体のバージョンも異なるケースに遭遇しました。

matplotlib(nightly)のインストールに使用したコマンド
$ uv pip install --upgrade --pre --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple --extra-index-url https://pypi.org/simple matplotlib
pipとuv pipでインストールされたパッケージの違い
pipとuv pipでインストールされたパッケージの違い

プレリリースバージョンを積極的に利用する機会は少ないと思いますが、Python標準のpipでは依存関係のあるパッケージでプレリリースバージョンが自動的にインストールされるケースもあるため、少し注意が必要です。

Ryeとuv

最初に示した「Pythonでよく使用されるパッケージ管理ツール」に記載した「Rye」もRust製のパッケージ管理ツールです。この2つのパッケージ管理ツールは、⁠uvを統一されたRyeの後継プロジェクトに拡張しつつ、Ryeの管理も引き継ぐ」ことが発表されています。

詳細について知りたい方は以下のブログを確認してみてください。1つめのブログはuvに関する最初のブログ記事でもあり、機能面の内容についても参考になります。

2つめのブログにも記載がありますが、Ryeは2023年に個人でスタートしたプロジェクトで、Pythonのパッケージ管理ツールがどうあるべきかを試したり、解決策を探ったりするにはとても便利なツールだったものの、さまざまなツールを寄せ集めて作成しているため脆弱さもあり、個人のサイドプロジェクトとして進めていくことの難しさもあったようです。

今後はRyeをAstral社の管理下に置きつつも、Pythonツールのテストベッドとしてさらに探求を続けるとのことで、その知見を活かして、uvはより高レベルなツールへと発展していくことを目指しているとのことです。

まとめ

uvはpipやvenvの代替として「Cargo for Python」になり得るとても興味深いパッケージ管理ツールです。プロジェクトはまだ初期段階ではありますが、さらに多くの機能が追加されていくことが予想されます。また、パフォーマンスを第一に考える場合に有効な選択肢の1つになるのではないかと思います。もちろん、uvがベストな選択肢であるとは現時点で言えませんが、uvの開発は互換性やパフォーマンス、プラットフォーム間の安定性の向上などに重点を置きながら進められており、初期段階のプロジェクトとは思えない安心感を持ち合わせています。ぜひ試してみていただければと思います。

おすすめ記事

記事・ニュース一覧