Pythonの環境構築をuvに変更した

概要

いままではシステムのPythonとpip、venvを使って構築していましたがグローバル環境にはPythonをインストールせずにuvのみに一本化してみました。Dropboxで複数のPCで共有している環境でも快適に使うことができそうです。

uvとは?

GitHub - astral-sh/uv: An extremely fast Python package and project manager, written in Rust.
An extremely fast Python package and project manager, written in Rust. - astral-sh/uv

上記のツールでPythonではなくRustでビルドされているため高速であり、さらにPythonに依存しなくて環境構築ができるメリットがあります。

これまでの構築手順例

# Pythonを入れる
sudo apt -y install python-is-python3 python3-pip python3-venv

# 仮想環境を作成
python3 -m venv ~/.venv

# 仮想環境を有効化させる
. ~/.venv/bin/activate

上記のようにシステムのグローバル環境にまずはPythonをインストールし、その後venvにてプロジェクト個別の環境を作成してactivate後にpipなどで環境構築をします。

この結果グローバルのPythonとプロジェクト別のvenv環境が混在してどっちで実行されているのかがわかりにくいことや、毎回のactivateが面倒でした。

uvでの構築手順例

Jupyter Notebookを利用する – 生活と学びとプログラム

今回は上記のページにあったJupyterを使って、かんたんな統計とグラフ化をしてみたいと思います。上記だと普通のJupyter Notebookですが、Jupyter Labを今回使ってみたいと思います。

uvのインストール

# Windowsの場合(WinGet)
winget install astral-sh.uv

# Windowsの場合(powershell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Linuxの場合
curl -LsSf https://astral.sh/uv/install.sh | sh

まずはuvを入れます。どちらもユーザー別の領域にuvが保存されていますので管理者権限は必要ありません。中身は単体の実行ファイルなのでコピーしてきても動きます。

プロジェクトの作成

uv init Jupyter-Lab

initのあとにプロジェクト名を入れることで新しいフォルダが作成されて、プロジェクトが作成されます。フォルダ名を省略するといまいるフォルダに必要なファイルを作成することとなります。

プロジェクト名にJupyter-Labと中途半端な名前がついているのには理由があります。JupyterやJupyterLabなどのツールと同じ名前の命名はしないでください。ツールと同じ名前のプロジェクト名は実行時にいろいろ問題が起こって謎のエラーに悩まされます。Jupyterだとその後のaddでエラーになるのでわかりやすいのですが、JupyterLabの場合は動いているように見えますが、カーネルの追加などができなくなります。

ためしに作成してみたところ、下記のようなファイルが作成されています。標準でgitなどのファイルも作成されます。

/tmp$ uv init Jupyter-Lab
Initialized project `test` at `/tmp/Jupyter-Lab`
/tmp$ tree Jupyter-Lab/ -a
Jupyter-Lab/
├── .git
│   ├── HEAD
│   ├── branches
│   ├── config
│   ├── description
│   ├── hooks
│   │   ├── applypatch-msg.sample
│   │   ├── commit-msg.sample
│   │   ├── fsmonitor-watchman.sample
│   │   ├── post-update.sample
│   │   ├── pre-applypatch.sample
│   │   ├── pre-commit.sample
│   │   ├── pre-merge-commit.sample
│   │   ├── pre-push.sample
│   │   ├── pre-rebase.sample
│   │   ├── pre-receive.sample
│   │   ├── prepare-commit-msg.sample
│   │   ├── push-to-checkout.sample
│   │   ├── sendemail-validate.sample
│   │   └── update.sample
│   ├── info
│   │   └── exclude
│   ├── objects
│   │   ├── info
│   │   └── pack
│   └── refs
│       ├── heads
│       └── tags
├── .gitignore
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

11 directories, 23 files

下記のようにオプションでファイルのバージョン管理をnoneにすることで作成を抑制できますが、コマンドを覚えるよりは不要なファイルをあとで消したほうが楽だとは思います。

/tmp$ uv init test --vcs none
Initialized project `test2` at `/tmp/test`
/tmp$ tree test -a
test
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

1 directory, 4 files

依存モジュールを追加(Jupyter)

uv add jupyter

まずはJupyterをいれます。addで必要なモジュールをプロジェクトに追加することができます。依存関係も内部で自動的に処理してくれるので非常に楽です。

Jupyterを動かす

uv run jupyter lab

