linux-cultist / venv-selector.nvim

Allows selection of python virtual environment from within neovim
MIT License
430 stars 44 forks source link

Pyenv virtual environments are not correctly activated in terminal window #165

Open lukeemhigh opened 3 weeks ago

lukeemhigh commented 3 weeks ago

I use pyenv and pyenv-virtualenv, and have exported $PYENV_ROOT to ~/.local/share/pyenv.

To be able to use the plugin with my configuration, I overridden the default pyenv search in the plugin config to look for venvs in that path instead. Here's my plugin config:

---@type LazySpec
return {
  "linux-cultist/venv-selector.nvim",
  branch = "regexp",
  cmd = { "VenvSelect", "VenvSelectLog" },
  lazy = false,
  dependencies = {
    "neovim/nvim-lspconfig",
    { "nvim-telescope/telescope.nvim", branch = "0.1.x", dependencies = { "nvim-lua/plenary.nvim" } },
    "mfussenegger/nvim-dap",
    "mfussenegger/nvim-dap-python",
    {
      "AstroNvim/astrocore",
      opts = {
        mappings = {
          n = {
            ["<Leader>lv"] = { "<Cmd>VenvSelect<CR>", desc = "Activate virtual environment" },
          },
        },
      },
    },
  },
  config = function()
    local function shorter_name(filename)
      local pyenv_root = os.getenv "PYENV_ROOT"
      return filename:gsub(pyenv_root .. "/versions/(%d+%.%d+%.%d+)/envs/", ""):gsub("/bin/python", "")
    end

    require("venv-selector").setup {
      settings = {
        options = {
          activate_venv_in_terminal = true,
          notify_user_on_venv_activation = true,
          debug = true,
        },
        search = {
          pyenv = {
            command = "fd python$ -E '*lib*' -E '*init*' ${PYENV_ROOT}/versions/*.*.*/envs",
            on_telescope_result_callback = shorter_name,
          },
        },
      },
    }
  end,
}

Venvs are found by the search and successfully activated in Neovim, but something weird is happening in the terminal window, as the $VIRTUAL_ENV variable is set to the correct venv, but none of the libraries I have installed are listed by pip list or pip freeze. If I unset the $VIRTUAL_ENV variable and then manually activate the venv in the terminal with pyenv activate <venv_name> the issue disappears (see screenshot):

image

I uploaded the output of VenvSelectLog: VenvSelectLog.txt

Another thing that concerns me (but may be just me not understanding how to use the function) is that if, with a venv activated by the plugin, try to use require("venv-selector").source() to print the current venv source, the function returns nil

linux-cultist commented 2 weeks ago

Hi,

The selected python interpreter should be activated since its first in your path so its strange that pip doesnt work.

The require("venv-selector").source() actually should give the name of the search that found the venv, so in your case where you named it pipenv it should say pipenv. But it seems its not always working. I can see on my own machine that it also gives nil, so I will look into whats happening there. But you can use require("venv-selector").python() to see the python being used, or require("venv-selector").venv for the venv path.

I cant reproduce pip not working however. I select a pipenv environment in VenvSelect and in my terminal, pip freeze lists the libraries and the python interpreter I selected is first in my PATH also.

$ which python

/home/cado/.pyenv/versions/3.10.12/bin/python

$ pip freeze

boto3==1.26.92
botocore==1.29.92
greenlet==2.0.2
msgpack==1.0.4
pynvim==0.4.3
s3transfer==0.6.0

What do you get if you type which pip in the terminal? It should be the pip inside your venv:

/home/cado/.pyenv/versions/3.10.12/bin/pip

lukeemhigh commented 2 weeks ago

Hi, and thanks for taking the time to look into this.

When I open a .py file in Neovim I get a log message from VenvSelect that states Registered '/home/lukeemhigh/.local/share/pyenv/versions/3.12.4/envs/asteroids/bin/python' with pyright LSP..

With that file opened and the venv activated, this is the output of the of the various functions:

print(require("venv-selector").python())
/home/lukeemhigh/.local/share/pyenv/versions/3.12.4/envs/asteroids/bin/python

print(require("venv-selector").venv()
/home/lukeemhigh/.local/share/pyenv/versions/3.12.4/envs/asteroids

print(require("venv-selector").source()
nil

Running which python from the terminal always returns /home/lukeemhigh/.local/share/pyenv/shims/python for me, with or without a venv activated, and the same goes for which pip, always returning /home/lukeemhigh/.local/share/pyenv/shims/pip. I think this is the default behavior for pyenv, which should prepend the shims path to your $PATH, so that the first python and pip executables foud by the system are those contained in that path.

Please let me know if there is a way I can provide more meaningful informations

EDIT: The pyenv shims are only available if you have the following in your shell rc file:

eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
linux-cultist commented 7 hours ago

The plugin doesnt really do any pyenv specific stuff on its own (it doesnt know about the pyenv shims).

I think for your use case, I would write a function that runs on venv activation: https://github.com/linux-cultist/venv-selector.nvim/tree/regexp?tab=readme-ov-file#run-your-own-code-on-venv-activation-on_venv_activate_callback

Then you can make it run pyenv activate <venv_name> for example, if the source is "pyenv". I think right now, the source is always nil if the venv is activated from cache though, but thats a bug that I hope to fix soon. But if you anyway activate the venv by using telescope, it should work.