neovimのpython環境についてメモ

vim-lspによる補完がうまく効かない状態になっていた。補完が効かない問題自体はvenvの環境そのものがおかしくなっていたようで新しく作り直したら問題なかったのだが、その際に調べたことをせっかくなのでメモしておく。

手元の環境はこんな感じ

  • pyenvで入れたpython3.7.7
  • プロジェクト毎にvenvで仮想環境作成
  • neovim, pynvimはglobal環境にpipでインストール済み
  • vim-lsp, vim-lsp-settingsを利用

neovimのpython環境

neovimでpython3を使う場合は以下2つのpackageが入ったpython3をproviderとして設定する必要がある。

  • neovim
  • pynvim

g:python3_host_prog にpathを設定すればそのpython3が使われることになるが、設定しなかった場合はシステムのものやpyenvのものを探しに行く。私の環境ではpyenvを使っており、pyenv localで設定されたversionのグローバル環境が参照されていた。

この部分はneovim専用の仮想環境を用意してそれを使うように設定しておくのがよいみたいだが、私はそこまで頻繁にversionの変更をしてこなかったのでグローバル環境にneovim用の必要なpackageだけ入れて使っていた(せっかくなので今回この辺は仮想環境を見るように直しておこうと思う)

ここでの注意点としては、venvの環境をシェル上でactivateしてあったとしてもそちらの仮想環境は使われないこと。

activateしたvenv側にだけpynvimなどを入れ、グローバル環境には何も入れない状態だとcheckhealthで以下のようにエラーになる。

## Python 3 provider (optional)
  - INFO: pyenv: Path: /usr/local/Cellar/pyenv/2.0.7/libexec/pyenv
  - INFO: pyenv: $PYENV_ROOT is not set. Infer from `pyenv root`.
  - INFO: pyenv: Root: /Users/uj/.pyenv
  - INFO: `g:python3_host_prog` is not set.  Searching for python3 in the environment.
  - INFO: Executable: /Users/uj/.pyenv/versions/3.7.7/bin/python3
  - ERROR: Command error (job=18, exit code 1): `'/Users/uj/.pyenv/versions/3.7.7/bin/python3' -c 'import sys; sys.path = list(filter(lambda x: x != "", sys.path)); import
  neovim; print(neovim.__file__)'` (in '/Users/uj/test')
    stderr: Traceback (most recent call last):  File "<string>", line 1, in <module>ModuleNotFoundError: No module named 'neovim'
  - INFO: Python version: 3.7.7
  - INFO: pynvim version: unable to load neovim Python module
  - ERROR: pynvim is not installed.
    Error: unable to load neovim Python module
    - ADVICE:
      - Run in shell: /Users/uj/.pyenv/versions/3.7.7/bin/python3 -m pip install pynvim

## Python virtualenv
  - INFO: $VIRTUAL_ENV is set to: /Users/uj/test/venv
  - INFO: Python version: 3.7.7
  - OK: $VIRTUAL_ENV provides :!python.

ちなみに上記はneovim-0.5.0の出力。0.4.4だと仮想環境は見つかったがactivateされていない、みたいなwarningが出る状態だったため少し混乱した。

pylsのpython環境

vim-lsp-settingsを利用しているのでlsp serverは以下にインストールされている。

~/.local/share/vim-lsp-settings/servers/pyls-al

この下にvenvで専用の仮想環境が作られておりその環境でlsp serverが起動する。これだけだと自分のプロジェクトの仮想環境が読まれない感じだが、内部で使っているjediが VIRTUAL_ENV という環境変数に設定があればその環境のsite-packagesも読むようになっている模様。
https://github.com/palantir/python-language-server/issues/660#issuecomment-553284845
リンクが貼られているjediのコードは少し古いが、最新を確認しても同様の処理だった。

pyvenvを利用する場合の仮想環境設定用pluginであるvim-virtualenvでもactivateした上でVIRTUAL_ENVの値を設定してるのでそんな感じっぽい。
https://github.com/jmcantrell/vim-virtualenv/blob/3841e26/autoload/virtualenv.vim#L50-L55

venvの場合、VIRTUAL_ENVへの値設定は venv/bin/activate にて行われているためactivateしてあれば目的の環境のpathが設定されている。
https://github.com/python/cpython/blob/bb3e0c240bc60fe08d332ff5955d54197f79751c/Lib/venv/scripts/common/activate#L41-L42

pylsが起動するのはneovim起動時にpluginが読み込まれたときなので、activateしたシェル上でneovimを起動すれば問題ない。

ちなみにneovim上での環境変数の設定は以下で確認できる。

:py3 import os
:py3 print(os.environ)

想定どおりプロジェクト用仮想環境のpackageが読まれているかは、プロジェクト用のvenv側にだけ特定のpackageを入れて LspDefinition で定義へジャンプできるか否かで確認した。

まとめ

当初vim-virtualenvなど入れて参照先を調整したりする必要あるのかと思ったが、特別なことは必要なく以下の形で問題なかった。

  • python3のグローバル環境にneovim, pynvimを入れる
    • もしくはneovim専用の仮想環境を用意して g:python3_host_prog で設定する
  • シェル上で venv/bin/activate してからneovimを起動する

pylsのpython環境はvenvで作成されている状態であるため、メインのpythonのversionを上げた際にpyls側の環境と乖離してエラーなどの表示に食い違いが出てくるかもしれないことは頭の片隅に置いておこうと思う。