EmacsでPythonを書く設定 2021

はじめに

PythonまわりのEmacsの設定を整理したということ。Company-modeの設定は言語共通の部分が多く長くなるので省略した。Language serverの紹介がメイン。

※最新の設定は2022の記事に

tam5917.hatenablog.com

Language server

Emacsからlanguage serverを使うためにeglotを入れる。MELPAからインストール可能。さらにPython用のpython-language-serverをインストールしておく。ターミナルから以下を実行する。

pip3 install python-language-server

関連パッケージをまとめて入れる場合は以下がラク

pip install 'python-language-server[all]'

Flymake

flycheckはOFFにして、flymakeを使うようにした。flymake-diagnostic-at-pointはなかなか便利なのでおすすめ。MELPAからインストール可能。

python-black

Emacsからblackを呼び出せるようにするため、python-blackを導入する。
https://github.com/wbolster/emacs-python-black

バッファ保存時に「常に」blackをかけたいときは、以下のように設定可能である。

(declare-function python-black-on-save-mode "python-black")
(add-hook 'python-mode-hook
          #'(lambda ()
              (python-black-on-save-mode)))

python-black-on-save-modeを持ち出さない場合は、以下でもOK。

(add-hook 'python-mode-hook
          #'(lambda ()
              (add-hook 'before-save-hook
                        'python-black-buffer nil t)))

前者のminor-modeを使うとlighterの文字列が増えてゴチャゴチャするので、個人的には後者が好み。
projectがblackによるフォーマットを必要とするかに応じて振る舞いを変えたい場合はpython-black-on-save-mode-enable-dwimを使う。このようにユーザに選択の余地が残されているのがよい。

設定

;; Python
(setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist))
(setq interpreter-mode-alist (cons '("python" . python-mode)
                                   interpreter-mode-alist))

;; pip3 install python-language-server
;; https://github.com/palantir/python-language-server
;;
;; 以下は追加で(お好みで)インストール
;; pip install 'python-language-server[all]' としてしまうのが早い
;; 
;; pip3 install rope ; completions and renaming
;; pip3 install pyflakes ; linter to detect various errors
;; pip3 install mccabe ; linter for complexity checking
;; pip3 install pycodestyle ; linter for style checking
;; pip3 install pydocstyle ; linter for docstring style checking
;; pip3 install pyls-mypy ; type checker (heavy)
;; pip3 install pyls-isort ; import sort code formatting
;; pip3 install pyls-black ; code formatting using Black

(require 'eglot)
(add-hook 'python-mode-hook 'eglot-ensure)

;; server として起動
;; (add-to-list 'eglot-server-programs
;;              `(python-mode . ("pyls" "-v" "--tcp" "--host"
;;                               "localhost" "--port" :autoport)))

;; 保存時に自動整形 (black)
;; python-blackをmelpaからインストールしておく
(add-hook 'python-mode-hook
          #'(lambda ()
              (add-hook 'before-save-hook
                        'python-black-buffer nil t)))

;; 以下の設定でもOKだが、minor-modeの分、lighterが増えてごちゃごちゃする
;; (declare-function python-black-on-save-mode "python-black")
;; (add-hook 'python-mode-hook
;;           #'(lambda ()
;;               (python-black-on-save-mode)))

;; 保存時にインポート順を自動修正
;; py-isortをmelpaからインストールしておく
(add-hook 'python-mode-hook #'(lambda ()
                                (add-hook 'before-save-hook
                                          'py-isort-buffer nil t)))

;; point位置にメッセージを表示する。eldocと干渉しないのが利点
(with-eval-after-load "flymake"
  (require 'flymake-diagnostic-at-point)
  (add-hook 'flymake-mode-hook #'flymake-diagnostic-at-point-mode))

その他

ほか、以下は好みで設定した。エコーエリアが複数行になるのを防ぐ効果がある。

(custom-set-variables
  '(eldoc-echo-area-use-multiline-p nil))

またsmart-jumpやivy-xrefも便利なので使っている。

(require 'smart-jump)
(smart-jump-setup-default-registers)  ;; pythonはデフォルトで有効になる
;; M-. (smart-jump-go; xref-find-definitions)
;; M-, (smart-jump-back; xref-pop-marker-stack)
;; M-? (smart-jump-references; xref-find-references)

(require 'ivy-xref)
(setq xref-show-xrefs-function #'ivy-xref-show-xrefs)

もし、blackユーザならばpycodestyleの設定をしておくと良い。

[pycodestyle]
ignore = E203, W503, W504
max-line-length = 88

おわりに

eglotとpython-language-serverの組み合わせがなかなか快適だったので紹介した。lsp-modeを設定するのも悪くはないし、elpyとflycheckの組み合わせで書くのも悪くはないので(特に軽快性が優れる)、このあたりは好みだろう。