From 194c97e69b65228657fe3ebc73cf76646a5a3752 Mon Sep 17 00:00:00 2001 From: Gerard Vermeulen Date: Wed, 19 Jan 2022 07:47:56 +0100 Subject: [PATCH] Revise Python section * Generate Python project configuration files. * Use pyls-flake8 again. * Revise text. --- .gitignore | 2 + README.org | 121 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index e237718..d30648d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,9 @@ dir-locals.el example.py latexmkrc +pyproject.toml org-store-link +setup.cfg setup-include.org tree.svg worg-backend-dependent-execution-update.org diff --git a/README.org b/README.org index 0b1f49a..ede20f0 100644 --- a/README.org +++ b/README.org @@ -1058,8 +1058,8 @@ The code in listing [[lst:customize-org-babel]], [[lst:customize-org]], and (cperl "perl") (diff "diff") (shell-script "bash") - (caml "ocaml") - (org "text"))) + (org "text") + (toml "toml"))) '(org-latex-minted-options '(("bgcolor" "LightGoldenrodYellow"))) `(org-latex-logfiles-extensions ',(cl-union '("lof" "lot") org-latex-logfiles-extensions :test #'equal)) @@ -1780,7 +1780,6 @@ non-interactive =org-element= functions to an =Emacs-lisp= buffer. :PROPERTIES: :CUSTOM_ID: sec:python-coding :END: - The [[https://www.emacswiki.org/emacs/PythonProgrammingInEmacs][Python Programming in Emacs]] wiki page lists options to enhance Emacs's built-in ~python-mode~. Here, the focus is on two packages: 1. [[https://github.com/joaotavora/eglot][Eglot - Emacs polyGLOT: an Emacs LSP client that stays out of your way]]. The @@ -1790,13 +1789,23 @@ built-in ~python-mode~. Here, the focus is on two packages: shows. 2. [[https://github.com/pythonic-emacs/anaconda-mode][Anaconda - code navigation, documentation lookup, and completion for Python]]. In my opinion, [[https://github.com/joaotavora/eglot][eglot]] has more potential than [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]], but [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]] is -compatible with [[info:org#Editing Source Code][source code block editing]] while [[https://github.com/joaotavora/eglot][eglot]] is not. Listing -[[lst:configure-python]] configures [[https://www.python.org][Python]]. +compatible with [[info:org#Editing Source Code][source code block editing]] while [[https://github.com/joaotavora/eglot][eglot]] is not. + +Here are a few links covering how to integrate Emacs, Python and a Python LSP +server, before plunging into the configuring steps: +1. [[https://taingram.org/blog/emacs-lsp-ide.html][Building Your Own Emacs IDE with LSP]] +2. [[https://rgoswami.me/posts/emacs-lang-servers/][Doom Emacs and Language Servers]] +3. [[https://ddavis.io/posts/eglot-python-ide/][Eglot based Emacs Python IDE]] +4. [[https://www.mattduck.com/lsp-python-getting-started.html][Getting started with lsp-mode for Python]] +5. [[https://ddavis.io/posts/python-emacs-3/][Python & Emacs, Take 3]] +6. [[https://ddavis.io/posts/emacs-python-lsp/][Python with Emacs: py(v)env and lsp-mode]] *** [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/progmodes/python.el][Python-mode]] :PROPERTIES: :CUSTOM_ID: sec:python-mode :END: +Listing [[lst:configure-python]] tells the Python shell to disregard its environment +variables (in particular =PYTHONSTARTUPFILE=). #+caption[Configure =python=]: #+caption: Configure =python=. @@ -1812,7 +1821,6 @@ compatible with [[info:org#Editing Source Code][source code block editing]] whil :PROPERTIES: :CUSTOM_ID: sec:pyenv :END: - Listing [[lst:enable-pyenv-mode]] configures and enables =pyenv-mode=. #+caption[Enable =pyenv-mode=]: @@ -1826,22 +1834,22 @@ Listing [[lst:enable-pyenv-mode]] configures and enables =pyenv-mode=. ;; Stop shadowing the org-mode-map "C-c C-s" binding. (define-key pyenv-mode-map (kbd "C-c C-s") nil)) #+end_src + *** [[https://github.com/joaotavora/eglot][Eglot]] :PROPERTIES: :CUSTOM_ID: sec:eglot :END: +Listing [[lst:configure-eglot+python-lsp-server-for-python]] tangles to +=user-init-file= and configures [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]] using the [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]. +In order to enable all builtin [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure +installation of the 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-rope/rope#readme][rope]], +and [[https://github.com/google/yapf#readme][yapf]]. In addition, install the [[https://github.com/emanspeaks/pyls-flake8#readme][pyls-flake8]] plugin to let [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] +use [[https://github.com/PyCQA/flake8][flake8]]. -Listing [[lst:configure-eglot+python-lsp-server-for-python]] (tangles to -=user-init-file=) and [[lst:configure-eglot+jedi-language-server-for-python]] (does -not tangle to =user-init-file=) configure [[https://github.com/joaotavora/eglot][eglot]] for [[https://www.python.org][Python]] using the -[[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] (or experimentally the less capable [[https://github.com/pappasam/jedi-language-server][jedi-language-server]]). In -order to enable all builtin [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]] capabilities, ensure installation -of the 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-rope/rope#readme][rope]], and -[[https://github.com/google/yapf#readme][yapf]]. Listing [[lst:on-hack-local-variables-hook-eglot-maybe]] defines a hook -function to launch [[https://github.com/joaotavora/eglot][eglot]] in presence of a proper [[info:emacs#Directory Variables][.dir-locals.el]] file in the root -directory of any [[https://www.python.org][Python]] project. Listing -[[lst:eglot-directory-variables-for-python]] shows such a proper [[info:emacs#Directory Variables][.dir-locals.el]] -file. +Listing [[lst:on-hack-local-variables-hook-eglot-maybe]] defines a hook function to +launch [[https://github.com/joaotavora/eglot][eglot]] in presence of a proper [[info:emacs#Directory Variables][.dir-locals.el]] file in the root directory +of any [[https://www.python.org][Python]] project. Listing [[lst:eglot-directory-variables-for-python]] shows +such a proper [[info:emacs#Directory Variables][.dir-locals.el]] file. #+caption[Configure =eglot= with =python-lsp-server= for Python]: #+caption: Configure =eglot= with =python-lsp-server= for Python. @@ -1853,23 +1861,10 @@ file. (setq-default eglot-workspace-configuration - '((:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))) - (:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"])))) - (:pylsp . (:configurationSources ["flake8"]))))) -#+end_src - -#+caption[Configure =eglot= with =jedi-language-server= for Python]: -#+caption: Configure =eglot= with =jedi-langage-server= for Python. -#+name: lst:configure-eglot+jedi-language-server-for-python -#+begin_src emacs-lisp :tangle no - (with-eval-after-load 'eglot - ;; (setq eglot-server-programs '((python-mode "jedi-language-server"))) - (add-to-list 'eglot-server-programs '(python-mode "jedi-language-server")) - - (setq-default - eglot-workspace-configuration - '((:jedi-language-server - . (:plugins (:jedi (:jediSettings (:autoImportModules ["numpy"])))))))) + '(;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle. + (:pylsp . (:plugins (:pyls_flake8 (:enabled t)))) + (:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))) + (:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"]))))))) #+end_src #+caption[Start =eglot= in case of a proper =dir-local-variables-alist=]: @@ -1896,15 +1891,50 @@ file. ;; Proposal for a .dir-locals.el file in the root of any Python project. ((python-mode . ((eglot-workspace-configuration - . ((:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"])))) - (:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"])))) - (:pylsp . (:configurationSources ["flake8"]))))))) + . (;; Disable the `:pyls_flake8' plugin to fall back to pycodestyle. + (:pylsp . (:plugins (:pyls_flake8 (:enabled t)))) + (:pylsp . (:plugins (:jedi (:auto_import_modules ["numpy"])))) + (:pylsp . (:plugins (:jedi_completion (:cache_for ["astropy"]))))))))) +#+end_src + +Allthough the configuration of [[https://github.com/pythonic-emacs/blacken#readme][blacken]] is not explicit, I use it to format all +new Python code with the [[https://black.readthedocs.io/en/stable/index.html][Python Black code formatter]]. 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 +#+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 #+end_src [[https://jedi.readthedocs.io/en/latest/][Jedi]] provides grammar checking and completion candidates to [[https://github.com/python-lsp/python-lsp-server][python-lsp-server]]. -Only [[https://jedi.readthedocs.io/en/latest/docs/changelog.html][jedi-0.18.1]] works with for instance [[https://numpy.org/][numpy-1.22.0]] in the sense that it -handles universal functions provided that [[https://jedi.readthedocs.io/en/latest/][jedi]] does not parse but imports -[[https://numpy.org/][numpy-1.22.0]] (see [[https://github.com/davidhalter/jedi/issues/1744][jedi issue #1744]], [[https://github.com/davidhalter/jedi/issues/1745][#1745]], and [[https://github.com/davidhalter/jedi/issues/1746][#1746]]). +Only [[https://jedi.readthedocs.io/en/latest/docs/changelog.html][jedi-0.18.1]] works with for instance [[https://numpy.org/][numpy-1.22.0]] in the sense that it does +not choke on universal functions provided that [[https://jedi.readthedocs.io/en/latest/][jedi]] does not parse but imports +[[https://numpy.org/][numpy-1.22.0]] (see [[https://github.com/davidhalter/jedi/issues/1744][jedi issue #1744]], [[https://github.com/davidhalter/jedi/issues/1745][#1745]], and [[https://github.com/davidhalter/jedi/issues/1746][#1746]]). Since the universal +functions are neither builtin methods nor data instances but a kind of "callable +instances", the [[https://docs.python.org/3/library/inspect.html][Python inspect]] module also fails to handle the universal +functions properly. Listing [[lst:make-pylsp-server-patch]] generates listing [[lst:show-pylsp-server-patch]] that shows the patch to make [[https://jedi.readthedocs.io/en/latest/][jedi]] import @@ -1976,20 +2006,10 @@ index bf312f6..4758b53 100644 #+end_src :end: -Finally, here are a few links covering how to integrate Emacs, Python and a -Python LSP server: -1. [[https://taingram.org/blog/emacs-lsp-ide.html][Building Your Own Emacs IDE with LSP]] -2. [[https://rgoswami.me/posts/emacs-lang-servers/][Doom Emacs and Language Servers]] -3. [[https://ddavis.io/posts/eglot-python-ide/][Eglot based Emacs Python IDE]] -4. [[https://www.mattduck.com/lsp-python-getting-started.html][Getting started with lsp-mode for Python]] -5. [[https://ddavis.io/posts/python-emacs-3/][Python & Emacs, Take 3]] -6. [[https://ddavis.io/posts/emacs-python-lsp/][Python with Emacs: py(v)env and lsp-mode]] - *** [[https://github.com/pythonic-emacs/anaconda-mode][Anaconda]] :PROPERTIES: :CUSTOM_ID: sec:anaconda :END: - Listing [[lst:configure-anaconda+company-for-python]] and [[lst:define-my-toggle-anaconda-mode]] configure [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]]. See [[https://github.com/jorgenschaefer/elpy/blob/8d0de310d41ebf06b22321a8534546447456870c/elpy.el#L2775][elpy-module-company]] for how to handle ~company-backends~ as a local variable in listing @@ -2060,7 +2080,6 @@ for how to handle ~company-backends~ as a local variable in listing :PROPERTIES: :CUSTOM_ID: sec:jedi :END: - Listing [[lst:example-py]] is a [[https://www.python.org][Python]] example to test whether [[https://jedi.readthedocs.io/en/latest/][jedi]] in combination with and either [[https://github.com/pythonic-emacs/anaconda-mode][anaconda]] or [[https://github.com/joaotavora/eglot][eglot]] works when coding certain functions of for instance [[https://numpy.org/][numpy]] and [[https://scipy.org/][scipy]].