📑

Zsh Hooks を活用して uv venv の仮想環境を自動有効化する方法

2025/03/21に公開

本記事では、uv(パッケージマネージャー)のコマンド uv venv を実行した際に、デフォルト仮想環境を自動でアクティベートする仕組みについて紹介します。Zsh のフック機能である preexecprecmd を利用し、add-zsh-hook を活用したシンプルな実装例を解説します。

背景

日常的に Python の仮想環境を使っていると、仮想環境の有効化作業が面倒になることがあります。特に、uv を使って環境を管理している場合、「uv venv」コマンド実行時に対応する仮想環境を自動的にアクティベートできれば、作業効率が向上します。

コードの概要

以下のコードは、以下の点を実現しています:

  • フック関数の登録
    add-zsh-hook を使って preexecprecmd フックに関数を登録しています。
  • コマンドの解析
    コマンドライン全体をシェルの単語分割ルールに基づき配列に変換し、厳密に「uv venv」または「uv venv <venv_path>」に一致する場合にのみ処理を実行します。
  • 仮想環境の自動有効化
    指定された仮想環境(またはデフォルトの .venv)が存在する場合、その activate スクリプトを自動的に読み込みます。

実装例

以下は、実際に .zshrc に追加するコードです。最初に autoload -Uz add-zsh-hook を記述することで、add-zsh-hook が確実に利用可能となります。

# .zshrc に追加

autoload -Uz add-zsh-hook

# 最後のコマンドを配列として保持するグローバル変数
LAST_COMMAND=()

# preexec フックで実行する関数
uvvenv_preexec() {
  # シェルの単語分割(引用符も考慮)を行う
  LAST_COMMAND=("${(z)1}")
}

# precmd フックで実行する関数
uvvenv_precmd() {
  # コマンドが「uv venv」または「uv venv <venv_path>」の形であるかチェック
  if (( ${#LAST_COMMAND[@]} == 2 || ${#LAST_COMMAND[@]} == 3 )); then
    if [[ ${LAST_COMMAND[1]} == "uv" && ${LAST_COMMAND[2]} == "venv" ]]; then
      # 3番目の要素があればそれを、なければデフォルトの .venv を使用
      local venv_path=${LAST_COMMAND[3]:-.venv}
      if [[ -d "$venv_path" && -f "$venv_path/bin/activate" ]]; then
        echo "Activating virtual environment: $venv_path"
        source "$venv_path/bin/activate"
      else
        echo "Warning: Virtual environment $venv_path not found"
      fi
    fi
  fi
  # 次回の実行のためにコマンド変数をクリア
  LAST_COMMAND=()
}

# add-zsh-hook を使って各フックに関数を登録
add-zsh-hook preexec uvvenv_preexec
add-zsh-hook precmd uvvenv_precmd

詳細な解説

  1. autoload の利用
    autoload -Uz add-zsh-hook は、add-zsh-hook 関数が未ロードの場合に備えて、必ずロードするための記述です。これにより、フックの登録がエラーなく行えます。

  2. LAST_COMMAND の配列化
    uvvenv_preexec 関数では、"${(z)1}" を利用して入力されたコマンド文字列を配列に変換しています。これにより、引用符で囲まれた部分も正しく認識でき、正確なコマンドの解析が可能になります。

  3. 厳密なコマンドチェック
    uvvenv_precmd 関数内で、配列の要素数が 2 または 3 であること、かつ先頭の2要素がそれぞれ uvvenv であることを確認しています。これにより、余計な引数が付与された場合や意図しないコマンド実行時には動作しないようにしています。

  4. 仮想環境の検出と有効化
    指定されたパス(またはデフォルトの .venv)にディレクトリと bin/activate ファイルが存在するかを確認し、存在する場合は自動的に仮想環境を有効化します。もし存在しない場合は警告を表示します。

  5. フックの登録
    add-zsh-hook を利用して、先ほど定義した uvvenv_preexecuvvenv_precmd 関数をそれぞれのフックに登録しています。これにより、シェル実行時に自動的にこれらの関数が呼ばれる仕組みになっています。

その他の記事紹介

これ以外にも以下のようなPythonの開発に役立つシェルスクリプトを紹介しています。

Discussion