Making pylsp Work in Vim

03 May, 2025 · 3 min read · #python #pylsp #vim #lsp

Language servers enable IDE-like features in text editors that support the Language Server Protocol. pylsp is a language server for Python. I use vim-lsp to integrate language servers into Vim. Configuring a language server in vim-lsp is straightforward for most languages, but not for Python.

Any non-trivial Python codebase uses a virtual environment (venv) to store its dependencies. pylsp needs to know the location of the venv, for the currently open file, to function correctly. When using Vim in the terminal, pylsp can be made aware of the location by activating the venv, before starting Vim. It is not possible to do this when starting a Vim GUI, like GVim, outside the terminal. If you use a modern Python dependency manager like uv or Poetry, this post offers a solution that works both inside and outside the terminal.

This post assumes that you have installed and configured vim-lsp. It focuses only on pylsp-specific configuration. Follow vim-lsp’s documentation if you haven’t installed it already. It also assumes that you have pylsp installed. If not, install it with one of the following commands.

uv tool install python-lsp-server
# or
pipx install python-lsp-server

Finding the Virtual Environment #

pylsp uses Jedi for most of its features. It can be pointed to the right venv by setting pylsp.plugins.jedi.environment to the path of the python/python3 executable in the venv.

The location of the python executable within the venv can be found in uv, using the following command.

uv python find

If you use Poetry, try

poetry env info --executable

Configuring pylsp #

In vim-lsp, additional configuration is passed to the language server by setting the workspace_config key in the call to lsp#register_server. Its value is usually a dict, but we cannot use that as lsp#register_server is called when Vim starts. When started outside the terminal, Vim starts with $HOME as the working directory and we do not know the project whose venv must be used. We must instead detect the venv after we switch to a project’s directory.

vim-lsp allows us to use a lambda that returns a dict as the value for workspace_config, instead of a dict itself. The lambda will be called when the language server is started, rather than when Vim starts up. Since the language server is started when we open a file whose type is allow-listed for the server, we are likely to be in the project’s directory at this point.

Let’s first define a function to detect the venv location using uv/Poetry and return it in a dict.

def PyLspConfig(): dict<any>
  # Use poetry env info --executable, if you use Poetry.
  var python = trim(system('uv python find'))
  return {'pylsp': {'plugins': {'jedi': {'environment': python}}}}
enddef

We can then set workspace_config to a lambda that calls PyLspConfig.

if executable('pylsp')
  au User lsp_setup {
    call lsp#register_server({ 
      'name': 'pylsp', 
      'cmd': ['pylsp'], 
      'allowlist': ['python'], 
      'workspace_config': (server_info) => PyLspConfig(), })
  }
endif

Note: The code snippets above use Vim9 script syntax and won’t work as-is in legacy Vim script.

Caveat #

vim-lsp configures the language server only once, on startup. If you switch to a different project’s directory, without quitting Vim, pylsp will continue to use the venv of the directory you were in earlier. To workaround this, you can either restart Vim or stop pylsp using :LspStopServer.

If you liked what you read, consider subscribing to the RSS feed in your favourite feed reader.