The critical part of Python integration with Emacs is running LSP in Python using [[file:ha-programming.org::*direnv][direnv]]. And the only question to ask is if the Python we run it in Docker or in a virtual environment.
** Virtual Environment
For a local virtual machine, simply put the following in your =.envrc= file:
#+begin_src conf
layout_python3
#+end_src
That is pretty slick and simple.
The old way, that we still use if you need a particular version of Python, is to install [[https://github.com/pyenv/pyenv][pyenv]] globally:
#+BEGIN_SRC sh
pip install pyenv
#+END_SRC
And have this in your =.envrc= file:
#+begin_src conf
use python 3.7.1
#+end_src
Also, you need the following in your =~/.config/direnv/direnvrc= file (which I have):
#+begin_src shell
use_python() {
local python_root=$(pyenv root)/versions/$1
load_prefix "$python_root"
if [[ -x "$python_root/bin/python" ]]; then
layout python "$python_root/bin/python"
else
echo "Error: $python_root/bin/python can't be executed."
exit
fi
}
#+end_src
** Docker Environment
Docker really allows you to isolate your project's environment. The downside is that you are using Docker and probably a bloated container. On my work laptop, a Mac, this creates a behemoth virtual machine that immediately spins the fans like a wind tunnel.
But, but... think of the dependencies!
Enough of the rant (I go back and forth), after getting Docker installed and running (ooo Podman ... shiny), and you've created a =Dockerfile= for your project, let's install [[https://github.com/snbuback/container-env][container-env]].
Your project's =.envrc= file would contain something like:
Whew. Each Python project's =requirements-dev.txt= file would reference the [[https://pypi.org/project/python-lsp-server/][python-lsp-server]] (not the /unmaintained/=python-language-server=):
#+begin_src conf
python-lsp-server[all]
#+end_src
*Note:* This does mean, you would have a =tox.ini= with this line:
#+BEGIN_SRC conf
[tox]
minversion = 1.6
skipsdist = True
envlist = linters
ignore_basepython_conflict = True
[testenv]
basepython = python3
install_command = pip install {opts} {packages}
deps = -r{toxinidir}/test-requirements.txt
commands = stestr run {posargs}
stestr slowest
# ...
#+END_SRC
*** Using Jedi Instead
Do we want to use the Jedi version of LSP? Not sure what it buys us.
#+BEGIN_SRC emacs-lisp :tangle no
(use-package lsp-jedi
:config
(with-eval-after-load "lsp-mode"
(add-to-list 'lsp-disabled-clients 'pyls)
(add-to-list 'lsp-enabled-clients 'jedi)))
#+END_SRC
* LSP Integration of Python
Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integration][LSP Integration]] is complete, we can stitch the two projects together:
#+BEGIN_SRC emacs-lisp
(use-package lsp-mode
:hook ((python-mode . lsp)))
#+END_SRC
And we're done.
* Technical Artifacts :noexport:
Let's =provide= a name so we can =require= this file:
#+BEGIN_SRC emacs-lisp :exports none
(provide 'ha-programming-python)
;;; ha-programming-python.el ends here
#+END_SRC
#+DESCRIPTION: A literate programming file for configuring Python.
#+PROPERTY: header-args:sh :tangle no
#+PROPERTY: header-args:emacs-lisp :tangle yes
#+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes