Make pyenv and pyright play nice together

Some time ago I started looking into setting up the built-in LSPs in Neovim, and being Python my main programming language, I set up Pyright as my first language server and gave it a spin. While all the basics things worked out of the box, I kept getting a bunch of Import "some_module" could not be resolved. After having ruled out the classic mistakes (i.e. forgetting to install dependencies, or running Neovim from the wrong folder), and ran some test (Ale recognized my virtualenv as expected), all that was left was that somehow Pyright did not play along with my virtualenv.

Why it happens

By default Pyright tries to be smart and to automatically pick up existing virtualenvs. When it comes to Pyenv, Pyright checks whether $PYENV_VERSION is set and determines which Python interpreter to use from its value. So far so good.

The problems however start when using pyenv local. Basically pyenv-virtualenv has this super nifty function that couples the specified virtualenv with the current folder, so that it gets automatically activated whenever you cd into the directory (and deactivate once you move away from it). However, whenever the virtualenv gets automagically activated, the $PYENV_VERSION variable doesn't get set (and apparently that's by design, and hence unlikely to change anytime soon).

How to solve(ish)

If you need to fix something on the fly, forcing Pyenv to set the environment variable by using pyenv shell <env_name> is a quick way to work around the issue. It's worth mentioning, however, that it's only temporary and that you will have type it again every time you start a new shell. So great for debugging, but not ideal as a long term solution.

A more long term solution is to leverage Pyright configuration options. For doing so, you need to create a pyrightconfig.json file in the root of your project with the following content

  "venvPath": "<PYENV_ROOT>/versions",
  "venv": "<ENV_NAME>"

where PYENV_ROOT is the output of echo $PYENV_ROOT and ENV_NAME is the name of your virtualenv.

Keep in mind though that pyrightconfig.json does not support shell variables, so stuff like ~/.pyenv/versions won't work.

While this is a way better method, it still requires a lot of typing. Wouldn't be great if it was possible to automate this somehow? Enter pyenv-pyright, a Pyenv plugin that takes care of handling pyrightconfig.json on your behalf. So now all you have to do is to type pyenv pyright once and you're ready to go!

Happy coding!


Go Top