MacVimでPythonの開発環境を構築する (2016/夏)

どうも、お久しぶりです。
最近暑くなってきましたね、ちょっと早いですがタイトルは夏にしちゃいました。

MacVimでPython/Python3の開発環境を構築したいと思いましたが、過去に同環境を構築できた方は見当たりませんでした。
私もうまくいかず諦めかけていましたが、MacVimやMacVim-KaoriYaのメンテナーであるsplhack氏が構築ガイドを公開してくださったので試してみたいと思います。

この記事は現時点での情報整理のために書いています。
少しだけ解説を入れていますが分かっている人向けに書いてある部分もありますので、ご不明点などありましたらお問い合わせください。
また、ファイルの編集を行う場合は実際の変更も載せるようにしますので、ご参考にしていただければと思います。

目標

  • MacVimでPython/Python3の開発環境を構築する
  • Pythonのバージョン管理にpyenvを使用する
  • 仮想環境管理にpyenv-virtualenvを使用する
  • 仮想環境にインストールしたパッケージをjedi-vimで補完する

問題点

  • Anacondaを使用することができない (--enable-sharedにできない?そもそもビルドしていないような...)
  • 環境変数に依存しているため、環境の切り替えがうまくいかない部分がある

環境

  • OS: OS X v10.9 Mavericks
  • Vim: 7.4.1825
  • pyenv: 20160509
  • pyenv-virtualenv: 20160315

手順1 - 各種パッケージのインストール

パッケージのインストールにHomebrewを使用します。

MacVim

--with-properly-linked-python2-python3オプションが重要です。

$ brew install macvim-dev/macvim/macvim --HEAD --with-properly-linked-python2-python3

pyenv

基本的にはREADME通りですが、存在チェックを入れています。

$ brew install pyenv
$ echo 'export PYENV_ROOT=~/.pyenv' >>~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT"/bin:"$PATH"' >>~/.bash_profile
$ echo 'if builtin type pyenv >/dev/null 2>&1; then eval "$(pyenv init -)"; fi' >>~/.bash_profile

参考: Add pyenv settings · ryunix/dotfiles@0d98667

pyenv-virtualenv

pyenvと同様に存在チェックを入れています。
また、変更を反映させるためにシェルの再起動を入れています。

$ brew install pyenv-virtualenv
$ echo 'if builtin type pyenv-virtualenv >/dev/null 2>&1; then eval "$(pyenv virtualenv-init -)"; fi' >>~/.bash_profile

$ exec $SHELL -l

参考: Add pyenv-virtualenv settings · ryunix/dotfiles@5796a05

手順2 - Pythonのインストール

pyenvを使用し、Pythonをインストールします。
--enable-sharedオプションを指定する必要があります。
また、関連するオプションの指定も必要です。

Python 2.7.11

$ PYTHON_CONFIGURE_OPTS="--enable-shared" \
    LDSHARED="clang -bundle" \
    LDCXXSHARED="clang++ -bundle" \
    BLDSHARED="clang -bundle -lpython2.7" \
    pyenv install 2.7.11

$ otool -L $PYENV_ROOT/versions/2.7.11/lib/python2.7/lib-dynload/_ctypes.so
# -> 実行結果に libpython2.7.dylib が含まれていればOK

Python 3.5.1

$ PYTHON_CONFIGURE_OPTS="--enable-shared" \
    LDSHARED="clang -bundle" \
    LDCXXSHARED="clang++ -bundle" \
    BLDSHARED="clang -bundle -lpython3.5m" \
    pyenv install 3.5.1

$ otool -L $PYENV_ROOT/versions/3.5.1/lib/python3.5/lib-dynload/_ctypes.cpython-35m-darwin.so
# -> 実行結果に libpython3.5m.dylib が含まれていればOK

手順3 - Vimの設定

pythondllpythonthreedllオプションを指定する必要があります。
さらに、$PYTHONHOMEを指定した後に対応するバージョンのコマンドを実行する必要があります。
バージョンによって値が変わるので、変数にしておきました。

let s:python2home = $PYENV_ROOT . '/versions/2.7.11'
let s:python2dll  = $PYENV_ROOT . '/versions/2.7.11/lib/libpython2.7.dylib'
let s:python3home = $PYENV_ROOT . '/versions/3.5.1'
let s:python3dll  = $PYENV_ROOT . '/versions/3.5.1/lib/libpython3.5m.dylib'

let &pythondll = s:python2dll
let $PYTHONHOME = s:python2home
execute 'python import sys'

let &pythonthreedll = s:python3dll
let $PYTHONHOME = s:python3home
execute 'python3 import sys'

参考: Add +Python/+Python3 settings · ryunix/dotfiles@88721cb

手順4 - 各種プラグインのインストール

プラグインのインストールにDein.vimを使用します。
NeoBundleでもよいですが、その他のプラグインマネージャはダメかもしれません。 (プラグインの読み込み順序を操作可能なら大丈夫だと思います)

vim-pyenv

