Pythonのプロジェクト・パッケージ管理ツール uv の使用方法メモ

# はじめに
海外のPython関連のGitHubリポジトリを見るとuvという管理ツールを使う前提になっていることが増えてきました。uvをざっと使ってみました。使い方とそのメリットを個人的にメモしておきます。内容の正確性には自信が無いので、正しい情報は公式ページをご確認ください。

[uv | 公式ページ](https://docs.astral.sh/uv/)

# uv を使用するメリット

* 複数のPython環境を管理できる。pyenvはすぐ使い方忘れるので便利かも。でも自分は採用しないことにした（理由は後述）
* どのパッケージをインストールしているのかがtomlファイル内に自動的に記載されるのでわかりやすい
* インストール・アンインストールが高速。キビキビした動作は気持ちが良い
* ```uv tool run```を使うとローカル全体で使用できる分離した仮想環境にツールが自動的にインストールされて実行できる。環境を汚さない

仮想環境についてはVSCodeを使用しているなら[Python Environment](https://marketplace.visualstudio.com/items/?itemName=ms-python.vscode-python-envs)を併用するととても楽チンなのでお勧めです。あまり知られていない拡張機能みたいですけど。仮想環境の簡単な管理ツールが欲しいならこの拡張機能だけでも十分便利ですのでお試しください。

# プロジェクトの作成

1. カレントフォルダをPythonプロジェクトにする
    ```bash
    uv init
    ```
2. カレントフォルダの下に名前をつけたPythonプロジェクトを作成する
    ```bash
    uv init <ProjectName>
    ```

初期状態ではファイルが5種類作成されます。
1. pyproject.toml
1. 仮想環境のPythonバージョンを指定するための.python-version
1. .gitignoreファイル
1. サンプルのmain.py
1. README.md

プロジェクト全体はgit管理下に置かれます。

次のようなオプションがあります。

README.mdは不要

```bash
uv init --no-readme
```

.python-versionファイルは不要

```bash
uv init --no-pin-python
```

git管理下に置かない

```bash
uv init --vcs none
```

# 仮想環境の作成

最初、仮想環境は存在してません。プロジェクト内部で何かしらのuvコマンドを発行すると自動的に.vnevフォルダが作成され、仮想環境となります。例えばこんなコマンドを発行します。

```bash
uv run main.py
```

```bash
uv sync
```

とりあえずプロジェクトを作成したら、uv syncを発行しておくのが良さそうです。

## パッケージ管理

公式ページでは[Managing dependecies](https://docs.astral.sh/uv/guides/projects/#managing-dependencies)に記載があります。
パッケージ情報はpyproject.tomlファイルに記載されていくので、何がインストールされているのかが一目瞭然です。Node.jsのpackage.jsonによるパッケージ管理によく似ています。

1. パッケージの追加
    ```bash
    uv add <package>
    ```
2. パッケージの削除
    ```bash
    uv remove <package>
    ```

tomlファイルを直接修正してパッケージを追加・削除・更新した場合は、```uv sync```を叩くと反映されます。これは便利。（本当にNode.jsのpackage.jsonによく似てます）

uv 越しに pip コマンド**もどき**が使用できます。requirements.txtを使用することもできます。

```bash
uv pip install <package>
```

```bash
uv pip install -r requirements.txt
```

ただし、この方法でインストールしたパッケージはpyproject.tomlファイルに反映されません。そしてこのuv越しのpipは公式のpipコマンドではなく、uvによる実装だそうなので、全く同じ動作をするわけでは無いことに注意が必要です。

[The pip interface](https://docs.astral.sh/uv/pip/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/d934a74b-393c-4b2a-8c84-969f6e3be95d.png)

# Python製ツール

ツールの使用はプロジェクトだけで使用する場合、仮想環境下にインストールされ、プロジェクト横断的にインストールする場合はプロジェクトの外にインストールされるようです。

[Using tools](https://docs.astral.sh/uv/guides/tools/)

## プロジェクト内部だけでツールを使用する

### 1. ツールのインストール

プロジェクト直下で次のコマンドでツールをインストールします。パッケージのインストールと同じです。

```bash
uv add <tool>
```

例えば型チェックをするmypyを入れるなら

```bash
uv add mypy
```

となります。

### 2. ツールの実行

```bash
uv run <tool>
```

```uv run``` コマンドは```uv run main.py```のようにファイルを指定してスクリプト実行するだけでなく、ツールの実行も可能です。

## プロジェクト横断でツールを使用する

こちらは少しややこしいです。```uv tool```コマンドを使うのですが、ツール管理を行う形でインストールするか、管理しないでインストールするかでインストール先と実行コマンドが異なります。

### ツール管理をするでインストールする場合

ここではツールとしてmypyを使用する場合を例にします。

#### ツールのインストール

```bash
uv tool install mypy
```

初回インストール時は.local/binフォルダがPATHに通っていないため、自分でShellに追加するか、次のコマンドを叩くのかどちらかを選択するように促されます。

```bash
uv tool update-shell
```

update-shellを叩くと、.local/binフォルダにパスを通すためのファイル（MacOSの場合は.zshenvファイル）が作成されますのでこちらを選択するのが良いでしょう。Shellを立ち上げ直すと、自動的に読み込まれてtoolが使えるようになります。


#### ツールの実行

プロジェクト直下で次のコマンドを叩きます。

```bash
mypy .
```

PATHが通った環境にインストールされているので、ツールそのものを実行できます。 間違っても```uv tool run mypy .```としてはいけません。```uv tool run```コマンドは別の意味を持つからです。（後述）


#### インストール済みツールの一覧表示

```bash
uv tool list
```

#### ツールのアンインストール

```bash
uv tool uninstall <tool>
```

#### ツールのインストール先PATHを表示

```bash
uv tool dir
```

### ツール管理をしない形式でインストールする場合

```uv tool```コマンドを使うと、ツール管理をする形式になりますが、ダウンロードしたツールをキャッシュとしてあくまでも一時的に扱う方法があります。

```bash
uvx mypy .
```

インストールコマンドは不要です。いきなりツール名とツールが必要な引数を渡せば、キャッシュにない場合は自動的にダウンロードしてさらにツールを実行します。

そしてややこしいことにこのuvxコマンドは```uv tool run```コマンドの短縮系なのです。なので、すごく注意必要です。

一時的にダウンロードしたツールは、uvのcacheディレクトリに存在するようです **（公式情報ではありません）** 。アンインストールする場合はcacheに対して操作することになります。

### キャッシュの中の特定のパッケージを削除

```bash
uv cache clean mypy
```

このコマンドでmypyは消えてくれますが、mypyが依存しているパッケージまでは消してくれません。

### 全てのキャッシュを削除

```bash
uv cache clean
```

#### キャッシュの場所を表示

```bash
uv cache dir
```

まとめると
* ```uv tool install```でインストールしたツールは、Globalにツールとして実行可能
* ```uvx```または```uv tool run```で一時的にインストールしたツールは常に```uvx```または```uv tool run```で実行しなければならない

となります。

uvxでの実行は手軽で良いのですが、cacheにダウンロードされたツールの一覧を表示する機能ないことには注意が必要です。

MCP Serverとしてのツールを使用する場合、uvxコマンドでMCP Serverのダウンロードと実行をする場合が多いようですが、どのMCP Serverがインストールされているのかを把握できなってしまう問題があるということです。

# Python 複数バージョンの管理

uv では Python 自身の管理もできます。複数のバージョンをインストールしておいて、各プロジェクトの仮想環境使用時に選択できます。

が、個人的にはuvでのバージョン管理はやりません。それは公式ページの次の注意書きを見たからです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/60ba5f44-ca0d-41ce-87b6-6d9132dc3ea0.png)

> uv によってインストールしたPythonはグローバルで使用できない、例えばpythonコマンドが使えません。

pythonコマンドにパスが通らないとなると、色々と問題が出そうです。例えばIDEのインテリセンスなどに影響が出そうです。出ないかもしれませんが。

なので、私はuvではPythonのバージョン管理はしません。

コマンドは以下の通りです。

インストール済みPythonの一覧。uvでインストールした以外のPythonも検知してくれるのは便利。

```bash
uv python list
```

最新版のPythonのインストール

```bash
uv python install
```

特定バージョンのPythonのインストール

```bash
uv python install 3.12
```

# 最後に

実はMCP Serverとしてuvxを使用されていることがとても多く、仕方なくuvを調べ始めました。uvxの挙動がよく分からず、コマンドを色々と叩いて挙動を確認しましたので、ダウンロード先がcacheであることはあくまで私の個人的な見解であることにご注意ください。