いつでもティータイム

ここはハートが目覚めて花咲いてリスペクトしあう場所

pipenv を conda のように使う

pipenvディレクトリごとにPipfileおよびPipfile.lockを作成し、ディレクトリ単位で仮想環境を管理する。 この管理方法はプロジェクトなどにおいては非常に理にかなっている。 まっさらな状態から、プロジェクトに必要なパッケージだけを入れるだけで良いからだ。

しかし、普段からちょっとしたことでもPythonにやらせる場合にはこの管理方法は少し使いにくい。 そこで任意の場所で共通の環境を使えるように、Pipfileを管理するためのディレクトリを作成し、その場所にpipenv shellする関数を作成する。 こうすることで、conda activate hogeと同様のことが実現できる。

準備

まずはパスの設定やディレクトリの作成を行う。 また、ここではzshを対象とする。

Pipfileを保管するディレクトリを作成する。 ここでは、ホーム直下の.pipenvenvに保管することにする。

$ mkdir ~/.pipenvenv

作成したディレクトリへのパスを作成しておく。 パスの設定は.zshenvに記述しておく。

echo 'export $PIPENV_ENV_ROOT=$HONE/.pipenvenv' >> ~/.zshenv

次に自作関数のオプションなどを補完するための補完関数を置くディレクトリを用意する。 ここでは、~/.zsh-functionというディレクトリを作成し、そこに補完関数を置く。

mkdir ~/.zsh-function

zshの補完関数を場所を示す環境変数$fpathであるので、作成したディレクトリへのパスを追加する。

echo 'fpath=($HOME/.zsh-function $fpath)' >> ~/.zshenv

関数の作成

自作コマンドはシェルスクリプトとして作成した方がいい気もするが、ここでは.zshrcに直接記述することにする。

function gpipenv() {
    ERROR_STATUS=1
    if [ $# -lt 2 ]; then
    echo "Usage: gpipenv command env_name [package]"
    return $ERROR_STATUS
    fi

    ENV_PATH="$PIPENV_ENV_ROOT/$2"
    if [ $1 = "create" ]; then
    if [ -d $ENV_PATH ]; then
        echo "same environment name already exists!"
        return $ERROR_STATUS
    else
        (mkdir $ENV_PATH && cd $ENV_PATH && pipenv install)
    fi
    elif [ $1 = "install" ]; then
    if [ $# -eq 3 ]; then
        if [ -d $ENV_PATH ]; then
        (cd $ENV_PATH && pipenv install $3)
        else
        echo "env '$2' does not exists!"
        return $ERROR_STATUS
        fi
    else
        echo "Usage: gpipenv install env_name package_name"
        return $ERROR_STATUS
    fi
    elif [ $1 = "activate" ]; then
    if [ -d $ENV_PATH ]; then
        (cd $ENV_PATH && pipenv shell)
    else
        echo "the environment does not exists!"
        return $ERROR_STATUS
    fi
    else
    echo "illegal command!"
    return $ERROR_STATUS
    fi
}

condaでいうところのconda create, conda installおよびconda activateに相当する処理を行う関数gpipenvを作成した。 conda deactivateに相当する処理も書きたかったが、面倒なので煩雑になりそうだったのでCtrl-Dで行うことに。

余談
gpipenv shellを行うとディレクトリ移動してしまうのが難点。 なんとかならないものか。

補完関数の作成

これで終わりでもいいのだが、コマンドの種類、構築した仮想環境の名前を忘れると、いちいち.zshrcや仮想環境ディレクトリを確認しなければならない。 それは少し不便なのでzshの補完関数を作成する。

zshの補完関数は_関数名という名前で作成する。 補完関数は先程準備した~/.zsh-functionに配置する。

今回は自作関数gpipenvの補完関数ファイルを_gpipenvとして作成する。

#compdef gpipenv

_gpipenv() {
    _arguments '1: :->command' '2: :->env'

    case "$state" in
    command)
        _values '' \
            'create[Create new virtual environment.]' \
            'install[Install new package to specified virtual environment.]' \
            'activate[Spawns a shell within the virtualenv.]'
        ;;
    env)
        _path_files -/ -W $PIPENV_ENV_ROOT
        ;;
    esac
}

1行目の#compdef gpipenvgpipenvに関する補完関数であることを明示するものなので必須である(多分)。

これで補完を行えば以下のように補完される。

$ gpipenv [ここでTAB]

activate  -- Spawns a shell within the virtualenv.
create    -- Create new virtual environment.
install   -- Install new package to specified virtual environment.
$ gpipenv activate [ここでTAB]

base/ hoge/ fuga/