• 作成:

Emacsにelpyをpipenv環境でも動くように導入する

動機

他の人がPythonで書いたコードに継ぎ足しで書くタスクが発生したので、これを機に今まで雑にpython-modeとpython-language-serverとautopep8だけで雑に書いていた環境をちゃんと整備したかった。

elpy vs lsp

EmacsでのPython開発環境と言えば jorgenschaefer/elpy: Emacs Python Development Environment が有名です。

しかし今言語環境構築するならLSPが前提みたいな所がありますよね。

Languages - LSP Mode - LSP support for Emacs を見てもlsp-modeが公式サポートしている言語サーバはいくつかあります。

今使うならば LSP Pyright でしょうか。

しかしelpyのREPL(Jupyter Consoleも含めた)のインテグレーションに惹かれたため、 elpyを使うことにしました。

新規に環境が立ち上がってくる時にLSPベースで構築したら大概のクライアントに対応してて便利なのは確かですが、既にちゃんと動く環境があるのにそこまでLSPを重視する必要も無いという判断です。

pipenv

初期状態のelpyには1つ問題があって、 pipenvで入れたライブラリを認識してくれません。

REPLでpipenvで入れたライブラリをimport出来ないため、これではせっかくのREPL連携も台無しですね。

Support for pipenv · Issue #1217 · jorgenschaefer/elpy を見ていい感じになんとかしました。

この場合flake8だけはelpyの仮想環境の管理外なのでpipenvで[dev-packages]に入れてあげましょう。

現在の設定

Jupyter Notebookのファイルを開くためについでに millejoh/emacs-ipython-notebook: Jupyter notebook client in Emacs も設定しました。

(leaf python
  :custom (python-indent-guess-indent-offset-verbose . nil)
  :config
  (leaf elpy
    :ensure t
    :defvar elpy-modules python-shell-completion-native-disabled-interpreters
    :defun elpy-enable
    :after python
    :custom
    (python-shell-interpreter . "jupyter")
    (python-shell-interpreter-args . "console --simple-prompt")
    (python-shell-prompt-detect-failure-warning . nil)
    :init (elpy-enable)
    :hook (elpy-mode-hook . (lambda () (add-hook 'before-save-hook 'elpy-format-code nil t)))
    :config
    (setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
    (add-to-list 'python-shell-completion-native-disabled-interpreters "jupyter"))
  (leaf pipenv
    :ensure t
    :after python
    :require t
    :defvar python-shell-interpreter python-shell-interpreter-args python-shell-virtualenv-root pyvenv-activate
    :defun pipenv--force-wait pipenv-deactivate pipenv-projectile-after-switch-extended pipenv-venv
    :custom
    (pipenv-projectile-after-switch-function . #'pipenv-projectile-after-switch-extended)
    :init
    (defun pipenv-auto-activate ()
      (pipenv-deactivate)
      (pipenv--force-wait (pipenv-venv))
      (when python-shell-virtualenv-root
        (setq-local pyvenv-activate (directory-file-name python-shell-virtualenv-root))
        (setq-local python-shell-interpreter "pipenv")
        (setq-local python-shell-interpreter-args "run jupyter console --simple-prompt")))
    :hook (elpy-mode-hook . pipenv-auto-activate)
    :config
    (pyvenv-tracking-mode)
    (add-to-list 'python-shell-completion-native-disabled-interpreters "pipenv"))
  (leaf ein :ensure t))