pyenvからuvへお引越し

# 初めに
開発環境の構築は、pyenvを使用している。今後、LLMを用いた開発を進めていくにあたり、今一度開発環境を見直すことにした。
pyenv自体は、主にpythonのバージョン管理を行うことができ、PythonとAnacondaを頻繁に利用していた。特にAnacondaには最低限必要なライブラリがimportされており、使用しやすかった。
しかし、LLMのライブラリの更新速度や新規のライブラリの登場が多くpipには対応しているライブラリでも、condaではインストールできないケースも増えてきた。
そこで、pipを使用して環境を構築したいと考えた。
良い機会なので、pyenvごと見直ししたいと思いリサーチしていた際に見つけたものがuvである。

# uvとpyenvの違い

uvではvenvと同様に仮想環境を用意し使用する。ここで、一度仮想環境について簡単に述べることとする。
pyenvでもディレクトリ毎にpythonのバージョンを変更できるが、一体何が異なるのか。。。

## 仮想環境とは

仮想環境とは、仮想マシンよりも軽量であり、プロセスやアプリケーションのための専用環境である。
仮想マシンとはレイヤーが異なるイメージを持てば良い。これにより、依存関係の衝突を避けることができる。具体的には、pipとcondaの衝突等だろうか。。。

仮想環境とは、プロセスレイヤーで構築された環境という認識を持った。

## uvが人気な理由
最近、uvが人気なようだ。特にLLMを用いた開発ではよく使用されているように感じる。先日公開されたCyberAgentの記事においてもuvの使用を推奨していた。venvはpythonに付属している仮想環境であり、血統の良さは感じる。
uvの利用が推奨される理由として、その速度が上げられる。Rustで記述されているため高速らしい。（なぜ、Rustだと高速なのかは不明。~~pyenvはpythonで記述されているため遅いかと言われるとそんなに気にはならない。。。ここでいう速度とは、環境構築に要する時間だろうか？~~`pip`とは比べ物にならないくらい早いため、ストレス軽減になりそう。）

機能面で考えると、仮想環境を使用するためには、pyenv + venvを使用する必要が出てくる。
一方で、uvを使用することで、バージョン管理と仮想環境の構築をuv単体で行うことができる。
どうせなら一つのアプリケーションで仮想環境とバージョン管理できる方が楽であるため、uvを実装することにした。あと、流行りには乗っておかないとね！！

# pyenvの環境確認
引っ越しをする前に環境の確認をする。
## バージョンの確認
pyenvでは、installしているバージョンのリストを`pyenv versions`で確認することができる。また、使用しているpythonのバージョンが`.python_versionsに記述されている。

## ライブラリの確認
pipでインストールされているライブラリは`pip freeze`を使用することで確認できる。適当なファイルに保存しておき、`uv pip install -r [freezed lib list file]`コマンドを使用することでライブラリをインストールすることができる。


# uvのテスト
実際にuvのテストを行う。pyenvとuvは同時に使用できるため、慣れるまではpyenvを使用しながらでも良いかもしれない。
## uvのインストール
macではHomebrewを使用しインストールを行うことができる。
```zsh
brew install uv
```
ちなみに、windowsでは
```PowerShell
pip install uv
```
でインストールを行うことができる。

## uv仮想環境の構築
uvを使用し、テスト用の仮想環境を構築する。

## テスト環境の構築
```zsh
brew install uv
```
uvのバージョンを確認してみると

```zsh
uv --version
uv 0.7.0 (Homebrew 2025-04-29)
```
である。Homebrewを通してインストールを行なった場合上記のような表示が確認できる。

次にuvを使用し、仮想環境を構築する。次のコマンドを実行すると、hello-worldディレクトリが作成される。

```zsh
Work uv init hello-world
Initialized project `hello-world` at `/Users/HogeHoge/Work/hello-world`
```

`uv init [project-name]`を使用する事で、プロジェクトを使用することができる。

プロジェクト内のファイル構成は次のようになっている。

```zsh
ls -a
.gitignore
.python-version
main.py
pyproject.toml
README.md
```
それぞれのファイルの内容をまとめると次のようになる。

|ファイル名|内容|
|--|--|
|.gitignore|Gitのトラッキング対象外にするファイルを設定|
|.python-version|pythonのバージョンを指定|
|main.py|プロジェクトのメインファイル|
|pyproject.toml|プロジェクトの基本設定について記述されている|
|README.md|README:お気持ち表明をするファイル|

`uv init [project]`を実行することで、プロジェクトの実行に必要なファイルを生成することができる。

`.pyproject`ファイルの内容から求められるpythonのバージョンやプロジェクト名を確認することができる。

## 実行

プロジェクト中の`main.py`を実行するためには、以下のコマンドを使用する。
```zsh
uv run main.py
Hello from hello-world!
```
Hlloの出力を確認することができる。

## ライブラリの追加
ライブラリのテストを行うためにプロジェクト`lib-test`を作成する。
```zsh
uv init lib-test
```
`main.py`を次のように変更する。

```python
import numpy as np