pyenv環境でいい感じに切り替えを行ってくれます。
しかし、この環境では真価を発揮することができません... (理由は後述)

call dein#add('lambdalisue/vim-pyenv', {
      \   'on_ft' : [
      \     'python',
      \   ],
      \ })

参考: Add lambdalisue/vim-pyenv · ryunix/dotfiles@570ca37

jedi-vim

on_sourceオプションが重要です。
jedi-vimvim-pyenvより前にロードする必要があります。

call dein#add('davidhalter/jedi-vim', {
      \   'build' : 'git submodule update --init',
      \   'on_ft' : [
      \     'python',
      \   ],
      \   'on_source' : [
      \     'vim-pyenv',
      \   ],
      \ })

参考: Add davidhalter/jedi-vim · ryunix/dotfiles@6592048

使用例

準備が整いましたので、実際にpyenv-virtualenvで仮想環境を作成し、jedi-vimで補完できるか確認していきます。
現在の仮想環境が分かりやすいように、MacVimのステータスバーに仮想環境名を出すようにしています。

注意点があります。
まず、仮想環境の切り替えには$ pyenv activate <name>を使用し、:PyenvActivateは使用しません。
正確な調査を行っていないのですが、$PYTHONHOMEに依存することによって動的な仮想環境の切り替えが行えない場合があります。
仮想環境の切り替えはpyenv-virtualenvに任せて、vim-pyenvには初回時のみ働いてもらいます。

Python 3.5.1

# 仮想環境1を作成します。
$ pyenv virtualenv 3.5.1 py35_1

# 仮想環境1に切り替えます。
$ pyenv activate py35_1

# 仮想環境1にdateutilsをインストールします。
$ pip install dateutils

# Vimを起動します。
$ vim py35_1.py

インストールしたdateutilsの補完が効いていますね。
f:id:ryunix:20160530055713p:plain

# 仮想環境2を作成します。
$ pyenv virtualenv 3.5.1 py35_2

# 仮想環境2に切り替えます。
$ pyenv activate py35_2

# Vimを起動します。
$ vim py35_2.py

dateutilsをインストールしていないので補完対象がありません。
f:id:ryunix:20160530055756p:plain

Python 2.7.11

# 仮想環境1を作成します。
$ pyenv virtualenv 2.7.11 py27_1

# 仮想環境1に切り替えます。
$ pyenv activate py27_1

# 仮想環境1にdateutilsをインストールします。
$ pip install dateutils

# Vimを起動します。
$ vim py27_1.py

インストールしたdateutilsの補完が効いていますね。
f:id:ryunix:20160530055809p:plain

# 仮想環境2を作成します。
$ pyenv virtualenv 2.7.11 py27_2

# 仮想環境2に切り替えます。
$ pyenv activate py27_2

# Vimを起動します。
$ vim py27_2.py

dateutilsをインストールしていないので補完対象がありません。
f:id:ryunix:20160530055815p:plain

問題がないように見えますが、じつはエラーが発生していました。
f:id:ryunix:20160530055803p:plain

では何が問題かというと、vim-quickrunが実行できません。
f:id:ryunix:20160530055820p:plain

この問題ですが、$PYTHONHOMEによるものです。
先の設定ですと、$PYTHONHOMEにはs:python3homeが入っています。
今回は$PYTHONHOMEs:python2homeが入っている必要があります。 (初回だけ必要な環境変数なので本来は消すべきですが、環境変数を消せない問題がある)

回避策は以下の通りです。

  • s:python2homeを後で設定する
let &pythonthreedll = s:python3dll
let $PYTHONHOME = s:python3home
execute 'python3 import sys'

let &pythondll = s:python2dll
let $PYTHONHOME = s:python2home
execute 'python import sys'
  • vim-pyenvのautocmdを使用する (vim-pyenvのREADMEにあるサンプルに足しています)
function! s:jedi_auto_force_py_version() abort
  let major_version = pyenv#python#get_internal_major_version()
  " Add start
  if major_version == 2
    let $PYTHONHOME = s:python2home
  elseif major_version == 3
    let $PYTHONHOME = s:python3home
  endif
  " Add end
  call jedi#force_py_version(major_version)
endfunction
augroup vim-pyenv-custom-augroup
  autocmd! *
  autocmd User vim-pyenv-activate-post   call s:jedi_auto_force_py_version()
  autocmd User vim-pyenv-deactivate-post call s:jedi_auto_force_py_version()
augroup END

vim-quickrunが実行できました。
f:id:ryunix:20160530055825p:plain

さいごに

無事にMacVimでPython/Python3の開発環境を構築できました!

若干の問題はありますが、普通に使用することができると思います。
でも本当はAnacondaを使ってみたかったので、ちょっと残念な気持ちはあります。
Anacondaを使用することができない問題が解消されるともっと便利になると思うのですが...

splhack氏の構築ガイドがなかったら、この開発環境は構築できていませんでした。
また、lambdalisue氏とMiyakoDev氏からは助言をいただきました。
この場をお借りしてお礼を申し上げます、ありがとうございました。

参考