virtualenvwrapper.el での環境変数設定を修正
Emacs でのソースコード編集時に Language Server Protocol 経由での補完候補列挙やエラー/警告表示を行うために、 以下のツール群をインストールしてみました。
- pyls: Language Server Protocol で Jedi と連携するためのフロントエンド
- Jedi: Python での補完候補列挙やエラー/警告表示を行うツール/pyls のバックエンド
- lsp-mode: Language Server と連携するための Emacs パッケージ
上記構成では、Emacs 経由で起動された pyls/Jedi プロセスと lsp-mode を介して Language Server Protocol で連携することになります。
素の環境で開発する分にはこれでも良いのですが、 プロジェクトや作業毎に個別の virtualenv 環境を使用するようなケースでは、 以下のいずれかの対応が必要になります。
- 対象 virtualenv を activate した上で Emacs を起動
- Emacs 上で
VIRTUAL_ENV
環境変数 (+ 相応のPATH
) を設定した上で pyls/Jedi プロセスを起動
前者の対応方式は最大で以下の3手順を必要とするため、利便性が大幅に削がれますし、アプリケーションランチャーの使用が制限されてしまいます。
- terminal を起動
- terminal 上で virtualenv を activate
- emacs を起動
そこで、Emacs に virtualenvwrapper.el を導入することで、後者の対応方式を採用することにしました。
しかし virtualenvwrapper.el を併用した場合、
一定時間以上使い続けていると
OSError(24, ’Too many open files’)
によって pyls/Jedi プロセスが終了してしまうケースが多々発生します
(POSIX のエラーシンボル的には EMFILE
)。
調べてみると以下のような経緯で pyls/Jedi が終了していました。
- Emacs から lsp-mode 経由で Language Server Protocol による要求の発行
- Jedi は起動済み外部 Python プロセスの
sys.prefix
とVIRTUAL_ENV
を比較 - 一致している場合は起動済み外部 Python プロセスを再利用
- 不一致の場合は外部 Python プロセスを新規作成
- 既存の外部プロセス連携のための FIFO (pipe) が閉じられないまま放置
- FIFO 放置により同時 open 可能ファイル数を消費
- Language Server Protocol による要求発行の都度、上記手順が繰り返し実施
- エンドユーザプロセスの同時 open 可能ファイル数上限超過
- pyls/Jedi で新規の外部プロセスの生成ができなくなる (=
EMFILE
) - 要求に応答できないため pyls/Jedi が終了
Python プロセスの sys.prefix
と VIRTUAL_ENV
の不一致の要因は、
通常の activate と virtualenvwrapper.el
での設定値の違いに起因しています。
- Python プロセスの
sys.prefix
は virtualenv 有効化の有無に関わりなく末尾に "/" を 含まない - virtualenv の通常有効時の
VIRTUAL_ENV
は末尾 "/" を 含まない - virtualenvwrapper.el が
VIRTUAL_ENV
に設定する値は末尾に "/" が 含まれる
外部 Python プロセスとの連携用 FIFO を閉じずに放置する Jedi の実装は如何なものかと思いますが (笑)、 プロセス連携の際の環境変数値のフォーマットは API 仕様的な側面がありますから、 virtualenvwrapper.el 側でも修正を実施するのが妥当だと思われます。
そこで VIRTUAL_ENV
末尾に "/" を含めないようにする修正を作成しました。