uvでPython仮想環境(.venv)を移動したらどうなる?従来のvenvとの違いを検証

最近、読んだjunichimさんのエントリ「venv環境を移動してはまった話」という記事。確かに自分もハマったことがあったな~と勉強になりました。

blog.mori-soft.com

で、ふと思ったんです。「最近話題の爆速パッケージマネージャーuvならどうなの🤔」って。

まず結論から

uv runで実行すれば移動後も動きました🤩(ただし完全ではないっぽい)

最初は「できない」と思い込んでいたんですが…。今回はその実験過程を共有します。

⚠️ 【注意】この実験はGitHub Codespaces上のUbuntu(22.04)での結果です。Windows/macOSでは挙動が異なる可能性があります。

実験!

まずはuvを使用したプロジェクトを作成する

GitHub Codespaceの環境を起動して実験開始!

# プロジェクト作成
$ mkdir ~/uv_move_test
$ cd ~/uv_move_test
$ uv init test_project
$ cd test_project
$ uv add requests pandas numpy

テストスクリプトtest_script.pyを作成

import sys
import requests
import pandas as pd
import numpy as np

print(f"Python実行パス: {sys.executable}")
print(f"Requests version: {requests.__version__}")
print(f"Pandas version: {pd.__version__}")
print(f"NumPy version: {np.__version__}")

スクリプトの実行をすると…

# 動作確認
$ uv run python test_script.py
# Python実行パス: /home/codespace/uv_move_test/test_project/.venv/bin/python3

よし、動いた。

移動してみる

では本題、移動してみます。

$ cd ~
$ mv uv_move_test/test_project uv_moved_test/
$ cd uv_moved_test/test_project

# 移動後にスクリプトを実行すると…
$ uv run python test_script.py

えっ、動いた...⁉️

Python実行パス: /home/codespace/uv_moved_test/test_project/.venv/bin/python3
Requests version: 2.32.5
Pandas version: 2.3.2
NumPy version: 2.3.3

普通に動いてる!しかも新しいパスを認識してる🤔

なぜ動くのか調べてみると…

従来のvenvが移動できない理由

.venv内に絶対パスがベタ書きされてるから。

# pyvenv.cfg
home = /usr/bin/python3  # 絶対パス

# activate
VIRTUAL_ENV="/old/path/.venv"  # 絶対パス

# 各種実行ファイル
#!/old/path/.venv/bin/python  # shebangも絶対パス

uvはどうしてるの?

調べてみると、uvは回避策もっているのでした。

1. uv runが仲介役になる

2. ただし完全ではない

# これは動く
$ uv run python script.py
# これは失敗する可能性大
$ .venv/bin/python script.py  # 古いパスを指してるから

3. .venv内部は依然として古いパスのまま

# 移動後も古いパスが残っている
$ head -n 1 .venv/bin/pip
#!/home/codespace/uv_move_test/test_project/.venv/bin/python

つまり、uv runがよしなに仲介してくれるから動くんです。

activateについての重要な話

uv公式はactivateを推奨していない

実はuvの公式ドキュメントでは、activateを使わない運用が推奨されています。

# uv推奨スタイル
$ uv run python script.py
$ uvx pytest

# 従来のスタイル(非推奨)
$ source .venv/bin/activate
$ python script.py

その理由は?

  • uv runが環境を自動的に管理
  • activateによる環境変数の汚染を防げる
  • プロジェクトごとの環境切り替えが簡単

実用としてはどうなのか?

できること

  • プロジェクトフォルダの名前変更(uv run経由なら)
  • ディレクトリへの移動(uv run経由なら)
  • 開発中の一時的な移動

できないこと(非推奨)

  • .venv/bin/pythonを直接叩くと失敗
  • チーム共有する場合には、たとえ同じOSでも危険

正しいチーム共有の方法

.venvを共有するのではなく、uv.lockを共有する

そうすれば、uv syncコマンドで即復元できます。

おわりに

uvを使用すると場合

  • uv run経由なら移動後も動く(直接実行は不可)
  • 壊れてもuv syncで即修復(数秒)
  • そもそもactivate不要の設計

最初は「uvでも移動できないでしょ」って思い込んでました。でも実験したらuv run経由で問題なく動いて驚きました。完全な解決とはなりませんが、実用上十分な解決です。


参考リンク

⚠️ 他の環境での動作は未検証です