runのあとに実行したいコマンドを入れることでプロジェクトの仮想環境上で実行されます。uvの場合には明示的にactivateをさせる必要がなく、runで実行するのが好ましいみたいです。

Windowsだと自動的にブラウザで上記のページが開きます。Linuxの場合には「http://127.0.0.1:8888/lab?token=」のURLがコンソールに表示されているのでCtrl+クリックなどでブラウザで開きます。

サンプルのノートブックを作成する

ノートブックに追加しました。

実行してみる

あたりまえですが、内部で利用しているpandasがないとエラーがでます。

uvでモジュールを追加する

コンソールで「Ctrl+C」を押して少し待つとInterruptedと表示されてJupyter Labが終了します。

uv add pandas

上記でpandasを追加します。

uv run jupyter lab

再度Jupyter Labを起動します。

次はmatplotlibが足りないと言われます。「Ctrl+C」で終了します。

uv add matplotlib

上記で追加してから、立ち上げ直して再実行します。

インポートと基本統計までは通るようになりました。しかしグラフのところでエラーがでています。どうやらフォントが足りないようです。

uv add japanize-matplotlib

日本語を使うためのモジュールを追加します。

一番上で「import japanize_matplotlib」を追加してモジュールを読み込むことで、一番下のグラフで日本語が正しく描画されるようになりました。

(オプション)Jupyter Labの日本語化

uv add jupyterlab-language-pack-ja-jp

上記でJupyter Labを日本語化するモジュールを追加できます。

設定から言語、日本語を選択することで日本語化することができます。

(オプション)デバッグの有効化

昔は自動的に有効化されていたような気がするのですが、ノートブックの右上の虫のマークをクリックするとデバッグモードが有効になり、右側にある現在の変数一覧などが表示できます。

(オプション)フォーマッターの追加

uv add jupyterlab-code-formatter black isort

Jupyter Labの拡張機能のjupyterlab-code-formatterと、内部で利用しているblackとisortを追加します。

uv run jupyter labextension list

上記のコマンドで有効になっている拡張機能の一覧を確認できます。

C:\tmp\Jupyter-Lab>uv run jupyter labextension list
JupyterLab v4.4.1
C:\tmp\Jupyter-Lab\.venv\share\jupyter\labextensions
        jupyterlab_code_formatter v3.0.2 enabled ok (python, jupyterlab_code_formatter)
        jupyterlab_pygments v0.3.0 enabled ok (python, jupyterlab_pygments)
        @jupyter-notebook/lab-extension v7.4.1 enabled ok
        @jupyter-widgets/jupyterlab-manager v5.0.14 enabled ok (python, jupyterlab_widgets)

jupyterlab_code_formatterが追加されているのがわかると思います。ちなみにプロジェクト名をJupyterLabにすると拡張機能が追加できません。このリストコマンドもエラーになり、原因不明でかなり困るので他の名前をつけましょう。。。

拡張機能を追加したあとに起動すると上のメニューに丸っぽいアイコンが追加されています。これを押すことでフォーマッターが動きます。importの順番などがソートされました。

最終的な設定ファイルの確認

[project]
name = "jupyter-lab"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
    "black>=25.1.0",
    "isort>=6.0.1",
    "japanize-matplotlib>=1.1.3",
    "jupyter>=1.1.1",
    "jupyterlab-code-formatter>=3.0.2",
    "jupyterlab-language-pack-ja-jp>=4.3.post3",
    "matplotlib>=3.10.1",
    "pandas>=2.2.3",
]

pyproject.tomlを開いてみました。上記がこのプロジェクトの設定一覧です。uv runを実行するときにこのファイルを参照して必要なモジュールなどを自動的に構築してくれますので、プロジェクトのファイルを受け取った人はuvが入っていたら「uv run jupyter lab」だけで自動的に環境構築をして起動することが可能になります。

違う環境で実行する場合.venvフォルダに注意

さてpyproject.tomlがあることでそのまま他の環境で環境構築できるのですが、注意点があります。

/mnt/c/tmp/Jupyter-Lab$ uv run jupyter lab
error: Project virtual environment directory `/mnt/c/tmp/Jupyter-Lab/.venv` cannot be used because it is not a valid Python environment (no Python executable was found)

同じフォルダをWSL2上のUbuntuから実行した際のエラーです。uvは入っているのですが、.venvの中身がWindows向けなのでエラーになっています。環境を更新するsyncオプションがあるのですが、これも同じエラーになります。

uv venv