def main():
    print("Hello from lib-test!")

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

これを実行`uv run main.py`すると
```zsh
uv run main.py 
Traceback (most recent call last):
  File "/Users/yoshijun/Work/lib-test/main.py", line 1, in <module>
    import numpy as np
ModuleNotFoundError: No module named 'numpy'
```
numpyがインストールされていないことがわかる。

`uv add numpy`を使用することで、numpyのライブラリを追加することができる。
```zsh
uv add numpy
Resolved 2 packages in 162ms
Prepared 1 package in 189ms
Installed 1 package in 7ms
 + numpy==2.2.5
 ```

`pyproject.toml`を確認すると
```zsh
[project]
name = "lib-test"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "numpy>=2.2.5",
]
```
と表示される。dependenciesにnumpyが追加されていることがわかる。
次に、`uv remove umpy`のコマンドを使用し、`pyproject.toml`を確認すると
```zsh
[project]
name = "lib-test"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
```
dependenciesからnumpyが消えていることがわかる。

uvにおけるライブラリの管理は`uv add [lib]`と`uv remove [lib]`を使用することで管理ができる。

### 余談

vscodeを使用し作成したプロジェクトを開くと、当然のように仮想環境の設定で実行することができる。

よくできてるなぁ。。。。

## バージョン管理
pyenvと同様にpythonのバージョン管理を行うことができる。しかし、必要なバージョンは適宜uvを通してインストールする必要がある。

### バージョンのインストールとアンインストール
`uv python list`コマンドを使用することで、uvで管理しているpythonのversionを確認することができる。
```zsh
uv python list
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                   /opt/homebrew/bin/python3.13 -> ../Cellar/python@3.13/3.13.3/bin/python3.13
cpython-3.13.3-macos-aarch64-none                   /opt/homebrew/bin/python3 -> ../Cellar/python@3.13/3.13.3/bin/python3
cpython-3.13.3-macos-aarch64-none                   /Users/yoshijun/.pyenv/shims/python3.13
cpython-3.13.3-macos-aarch64-none                   /Users/yoshijun/.pyenv/shims/python3
cpython-3.13.3-macos-aarch64-none                   <download available>
cpython-3.13.3+freethreaded-macos-aarch64-none      <download available>
cpython-3.12.10-macos-aarch64-none                  /Users/yoshijun/.local/share/uv/python/cpython-3.12.10-macos-aarch64-none/bin/python3.12
cpython-3.11.12-macos-aarch64-none                  <download available>
cpython-3.10.17-macos-aarch64-none                  <download available>
cpython-3.9.22-macos-aarch64-none                   <download available>
cpython-3.9.6-macos-aarch64-none                    /usr/bin/python3
cpython-3.8.20-macos-aarch64-none                   <download available>
pypy-3.11.11-macos-aarch64-none                     <download available>
pypy-3.10.16-macos-aarch64-none                     <download available>
pypy-3.9.19-macos-aarch64-none                      <download available>
pypy-3.8.16-macos-aarch64-none   
```

新しくインストールする場合は`uv python istall [version]`を使用する。実際に古いVer.をインストールしてみる。

```zsh
$ uv python install 3.11
Installed Python 3.11.12 in 1.29s
 + cpython-3.11.12-macos-aarch64-none
```

再度、インストールされているリストを確認すると、
```zsh
uv python list
~
cpython-3.11.12-macos-aarch64-none                  /Users/yoshijun/.local/share/uv/python/cpython-3.11.12-macos-aarch64-none/bin/python3.11
~
```

のようにインストールされていることが確認できる。インストールしたリストは`uv python uninstall [version]`を使用することで、削除することができる。

```zsh
uv python uninstall 3.11
Searching for Python versions matching: Python 3.11
Uninstalled Python 3.11.12 in 87ms
 - cpython-3.11.12-macos-aarch64-none]]
```

リストを確認すると、消えていることが確認できる。

### バージョンの指定
プロジェクトにおけるバージョンの指定は`uv python pin [version]`を実行することで指定することができる。