$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

Emacsでvirtualenvに入れたライブラリも考慮したPythonの補完環境を作る

 新言語を使うときは、その言語の補完ができるかどうかで学習効率が変わってくるので、ひとまずPythonの補完環境を作った。基本Pythonではvirtualenvを使うのが一般的なようなので、環境ごとに入れたライブラリも考慮して補完できるようにした。

 色々調べたところ、次の三つを使うのが良さそうだった。

  • python-mode
  • jedi
  • auto-virtualenvwrapper

今回の設定で以下のように補完が出来るようになった。

f:id:shiba_yu36:20170402145819g:plain

python-mode

 とりあえず編集モードを入れる。M-x package-install RET python-mode RETしたあと、以下の設定を入れる。

(require 'python-mode)
(setq auto-mode-alist (cons '("\\.py\\'" . python-mode) auto-mode-alist))

jedi

 Pythonの補完なら、Jedi というのが良さそうに見えた。Emacsでの入れ方は http://tkf.github.io/emacs-jedi/latest/ に書かれていたので、このページに従ってインストールした。

 まずvirtualenvを自分がメインで使っているPython環境に入れる。

$ pip install virtualenv

 Emacsにjedi.elを入れる。

M-x package-install RET jedi RET

 以下の設定を追加する。

(require 'jedi)
(add-hook 'python-mode-hook 'jedi:setup)
(setq jedi:complete-on-dot t)

 最後にM-x jedi:install-serverして完了。

auto-virtualenvwrapper

 以上でPythonの補完が出来るようになった。しかし今のままだとグローバルなPython環境のみ見て補完してくれるだけだった。Pythonではプロジェクト単位でvirtualenvを用いるのが一般的なようなので、virtualenvの環境にインストールしたライブラリも見て補完できるようにしておきたい。

 それを実現するには virtualenvwrapper.el というのを使えば良いみたい。さらに auto-virtualenvwrapper.el というのを使うと、プロジェクトのファイルを開いた時に自動でvirtualenvの環境を切り替えてくれるようだった。

 まずはvirtualenvwrapper.elとauto-virtualenvwrapper.elをインストール

M-x package-install RET virtualenvwrapper RET
M-x package-install RET auto-virtualenvwrapper RET

 以下の設定を追加すると、自動でvirtualenvの環境を切り替えてくれるようになる。

(require 'virtualenvwrapper)
(require 'auto-virtualenvwrapper)
(add-hook 'python-mode-hook #'auto-virtualenvwrapper-activate)

まとめ

 今回の設定で、virtualenvにいれたライブラリも考慮したPythonの補完環境を作れた。ここにたどり着くまでに結構時間がかかってしまったけど、補完がうまくいくようになって良かった。

zsh-autoenvを使って、virtualenvの自動activate/deactivateを実現する

 pyenv + venvでPython3環境を構築する - $shibayu36->blog; の記事で、特定のPythonプロジェクト用のvirtualenv環境を導入することが出来ました。しかし、このプロジェクトに入るたびにsource venv/bin/activateし、逆に抜ける時にdeactivateするのは

  • 面倒
  • どう考えても実行を忘れる

という問題があります。

 そこでzsh-autoenvというzshプラグインを使って、自動でactivateとdeactivateを出来るようにしたのでメモしておきます。

zplugを導入する

今回の本題から外れますが、zshプラグインの管理ツールをこれまで入れてこなかったので、この機会にzplugを導入しました。

$ curl -sL --proto-redir -all,https https://zplug.sh/installer | zsh

でインストールし、下記設定をするだけの簡単導入でした。

# ---------------- setting for zplug --------------------------
source ~/.zplug/init.zsh

# zsh-autoenvのインストール
zplug "Tarrasch/zsh-autoenv"

# Install plugins if there are plugins that have not been installed
if ! zplug check --verbose; then
    printf "Install? [y/N]: "
    if read -q; then
        echo; zplug install
    fi
fi

# プラグインを読み込み、コマンドにパスを通す
zplug load --verbose

zsh-autoenvを使って自動でactivateとdeactivateを出来るように

 zsh-autoenv とは、

  • ディレクトリに.autoenv.zshを置いておくと、そのディレクトリ以下に入った時に自動でそのファイルを実行してくれる
  • ディレクトリに.autoenv_leave.zshを置いておくと、そのディレクトリから抜ける時に自動でそのファイルを実行してくれる

というものです。これを使えば

が実現できますね。

インストール

 先程zplugを導入したので、.zshrcに以下を追加するだけです。

zplug "Tarrasch/zsh-autoenv"

venv環境を作る

 以下のコマンドでvenv環境を作ります。

$ mkdir python-playground
$ cd python-playground
$ python -m venv venv

これでpython-playground/venvディレクトリ下にpythonの環境が作られました。

zsh-autoenvの設定を行う

 python-playgroundディレクトリにて以下のコマンドを実行し、.autoenv.zsh.autoenv_leave.zshを用意します。

$ echo 'source venv/bin/activate' > .autoenv.zsh
$ echo 'deactivate' > .autoenv_leave.zsh

 これでディレクトリに入ったらactivateし、ディレクトリから出たらdeactivateされるはずです。

確認する

 ではこのディレクトリに入ってみます。

$ cd python-playground
Attempting to load unauthorized env file!
-rw-r--r--  1 shibayu36  staff  25 Apr  1 21:20 /Users/shibayu36/development/src/github.com/shibayu36/python-playground/.autoenv.zsh

**********************************************

source venv/bin/activate

**********************************************

Would you like to authorize it? (type 'yes') yes
$ which python
/Users/shibayu36/development/src/github.com/shibayu36/python-playground/venv/bin/python

 初回はファイルを実行してよいか聞かれるのでyesと答えます。which pythonすると、ディレクトリ配下のpythonを示すようになっているので、cdでディレクトリに入っただけでvirtualenvのactivateがされるようになりました。


 逆にディレクトリを出てみます。

$ cd ..
Attempting to load unauthorized env file!
-rw-r--r--  1 shibayu36  staff  11 Apr  1 21:20 /Users/shibayu36/development/src/github.com/shibayu36/python-playground/.autoenv_leave.zsh

**********************************************

deactivate

**********************************************

Would you like to authorize it? (type 'yes') yes
$ which python
/Users/shibayu36/.anyenv/envs/pyenv/shims/python

 こちらも初回は確認が出るのでyesと答えます。そうするとディレクトリを出るだけでpyenvのpythonを指し示すようになり、自動でdeactivateされるようになりました。

まとめ

 今回はzsh-autoenvを使って、ディレクトリに入った時に自動でvirtualenvをactivateし、ディレクトリから出た時に自動でdeactivateするということをしてみました。zsh-autoenvは他にもいろいろと使えそうで良いですね。

Pythonのvenvのプロンプト表示をカスタマイズする

pyenv + venvでPython3環境を構築する - $shibayu36->blog;の記事で、Python3でvenvを使った環境を構築することができた。しかしvenvでsource bin/activateすると、自分の設定したプロンプトの左側に(venvの環境名)という文字列が勝手に挟み込まれてしまって、あまり好みではなかった。
f:id:shiba_yu36:20170401143732p:plain

それを以下のように、venv環境の中にいたらpy:(pythonのversion):(venvの環境名)という表示にしたかった。
f:id:shiba_yu36:20170401143900p:plain

のでやってみた。

プロンプトの左側の環境名表示を消す

まずプロンプトの左側の(venvの環境名)を消す。こちら を参考にして、VIRTUAL_ENV_DISABLE_PROMPTという環境変数を設定しておけば良いらしい。

# virtualenvでpromptを変更しない
export VIRTUAL_ENV_DISABLE_PROMPT=1

環境名をプロンプトの好きな場所に表示する

bin/activateのコードを読んでみると、VIRTUAL_ENVという環境変数にそのディレクトリのパスを入れているということが分かる。また、元々プロンプトの左側に出ていた内容も、VIRTUAL_ENVのbasenameを表示していただけだった。

これらを参考にし、またpyenv version-nameを利用すれば、py:(pythonのversion):(venvの環境名)という文字列を作ることが出来る。

PYTHON_VERSION_STRING="py:"$(pyenv version-name)
PYTHON_VIRTUAL_ENV_STRING=""
if [ -n "$VIRTUAL_ENV" ]; then
    PYTHON_VIRTUAL_ENV_STRING=":`basename \"$VIRTUAL_ENV\"`"
fi

あとはこの変数を使ってPROMPTを設定すればOK。僕の場合は他にもperlのversionとかも出していたので、以下のようになった。

### ------------------ ###
# prompt config
precmd () {
    PERL_VERSION_STRING="pl:"$(plenv version-name)
    RUBY_VERSION_STRING="rb:"$(rbenv version-name)
    NODE_VERSION_STRING="nd:"$(ndenv version-name)
    PYTHON_VERSION_STRING="py:"$(pyenv version-name)
    PYTHON_VIRTUAL_ENV_STRING=""
    if [ -n "$VIRTUAL_ENV" ]; then
        PYTHON_VIRTUAL_ENV_STRING=":`basename \"$VIRTUAL_ENV\"`"
    fi
}

function setprompt () {
      PROMPT='%F{yellow}%<...<%~%<< %F{blue}${PERL_VERSION_STRING} ${RUBY_VERSION_STRING} ${NODE_VERSION_STRING} ${PYTHON_VERSION_STRING}${PYTHON_VIRTUAL_ENV_STRING}
%F{blue}%D{%H:%M:%S} %F{green}${USER}%F{white}@%F{green}%m%F{white}%(!.#.$) '
}

setprompt
unfunction setprompt

https://github.com/shibayu36/config-file/blob/master/.zsh/appearance.zsh#L145

まとめ

venvが自動でプロンプトに表示する内容があまりかっこよくなかったので、自分でプロンプト表示をカスタマイズしてみた。以上二つをやれば、最初にやりたかったことができた。