Introdaction
Pythonで仮想環境作ったはいいけど毎回activate/deactivateするのが面倒臭い。
自動化させましょう。
環境
Python3.3 以降
Ubuntu 20.04
特徴
- プロジェクトディレクトリに移動した際に、直下に仮想環境があれば、自動でactivateする
- プロジェクトディレクトリの外へ
cd
する際には自動的にdeactivateする- 同一プロジェクトディレクトリ内で
cd
してもdeactivateしない
- 同一プロジェクトディレクトリ内で
- 仮想環境名は任意に設定できる
※参考にさせていただいたのはこちら[1−3]。
こちらのページで示されている方法を実装すればそれで十分だったが、プロジェクトディレクトリ下にあるサブディレクトリに移動してもdeactivateされてしまったり、仮想環境名を固定しなければいけなかったりと、ちょっと自分の使い方では痒所に手が届かなかったので自分好みにカスタマイズした。
方法
cdを関数化して、cd先に仮想環境があったときにactivateを実行させれば良い。処理の流れとしては、
- 任意のディレクトリに移動
- 仮想環境があるか判別
- 仮想環境がある場合は、仮想環境ディレクトリ下にある
bin/activate
を実行
となる。具体的には、下記のスクリプト.venvSwitcher.sh
を作成し、~/.bashrc
で呼び出して実行させる。直接~/.bashrc
に追記する形でも良いのだが、個人的に~/.bashrc
が冗長になるのを好まないので、別途作成する。
#!/bin/bash
cd() {
builtin cd "$@"
function activate_venv() {
if [[ $(ls -a -U1 .venv/ |wc -l) < 1 ]]; then #.venvディレクトリ下に仮想環境なし
echo "There is no virtual env"
elif [[ $(ls -a -U1 .venv/ |wc -l) > 1 ]]; then #.venv直下に仮想環境が複数ある
echo "There are over 2 venv dirs"
echo "Please activate venv manually"
else #.venvディレクトリが1つある時
source .venv/$(ls .venv/)/bin/activate
fi
}
if [ -z "$VIRTUAL_ENV" ]; then
if [ -d .venv ]; then
activate_venv
fi
elif [[ $(pwd) != $(dirname $(dirname "$VIRTUAL_ENV"))/* ]] ; then
deactivate
if [ -d .venv ]; then
activate_venv
fi
fi
}
解説
仮想環境名について
細かい処理の解説の前に、ちょっとこだわりたいポイントとして仮想環境名hoge
について検討する。
”cd先に仮想環境があれば、そのディレクトリ下の/bin/activate
を実行”という挙動を実装する際に以下の懸念点が生じる
-
仮想環境名が分からない
上記Step2での仮想環境の有無チェックにおいて、その環境名が分からないことには判別しようがないのである。cd directory
に追加で仮想環境名を変数として引き渡すとなると余計な手間が増えて面倒だし、そもそも仮想環境名を覚えておく(事前に確認しておく)必要があるので本当にだるい。cd先の、つまりプロジェクトのディレクトリ名と同じ仮想環境名にすることで対応可能なのだが、任意の名前が付けられないと困ることも多い(バージョン切り替えのために複数の環境が用意されていたりなど) -
仮想環境名を定数にするために共通の名前にする”ことは避けたい
仮想環境をactivateすると、(.venv)username@PCname:~$
のようにプロンプトの頭に環境名が表示されるわけだが、環境名が共通では"どの仮想環境かは分からないけれど、activateされている状態”というインジケータになってしまう。全自動でのactivateが上手く機能しているのであれば別に気にすることでもないのだが、例えば同じプロジェクト内で仮想環境を切り替えたいという場合には違いがわかった方が良い。
そのために以下の方針を採用する
- 目標:何も考えずに気がついたらactivateしてくれている、そんな素敵な環境を作る。
- 方法:
.venv
ディレクトリ下に、仮想環境を作る
自作の.venv
ディレクトリ(プロジェクトに関わらず共通名)を一回噛ませ、任意の仮想環境名はlsで取得するという作戦。”仮想環境は.venv直下にあるという”前提条件を作ることで、仮想環境名に関わらず一意に仮想環境を指定できるようにする。
スクリプトについて
-
builin
builtin
を使うことで、自作cd関数のなかで優先的にビルトインコマンドのcdを実行させる。その後にactivation周りの処理を組んでいくことになる -
activate_venv function
本スクリプトでは、.venv
ディレクトリ直下にあるディレクトリに応じた処理をさせる。
-
.venv/
にディレクトリがないとき:環境がないと警告 -
.venv/
に仮想環境ディレクトリが複数あるとき:手動でactivateするように警告 -
.venv/
に仮想環境が1つあるとき:activation
.venv
下に仮想環境が複数ある場合は警告を出して手動でのactivateを促しているが、キーボード入力を利用してどれをactivateさせるかを選ばせても良いかもしれない
-
if [ -z "$VIRTUAL_ENV" ]; then
仮想環境がactivateされると、環境変数VIRTUAL_ENV
が定義される。これを利用し、まだ環境変数VIRTUAL_ENV
が未定義(文字列長が0)であればactivate_venv
を実行するという場合わけをする。 -
elif [[ $(pwd) != $(dirname $(dirname "$VIRTUAL_ENV"))/* ]] ; then
cd先のディレクトリ(pwd)が、現在の仮想環境がある親ディレクトリとは異なる場合、一度deactiavteしてからactivate_venv
を実行する。これにより、仮想環境がある.venv
の親ディレクトリから出た際にはdeactivateがなされ、かつ移動先のディレクトリにまた.venv
ディレクトリがあればactivationがなされる。