2021/06/16
はじめに
Python パッケージをそのままの pip ですべてインストールして使っていると,パッケージリストが肥大化したり,バージョン指定があるパッケージを使用する際などにいちいちインストールしなければならなくなり,不便なことがある.
そんな人にとって重宝するのが,virtualenv
やpyenv
やanaconda
であろう.
これらを使うと,プロジェクトごとにライブラリを管理できるため,pip freeze
などもラクラクである.
しかし,これらをそのまま使おうとすると,プロジェクトを切り替える毎に環境をアクティベートするのが面倒であった.
特に,ディレクトリベース(anaconda
以外)の方を使うと,隠しファイルにして環境情報を格納するので,どこにアクティベートするスクリプトが負いてあるのか探すのが自分にとって大変だった.
考えたこと
他にもよい扱い方があるかもしれないが,私の場合は以下を考えた.
環境情報を格納するファイルを.venv
という名前で決め,カレントディレクトリが.venv
に管理されたディレクトリかどうかを自動で探せばいいじゃんと思った.
もうちょっと考えたこと
Python スクリプトに限らずだが,ファイルをネストして配置することも多いので,.venv
の適用範囲は,カレントディレクトリはもちろんのこと,子ディレクトリ,孫ディレクトリ,曽孫ディレクトリ(?)...までずっと広げたい.
つまり,再帰して.venv
を探せばよい.
また,.venv
を/
などに配置することは(私の場合は)ありえないので,探索範囲を/home/<username>
までと決めてしまった.
設定
こんな感じ
.bashrc
_auto_activate_nested_venv() {
if [[ ${PWD} != *${HOME}* ]]; then
return
fi
env_key='.venv'
search_path=$PWD
while [ ${search_path} != ${HOME} ]
do
if [ -e "${search_path}/${env_key}" ]; then
env_dir=${search_path##*/}
if [ ${_VENV_NAME} ] && [ ${env_dir} == ${_VENV_NAME} ]; then
break;
fi
if [ "$VIRTUAL_ENV" != "${search_path}/${env_key}" ]; then
env_owner=$(stat -c '%U' ${search_path}/${env_key})
if [ $env_owner != $USER ]; then
echo '[VENV OWNER]: '$env_owner
# For security: question if `.env` is third party
read -p "Do you activate? [y/N]" -n 1 -r
if [[ ! $REPLY =~ ^[yN]$ ]]; then
return
fi
else
echo '[ENV OWNER]: '$env_owner
fi
_VENV_NAME=$(basename ${search_path##*/})
echo Activating virtualenv \"$_VENV_NAME\"...
VIRTUAL_ENV_DISABLE_PROMPT=1
source ${search_path}/${env_key}/bin/activate
_OLD_VIRTUAL_PS1="$PS1"
PS1="(pyenv $_VENV_NAME)$PS1"
export PS1
fi
break
fi
search_path=${search_path%/*}
done
if [ ${_VENV_NAME} ] && [ ${HOME} == ${search_path} ]; then
_VENV_NAME=''
deactivate
fi
}
export PROMPT_COMMAND=_auto_activate_nested_venv # この書き方だと上書きするので,すでに他に設定している場合は,既存を含めるようにexportする
おわりに
だいぶ便利になった
参考
(過去に作った設定なので,参考元を忘れてしまいました...すみません)