背景
上記リンクの記事を参考にVim(Neovim)のpluginを作っています。
Pythonファイルが大きくなり分割しようとしたところ、少しつまずいたので解決法を共有します。
この記事では、例としてrequestsモジュールを用いてWebページのタイトルを表示するプラグインを作ってみます。
ディレクトリ構成とファイルの中身
sample-vim-plugin
plugin/
sample_vim_plugin.vim
src/
sample_vim_plugin.py
requests_caller.py
scriptencoding utf-8if exists('g:loaded_sample_vim_plugin')finishendifletg:loaded_sample_vim_plugin=1lets:save_cpo=&cpo
set cpo&vim
py3file <sfile>:h:h/src/sample_vim_plugin.pyfunction! sample_vim_plugin#print_title(url)py3 sample_vim_plugin_print_title(vim.eval('a:url'))endfunctionlet&cpo =s:save_cpo
unlet s:save_cpo
importvimimportrequests_callerdefsample_vim_plugin_print_title(url):print(requests_caller.get_title(url))
importrequestsfrombs4importBeautifulSoupdefget_title(url):response=requests.get(url)soup=BeautifulSoup(response.text,'lxml')returnsoup.title.text
私はdeinでプラグインを管理しているので、tomlファイルに上記のプラグインを追加しneovimを起動するとModuleNotFoundError: No module named 'requests_caller'
と言われます。
このモジュール見つからない問題を解決したいと思います。
「Python における 'runtimepath' の処理」に
Python では、'runtimepath' のパスのリストを使う代わりに、vim.VIM_SPECIAL_PATH
という特別なディレクトリが使われます。このディレクトリが sys.path 内で使われる
とき、そして vim.path_hooks が sys.path_hooks 内で使われるとき、'runtimepath'
の各パス {rtp} に対して {rtp}/python2 (or python3) と {rtp}/pythonx (両バー
ジョンで読み込まれる) のモジュールがロードされます。
とあります。
よって、二つの方法が考えられます。
解決法1: ディレクトリの名前を変更する
runtimepathの直下にpython2,python3,pythonxのディレクトリがあればロードされるとのことなので、srcディレクトリをpython3にリネームします。
当然読み込む部分を変える必要があるので、下記のように変更します
- py3file <sfile>:h:h/src/sample_vim_plugin.py
+ py3file <sfile>:h:h/python3/sample_vim_plugin.py
解決法2: sys.pathに追加する
ディレクトリの名前を変えたくない場合は、直接sys.pathに追加します。
+ let s:sample_vim_plugin_root_dir = expand('<sfile>:p:h:h')
py3file <sfile>:h:h/src/sample_vim_plugin.py
import vim
+ import sys
+ import os
+ plugin_python_dir = os.path.join(vim.eval('s:sample_vim_plugin_root_dir'), 'src')
+ sys.path.append(plugin_python_dir)
import requests_caller
まとめ
- python2, python3, pythonxディレクトリにPythonファイルを置く
- sys.pathにPythonファイルをおいたディレクトリを追加する
という二つの方法でプラグインが動くようになります。
有名どころで言うと、davidhalter/jedi-vimでは解決法1(pythonx)を使っているみたいです。
ソースコードをチラ見しただけですが、Shougo/denite.nvimやShougo/deoplete.nvimでは解決法2を使っているように見えます。