Setting up Emacs to use lsp-mode with Python virtualenvs


I found it surprisingly tricky to get good information on how to set up lsp-mode to work with a Python virtual environment. Here’s my solution.

Global setup

Use pyvenv. This provides Emacs lisp code that can set up Emacs to use a particular virtualenv using the pyvenv-activate function. I do this in my init.el with use-package:

(use-package pyvenv
  :ensure t)

Of course, I also have lsp installed:

(use-package lsp
  :ensure t)

Per-project setup

Add a file named “.dir-locals.el” to the root of the project. For example, here’s mine for the precovery project:

((python-mode . ((pyvenv-activate . "~/code/b612/precovery/.precovery-venv/")
         (pyvenv-post-activate-hooks . (lsp)))))

The pyvenv-activate cell’s value should be a path to a virtualenv directory. For example, that one was made with

cd ~/code/b612/precovery
python -m venv .precovery-venv

Within each per-project virtualenv, it’s important to install the python-lsp-server package:

source .precovery-venv/bin/activate
pip install python-lsp-server

That’s all there is to it.

The tricky bit here is really pyvenv-post-activate-hooks. The lsp function needs to be called after the Python virtual environment has been activated.