正解は仮想環境を作り直すvenvオプションになります。

/mnt/c/tmp/Jupyter-Lab$ uv venv
Using CPython 3.13.3
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate

上記のように.venvを作成するコマンドとなります。

rm -rfv .venv/
uv run jupyter lab

ですが、上記のように.venvを消せば次回なにか実行したときに自動的に再作成してくれます。

プロジェクトファイルを人に渡す方法

$ git add .
$ git commit -m "add"

とりあえず配布するものをコミットします。

$ git archive HEAD --output=/tmp/Jupyter-Lab.zip

git archiveで配布用のファイルを作成してみます。

$ zipinfo /tmp/Jupyter-Lab.zip
Archive:  /tmp/Jupyter-Lab.zip
Zip file size: 86974 bytes, number of entries: 9
-rw----     0.0 fat      109 tx defN .gitignore
drwx---     0.0 fat        0 bx stor .ipynb_checkpoints/
-rw----     0.0 fat    24666 tx defN .ipynb_checkpoints/plt_test-checkpoint.ipynb
-rw----     0.0 fat        5 tx stor .python-version
-rw----     0.0 fat        0 tx stor README.md
-rw----     0.0 fat       89 tx defN main.py
-rw----     0.0 fat    24666 tx defN plt_test.ipynb
-rw----     0.0 fat      391 tx defN pyproject.toml
-rw----     0.0 fat   171556 tx defN uv.lock
9 files, 221482 bytes uncompressed, 85788 bytes compressed:  61.3%

Git系はなくなりましたがJupyterLabのチェックポイントファイルが追加されてしまっています。.gitignoreで無視する設定を追加すべきでした。git addするまえにgit statusを確認しましょう!

ちなみにノートブックはトップレベルに入れておくとあとでファイルが増えたときに整理できなくなるので、dataフォルダとかを追加して管理したほうがおすすめです。

(オプション)Dropbox管理用に.venvを隔離する

.venvフォルダはデフォルトでプロジェクトフォルダの中にありますがDropboxを利用している場合にはファイルサイズが増える原因だったり、Dropboxの同期中にファイルをロックするのでuv venvなどが失敗することがあります。そこで.venvフォルダを/tmp配下などに隔離したいと思います。

Windows用

where uv
if %errorlevel%==1 (
    winget install astral-sh.uv
)

set VIRTUAL_ENV=C:\tmp\.venv
rmdir /S /Q .venv
rmdir /S /Q "%VIRTUAL_ENV%"
uv venv "%VIRTUAL_ENV%"
call "%VIRTUAL_ENV%\Scripts\activate.bat"
uv run --active jupyter lab

deactivate

run.batという名前でプロジェクトの中に上記のバッチファイルを入れてあります。whereでuvがインストールされているかを確認して、インストールされていない場合にはWinGetで追加しています。

まずは.venvの隔離場所を指定してから、既存環境の.venvをrmdirで削除しています。uv venvで仮想環境を作成したあとにactivateを実行しています。この状態の.venvはプロジェクトのpyproject.tomlが反映されていない素の状態であり、syncやrunを実行することで環境構築がされます。

注意点としてはドキュメントではactivateしたVIRTUAL_ENVの仮想環境が有効利用されるとありましたが、プロジェクトフォルダ直下の.venvが優先利用されます。そのため–activeオプションを追加して、activateした仮想環境を使うように指示をする必要があります。

Linuxの場合

#!/bin/bash

if ! command -v uv > /dev/null 2>&1; then
    curl -LsSf https://astral.sh/uv/install.sh | sh
fi

set -e

PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$PROJECT_DIR"

export VIRTUAL_ENV=/tmp/.venv
rm -rf .venv
rm -rf "$VIRTUAL_ENV"
uv venv "$VIRTUAL_ENV"
source /tmp/.venv/bin/activate
uv run --active jupyter lab

deactivate

ほぼ同じコードでrun.shで保存してあります。

まとめ

uvを利用することでPython環境がまったく入っていない場合でもpyproject.tomlを使ってかんたんに環境構築が可能です。

uv以外の管理ツールもありますが、いまのところuvのみ使うのがシンプルな環境構築で使いやすいと思います。GitHubのチケットなどを見たところuvへの不満としてactivate用のコマンドが準備されていないなどがありましたが、別のプロセスを立ち上げる以外でアプリからactivateするのは困難なのでactivateするのではなくrunを使えとの方針のようでした。

コメント