Switch to python-lsp-ruff and overhaul the Python and Eglot sections

This commit is contained in:
Gerard Vermeulen 2022-12-24 16:36:10 +01:00
parent 00a048ef5b
commit eb6cda3025

View File

@ -3824,8 +3824,9 @@ Listing [[lst:configure-writegood-mode]] configures [[https://github.com/bnbeckw
[[https://github.com/joaotavora/eglot#readme][Emacs polyGLOT (Eglot)]] is an Emacs language-server-protocol client that stays [[https://github.com/joaotavora/eglot#readme][Emacs polyGLOT (Eglot)]] is an Emacs language-server-protocol client that stays
out of the way. The following listings contribute to a programming language out of the way. The following listings contribute to a programming language
mode independent [[https://github.com/joaotavora/eglot][Eglot]] configuration: mode independent [[https://github.com/joaotavora/eglot][Eglot]] configuration:
1. Listing [[lst:ensure-eglot-installation]] ensures installation of [[https://github.com/joaotavora/eglot][Eglot]] with 1. Listing [[lst:minimal-eglot-setup][minimal Eglot setup]] ensures installation of [[https://github.com/joaotavora/eglot][Eglot]], shows how to get
minimal configuration. debug information from the [[https://github.com/python-lsp/python-lsp-server][Python LSP server]], and adds key bindings to
=eglot-mode-keymap=.
2. Listing [[lst:help-setup-org-src-mode-for-eglot]] and 2. Listing [[lst:help-setup-org-src-mode-for-eglot]] and
[[lst:setup-python-org-src-mode-for-eglot]] try to prepare any =org-src-mode= [[lst:setup-python-org-src-mode-for-eglot]] try to prepare any =org-src-mode=
buffers for use with [[https://github.com/joaotavora/eglot][Eglot]]. They are a refactored implementation of the post buffers for use with [[https://github.com/joaotavora/eglot][Eglot]]. They are a refactored implementation of the post
@ -3841,15 +3842,20 @@ mode independent [[https://github.com/joaotavora/eglot][Eglot]] configuration:
file [[info:emacs#Directory Variables][.dir-locals.el]] in the root directory of any project using proper file [[info:emacs#Directory Variables][.dir-locals.el]] in the root directory of any project using proper
programming modes). programming modes).
#+caption[Ensure =eglot= installation]: #+caption[Ensure =eglot= installation with minimal configuration]:
#+caption: Ensure =eglot= installation. #+caption: Ensure =eglot= installation with minimal configuration.
#+name: lst:ensure-eglot-installation #+name: lst:minimal-eglot-setup
#+begin_src emacs-lisp #+begin_src emacs-lisp
(when (and (version< emacs-version "28.9.9") (with-eval-after-load 'emacs
(when (version< emacs-version "28.9.9")
(ensure-package-installation 'eglot)) (ensure-package-installation 'eglot))
;; (defvar eglot-server-programs
;; `((python-mode . ("pylsp" "-vvv"))) ;; Replace `nil' with `t' for debugging.
;; "Shadow the definition of `eglot-server-programs' in `eglot'.") (when nil
(defvar eglot-server-programs
`((python-mode . ("pylsp" "-vvv")))
"Shadow the definition of `eglot-server-programs' in `eglot'."))
(with-eval-after-load 'eglot (with-eval-after-load 'eglot
(define-key eglot-mode-map (kbd "C-c n") #'flymake-goto-next-error) (define-key eglot-mode-map (kbd "C-c n") #'flymake-goto-next-error)
(define-key eglot-mode-map (kbd "C-c p") #'flymake-goto-prev-error) (define-key eglot-mode-map (kbd "C-c p") #'flymake-goto-prev-error)
@ -4018,6 +4024,7 @@ Listing [[lst:configure-format-all]]:
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:flymake :CUSTOM_ID: sec:flymake
:END: :END:
Flymake is an universal on-the-fly syntax checker for Emacs. It is a requirement Flymake is an universal on-the-fly syntax checker for Emacs. It is a requirement
of [[https://github.com/joaotavora/eglot][eglot]], but you can use it without [[https://github.com/joaotavora/eglot][eglot]] for instance in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] buffers of [[https://github.com/joaotavora/eglot][eglot]], but you can use it without [[https://github.com/joaotavora/eglot][eglot]] for instance in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] buffers
that do not visit a file. that do not visit a file.
@ -4031,6 +4038,7 @@ that do not visit a file.
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:common-lisp-programming :CUSTOM_ID: sec:common-lisp-programming
:END: :END:
Listing [[lst:configure-sly]] configures the [[info:sly#Top][Sly (info)]] Common Lisp IDE for Emacs Listing [[lst:configure-sly]] configures the [[info:sly#Top][Sly (info)]] Common Lisp IDE for Emacs
for use with [[http://www.sbcl.org/][Steel Bank Common Lisp (sbcl)]]: for use with [[http://www.sbcl.org/][Steel Bank Common Lisp (sbcl)]]:
1. It configures =sly-default-lisp= and =sly-lisp-implementations= as in the 1. It configures =sly-default-lisp= and =sly-lisp-implementations= as in the
@ -4302,45 +4310,62 @@ server, before plunging into the configuration steps:
:CUSTOM_ID: sec:python-mode :CUSTOM_ID: sec:python-mode
:END: :END:
Listing [[lst:configure-python]] configures [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] to use [[https://flake8.pycqa.org/en/latest/][flake8]] as style Listing [[lst:setup-python-mode][setup Python mode]] and [[lst:choose-common-python-interpreter][choose common Python interpreter]] select a common
checker and [[https://ipython.org/][IPython]] as shell interpreter and selects the Python interpreter by Python interpreter in a virtual environment for use in =python-mode= and
means of src_emacs-lisp{(choose-common-python-interpreter)} defined in listing =ob-python= by means of src_emacs-lisp{(choose-common-python-interpreter)}. The
[[lst:choose-common-python-interpreter]]. The [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]] and [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]] packages provide support [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]], [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]], and [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]] packages allow to handle Python virtual
to handle Python virtual environments within Emacs. The [[https://github.com/pyenv/pyenv][pyenv]] package provides environments within Emacs. The [[https://github.com/pyenv/pyenv][pyenv]] package provides support to work with
support to work with [[https://github.com/pyenv/pyenv#readme][pyenv]] (eventually with [[https://github.com/pyenv/pyenv-virtualenv#readme][pyenv-virtualenv]]) to select between [[https://github.com/pyenv/pyenv#readme][pyenv]] (eventually with [[https://github.com/pyenv/pyenv-virtualenv#readme][pyenv-virtualenv]]) to select between different python
different python versions (eventually each with different environments). In the versions (eventually each with different environments). In the end, all those
end, all those packages do is to set =python-shell-virtualenv-root= (in case of packages do is to set =python-shell-virtualenv-root= (in case of [[https://github.com/pyenv/pyenv#readme][pyenv]] and
[[https://github.com/pyenv/pyenv#readme][pyenv]] and [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]]) and tweak the environment variables and restart the relevant [[https://github.com/pythonic-emacs/pythonic#readme][pythonic]]) or tweak the environment variables and restart the relevant Python
Python child processes (in case of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, this setup replaces child processes (in case of [[https://github.com/jorgenschaefer/pyvenv#readme][pyvenv]]). Therefore, I replace those packages with
those packages with listing [[lst:manage-pyenv]] to manage [[https://github.com/pyenv/pyenv#readme][pyenv]] from within Emacs listing [[lst:access-pyenv][access pyenv]] and [[lst:select-python-virtual-environment][select a Python interpreter in a virtual environment]] to
and listing [[lst:setting-python-shell-virtualenv-root]] to set set =python-shell-virtualenv-root= from within Emacs.
=python-shell-virtualenv-root=.
#+caption[Configure =python=]: Listing [[lst:setup-python-mode][setup Python mode]] and [[lst:choose-common-python-linter][choose common Python linter]] select a common Python
#+caption: Configure =python=. linter for the =python-check-command= and the =python-flymake-command= by means
#+name: lst:configure-python of src_emacs-lisp{(choose-common-python-linter)} from:
1. [[https://github.com/PyCQA/pyflakes][Pyflakes - simple tool which checks Python source files for errors]].
2. [[https://flake8.pycqa.org/en/latest/][Flake8 - your tool for style guide enforcement]].
3. [[https://github.com/charliermarsh/ruff][Ruff - an extremely fast Python linter written in Rust]].
I use [[https://pypi.org/project/ruff/][Ruff]] to replace [[https://pypi.org/project/flake8/][Flake8]] with a variety of its plugins. [[https://notes.crmarsh.com/][Charlie Marsh]]
explains why he started [[https://pypi.org/project/ruff/][Ruff]] in the post [[https://notes.crmarsh.com/python-tooling-could-be-much-much-faster][Python tooling could be much faster]].
Listing [[lst:pyproject-toml-kickoff][kickoff pyproject.toml proposal]] facilitates dropping a [[https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml][pyproject.toml]]
file into Python projects which anyhow should switch to using a [[https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml][pyproject.toml]]
file as explained in the post [[https://bbc.github.io/cloudfit-public-docs/packaging/this_way_up.html][This Way Up: A Bottom-Up Look At Python Packaging]].
Listing [[lst:setup-cfg-kickoff][kickoff setup.cfg proposal]] implements the [[https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html][using black with other tools]]
rules which make [[https://flake8.pycqa.org/en/latest/][flake8]] or [[https://pycodestyle.pycqa.org/en/latest/][pycodestyle]] agree with [[https://black.readthedocs.io/en/stable/index.html][black's uncompromising style]].
Finally, listing [[lst:flake8-nocolor][flake8-nocolor]] and [[lst:ruff-nocolor][ruff-nocolor]] pipe the =stdout= output of the
[[https://pypi.org/project/flake8/][flake8]] and [[https://pypi.org/project/ruff/][ruff]] executables through =cat= to remove escape sequences.
#+caption[Setup Python mode]:
#+caption: Setup Python mode.
#+name: lst:setup-python-mode
#+begin_src emacs-lisp #+begin_src emacs-lisp
(with-eval-after-load 'python (with-eval-after-load 'python
(custom-set-variables (custom-set-variables
`(python-check-command ,(executable-find "flake8"))
`(python-flymake-command '(,(executable-find "flake8") "-"))
'(python-indent-guess-indent-offset nil) '(python-indent-guess-indent-offset nil)
'(python-shell-completion-native-disabled-interpreters '("ipython3" "pypy"))) '(python-shell-completion-native-disabled-interpreters '("ipython3" "pypy")))
(choose-common-python-interpreter 'python)) (choose-common-python-interpreter 'python)
(choose-common-python-linter 'ruff-nocolor))
#+end_src #+end_src
#+caption[Choose common =python= interpreter for =ob-python= and =python-mode=]: #+caption[Choose a common Python interpreter]:
#+caption: Choose =python= interpreter for =ob-python= and =python-mode=. #+caption: Choose a common Python interpreter for =ob-python= and =python-mode=.
#+name: lst:choose-common-python-interpreter #+name: lst:choose-common-python-interpreter
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defun choose-common-python-interpreter (&optional program) (defun choose-common-python-interpreter (&optional interpreter)
"Choose Python interpreter PROGRAM for `ob-python' and `python-mode'." "Let `ob-python' and `python-mode' use the same Python INTERPRETER."
(interactive) (interactive)
(let* ((prompt (format "Choose Python (%s): " (let* ((prompt (format "Choose Python (%s): "
(bound-and-true-p python-shell-interpreter))) (bound-and-true-p python-shell-interpreter)))
(choices '(ipython python)) (choices '(ipython python))
(choice (if (member program choices) (choice (if (member interpreter choices)
(symbol-name program) (symbol-name interpreter)
(completing-read prompt choices nil t)))) (completing-read prompt choices nil t))))
(when (boundp 'org-babel-python-command) (when (boundp 'org-babel-python-command)
(pcase choice (pcase choice
@ -4375,9 +4400,44 @@ and listing [[lst:setting-python-shell-virtualenv-root]] to set
python-shell-interpreter)))) python-shell-interpreter))))
#+end_src #+end_src
#+caption[Manage =pyenv=]: #+caption[Choose a common Python linter]:
#+caption: Manage =pyenv=. #+caption: Choose a common Python linter for =python-check-command= and
#+name: lst:manage-pyenv #+caption: =python-flymake-command=.
#+name: lst:choose-common-python-linter
#+begin_src emacs-lisp
(defun choose-common-python-linter (&optional linter)
"Let `python-check-command' and `python-flymake-command' use the same LINTER."
(interactive)
(let* ((prompt (format "Choose Python checker (%s): "
(bound-and-true-p python-check-command)))
(choices '(flake8-nocolor pyflakes ruff-nocolor))
(choice (if (member linter choices)
(symbol-name linter)
(completing-read prompt choices nil t))))
(when (and (boundp 'python-check-command) (boundp 'python-flymake-command))
(pcase choice
("flake8-nocolor"
(custom-set-variables
`(python-check-command ,(executable-find choice))
`(python-flymake-command (list ,(executable-find choice) "-"))))
("pyflakes"
(custom-set-variables
`(python-check-command ,(executable-find choice))
`(python-flymake-command `(,(executable-find choice)))))
("ruff-nocolor"
(custom-set-variables
`(python-check-command ,(executable-find choice))
`(python-flymake-command
(list ,(executable-find choice) "--stdin-filename" "stdin" "-")))))
(when (bound-and-true-p python-check-custom-command)
(setq python-check-custom-command nil))
(message "Python checker commands are %S and %S"
python-check-command python-flymake-command))))
#+end_src
#+caption[Access =pyenv=]:
#+caption: Access =pyenv=.
#+name: lst:access-pyenv
#+begin_src emacs-lisp #+begin_src emacs-lisp
(when (executable-find "pyenv") (when (executable-find "pyenv")
(defun pyenv-full-path (version) (defun pyenv-full-path (version)
@ -4421,9 +4481,9 @@ Complete the result with \"system\"."
(error "%s" (string-trim output)))))) (error "%s" (string-trim output))))))
#+end_src #+end_src
#+caption[Setting =python-shell-virtualenv-root=]: #+caption[Select the Python virtual environment]:
#+caption: Setting =python-shell-virtualenv-root=. #+caption: Select the Python virtual environment.
#+name: lst:setting-python-shell-virtualenv-root #+name: lst:select-python-virtual-environment
#+begin_src emacs-lisp #+begin_src emacs-lisp
(with-eval-after-load 'python (with-eval-after-load 'python
(when (cl-every #'fboundp '(pyenv-full-path (when (cl-every #'fboundp '(pyenv-full-path
@ -4464,65 +4524,174 @@ Complete the result with \"system\"."
python-shell-virtualenv-root))))) python-shell-virtualenv-root)))))
#+end_src #+end_src
#+caption[Kickoff =pyproject.toml= proposal]:
#+caption: Kickoff =pyproject.toml= proposal.
#+name: lst:pyproject-toml-kickoff
#+begin_src toml :tangle pyproject.toml
# [project]
# name = "fancy-name"
# [build-system]
# requires = ["setuptools", "wheel"]
# build-backend = "setuptools.build_meta"
[tool.black]
line-length = 88
[tool.ruff]
line-length = 88
select = [
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
"C", # mccabe
"E", # pycodestyle
"D", # pydocstyle
"F", # pyflakes
# "W", # ruff emits no pycodestyle warnings yet
]
ignore = [
# https://www.pydocstyle.org/en/stable/error_codes.html#default-conventions
# pydocstyle numpy convention:
"D107", # ignore: missing docstring in __init__
"D203", # ignore: single blank line required before class docstring
"D212", # ignore: multi-line docstring summary should start at the first line
"D213", # ignore: multi-line docstring summary should start at the second line
"D402", # ignore: first line should not be the function signature
"D413", # ignore: missing blank line after last section
"D415", # ignore: 1st line should end with a ".", "?", or "?"
"D416", # ignore: section name should end with a ":"
"D417", # ignore: missing argument descriptions in the docstring
]
[tool.ruff.mccabe]
max-complexity = 15
# Local Variables:
# mode: conf-toml
# End:
#+end_src
#+caption[Kickoff =setup.cfg= proposal]:
#+caption: Kickoff =setup.cfg= proposal.
#+name: lst:setup-cfg-kickoff
#+begin_src toml :tangle setup.cfg
[flake8]
docstring-convention = numpy
extend-select = B,F,W
extend-ignore = W503
max-complexity = 15
max-line-length = 88
[pycodestyle]
ignore = W503
max-line-length = 88
# Local Variables:
# mode: conf-toml
# End:
#+end_src
#+caption[Wrap =flake8= to remove color from text output]:
#+caption: Wrap =flake8= to remove color from text output.
#+header: :tangle-mode (identity #o755)
#+name: lst:flake8-nocolor
#+begin_src shell :noeval :tangle ~/bin/flake8-nocolor
#!/bin/sh
flake8 "$@" | cat
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
#+end_src
#+caption[Wrap =ruff= to remove color from text output]:
#+caption: Wrap =ruff= to remove color from text output.
#+header: :tangle-mode (identity #o755)
#+name: lst:ruff-nocolor
#+begin_src shell :noeval :tangle ~/bin/ruff-nocolor
#!/bin/sh
ruff "$@" | cat
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-basic-offset: 2
# End:
#+end_src
*** [[https://github.com/joaotavora/eglot][Eglot]] for [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]] *** [[https://github.com/joaotavora/eglot][Eglot]] for [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][python-mode]]
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: sec:eglot-python :CUSTOM_ID: sec:eglot-python
:END: :END:
Listing [[lst:configure-eglot+pylsp-with-pyls-flake8]] configures [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]] Listing [[lst:configure-eglot+pylsp-ruff]] configures [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]] using the
using the [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] with the [[https://github.com/emanspeaks/pyls-flake8#readme][pyls-flake8]] plugin for the easiest way to [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] with the [[https://github.com/python-lsp/python-lsp-ruff#readme][pylsp-ruff]] plugin for the easiest way to let
let [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] use [[https://github.com/PyCQA/flake8][flake8]]. In order to enable all builtin [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] use [[https://pypi.org/project/ruff/][Ruff]]. The latest [[https://github.com/python-lsp/python-lsp-server#readme][python-lsp-server]] documentation tells to
[[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure installation of the Python packages configure it for [[https://github.com/PyCQA/flake8][flake8]] as in listing [[lst:configure-eglot+pylsp+flake8]]. In order
[[https://github.com/hhatto/autopep8#readme][autopep8]], [[https://github.com/PyCQA/flake8][flake8]], [[https://github.com/PyCQA/pydocstyle#readme][pydocstyle]], [[https://github.com/PyCQA/pylint#readme][pylint]], [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]], [[https://github.com/python-rope/rope#readme][rope]], and [[https://github.com/google/yapf#readme][yapf]]. The to enable all builtin [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure installation of the
latest [[https://github.com/python-lsp/python-lsp-server#readme][python-lsp-server]] documentation tells to configure it for [[https://github.com/PyCQA/flake8][flake8]] as in Python packages [[https://github.com/hhatto/autopep8#readme][autopep8]], [[https://github.com/PyCQA/flake8][flake8]], [[https://github.com/PyCQA/pydocstyle#readme][pydocstyle]], [[https://github.com/PyCQA/pylint#readme][pylint]], [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]], [[https://github.com/python-rope/rope#readme][rope]],
listing [[lst:configure-eglot+pylsp-sans-pyls-flake8]]. This method is under and [[https://github.com/google/yapf#readme][yapf]]. This method is under investigation (it feels flaky since it shows
investigation (it feels flaky since it shows some error messages twice). some error messages twice).
Listing [[lst:eglot-directory-variables-for-python]] shows a proper [[info:emacs#Directory Variables][.dir-locals.el]] Listing [[lst:eglot-directory-variables-for-python]] shows a proper [[info:emacs#Directory Variables][.dir-locals.el]]
file in the root directory of any [[https://www.python.org][Python]] project to start [[https://github.com/joaotavora/eglot][eglot]] automatically file in the root directory of any [[https://www.python.org][Python]] project to start [[https://github.com/joaotavora/eglot][eglot]] automatically
according to the configuration in listing [[lst:eglot-maybe-ensure]]. Type according to the configuration in listing [[lst:eglot-maybe-ensure]]. Type
{{{kbd(M-x eglot-show-workspace-configuration)}}} to dump a =JSON= {{{kbd(M-x eglot-show-workspace-configuration)}}} to dump a =JSON=
representation of src_emacs-lisp{eglot-workspace-configuration} for debugging. representation of src_emacs-lisp{eglot-workspace-configuration} for debugging.
The comment in listing [[lst:ensure-eglot-installation]] also shows how to increase The comment in listing [[lst:minimal-eglot-setup][minimal Eglot setup]] also shows how to decrease
the the verbosity of [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] log output for debugging. or to increase the verbosity of [[https://github.com/python-lsp/python-lsp-server][Python LSP server]] log output for debugging.
#+caption[Configure =eglot= with =python-lsp-server= with =pyls_flake8=]: #+caption[Configure =eglot= with =python-lsp-ruff=]:
#+caption: Configure =eglot= with =python-lsp-server= with =pyls_flake8=. #+caption: Configure =eglot= with =python-lsp-ruff=.
#+name: lst:configure-eglot+pylsp-with-pyls-flake8 #+name: lst:configure-eglot+pylsp-ruff
#+begin_src emacs-lisp #+begin_src emacs-lisp
(with-eval-after-load 'eglot (with-eval-after-load 'eglot
(setq-default (setq-default
eglot-workspace-configuration eglot-workspace-configuration
;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle. ;; Enable the `:pyls_ruff' plugin and ensure to disable the
;; `:flake8', `:mccabe', and `:pycodestye' plugins.
'(:pylsp (:plugins '(:pylsp (:plugins
(:pyls_flake8 (:pylsp_ruff
(:enabled t) (:enabled t)
:flake8
(:enabled :json-false)
:mccabe
(:enabled :json-false)
:pycodestyle
(:enabled :json-false)
:jedi :jedi
(:auto_import_modules ["numpy"]) (:auto_import_modules ["numpy"])
:jedi_completion :jedi_completion
(:cache_for ["astropy"])))))) (:cache_for ["astropy"]))))))
#+end_src #+end_src
#+caption[Configure =eglot= with =python-lsp-server= sans =pyls_flake8=]: #+caption[Configure =eglot= with =python-lsp-server= and the =flake8= plugin]:
#+caption: Configure =eglot= with =python-lsp-server= sans =pyls_flake8=. #+caption: Configure =eglot= with =python-lsp-server= and the =flake8= plugin.
#+name: lst:configure-eglot+pylsp-sans-pyls-flake8 #+name: lst:configure-eglot+pylsp+flake8
#+begin_src emacs-lisp :tangle no #+begin_src emacs-lisp :tangle no
(with-eval-after-load 'eglot (with-eval-after-load 'eglot
(setq-default (setq-default
eglot-workspace-configuration eglot-workspace-configuration
;; How to use flake8 instead of pycodestyle officially, see: ;; How to use flake8 instead of pycodestyle or ruff, see:
;; https://github.com/python-lsp/python-lsp-server#configuration ;; https://github.com/python-lsp/python-lsp-server#configuration
'(:pylsp (:configurationSources '(:pylsp (:configurationSources
["flake8"] ["flake8"]
:plugins :plugins
(:pycodestyle (:flake8
(:enabled :json-false) (:enabled t)
:mccabe :mccabe
(:enabled :json-false) (:enabled :json-false)
:pycodestyle
(:enabled :json-false)
:pyflakes :pyflakes
(:enabled (:enabled :json-false)
:json-false) :pylsp-ruff
:flake8 (:enabled :json-false)
(:enabled t)
:jedi :jedi
(:auto_import_modules ["numpy"]) (:auto_import_modules ["numpy"])
:jedi_completion :jedi_completion
@ -4530,9 +4699,8 @@ the the verbosity of [[https://github.com/python-lsp/python-lsp-server][python-l
#+end_src #+end_src
#+caption[A =.dir-locals.el= proposal to launch =eglot= automatically]: #+caption[A =.dir-locals.el= proposal to launch =eglot= automatically]:
#+caption: A =.dir-locals.el= proposal for any Python project #+caption: A =.dir-locals.el= file proposal for Python projects or Org-mode
#+caption: or any Org-mode project tangling Python files #+caption: projects tangling Python files to launch =eglot= automatically.
#+caption: to launch =eglot= automatically.
#+name: lst:eglot-directory-variables-for-python #+name: lst:eglot-directory-variables-for-python
#+begin_src emacs-lisp :tangle dir-locals.el #+begin_src emacs-lisp :tangle dir-locals.el
;; A .dir-locals.el file proposal in the root of any ;; A .dir-locals.el file proposal in the root of any
@ -4540,10 +4708,17 @@ the the verbosity of [[https://github.com/python-lsp/python-lsp-server][python-l
;; to launch eglot automatically. ;; to launch eglot automatically.
((nil ;; nil, since Emacs-29.1 filters out irrelevant variable names. ((nil ;; nil, since Emacs-29.1 filters out irrelevant variable names.
. ((eglot-workspace-configuration . ((eglot-workspace-configuration
;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle. ;; Enable the `:pyls_ruff' plugin and ensure to disable the
;; `:flake8', `:mccabe', and `:pycodestye' plugins.
. (:pylsp (:plugins . (:pylsp (:plugins
(:pyls_flake8 (:pylsp_ruff
(:enabled t) (:enabled t)
:flake8
(:enabled :json-false)
:mccabe
(:enabled :json-false)
:pycodestyle
(:enabled :json-false)
:jedi :jedi
(:auto_import_modules ["numpy"]) (:auto_import_modules ["numpy"])
:jedi_completion :jedi_completion
@ -4565,43 +4740,6 @@ the the verbosity of [[https://github.com/python-lsp/python-lsp-server][python-l
| eldoc-doc-buffer | eglot-mode-map | {{{kbd(C-h .)}}} | | eldoc-doc-buffer | eglot-mode-map | {{{kbd(C-h .)}}} |
|-------------------------+----------------+------------------| |-------------------------+----------------+------------------|
Listing [[lst:pyproject-toml-kick-off]] and [[lst:setup-cfg-kick-off]] implement the
rules in [[https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html][using black with other tools]] in order to make [[https://flake8.pycqa.org/en/latest/][flake8]] or [[https://pycodestyle.pycqa.org/en/latest/][pycodestyle]]
agree with [[https://black.readthedocs.io/en/stable/index.html][black's uncompromising style]].
#+caption[Kick starting a =pyproject.toml= file]:
#+caption: Kick starting a =pyproject.toml= file.
#+name: lst:pyproject-toml-kick-off
#+begin_src toml :tangle pyproject.toml
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 88
# Local Variables:
# mode: conf-toml
# End:
#+end_src
#+caption[Kick starting a =setup.cfg= file]:
#+caption: Kick starting a =setup.cfg= file.
#+name: lst:setup-cfg-kick-off
#+begin_src toml :tangle setup.cfg
[flake8]
max-line-length = 88
extend-ignore = E203
[pycodestyle]
ignore = E203
max-line-length = 88
# Local Variables:
# mode: conf-toml
# End:
#+end_src
Listing [[lst:make-pylsp-server-patch]] is useful to propagate eventual patches of Listing [[lst:make-pylsp-server-patch]] is useful to propagate eventual patches of
a local fork of [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]. a local fork of [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]].