mfussenegger / nvim-lint

An asynchronous linter plugin for Neovim complementary to the built-in Language Server Protocol support.
GNU General Public License v3.0
2.03k stars 209 forks source link

mypy does not work under a venv #662

Open rhusiev opened 2 months ago

rhusiev commented 2 months ago

When I install mypy for my user (pip install --user mypy), it is recognized by nvim-lint and works.

However, when I use a custom environment for my linters (I create some python -m venv linters_venv, add it to bash, .profile and vim.env.PATH), nvim-lint no longer runs mypy.

I can run mypy in my terminal and using :!mypy in neovim, but nvim-lint does not seem to see it. I also tried changing the require('lint').linters.mypy.cmd to the absolute path to mypy, but nvim-lint still did not run it.

mfussenegger commented 3 weeks ago

If mypy is in $PATH nvim-lint should pick it up.

There's probably something else wrong. Maybe the --python-executable parameter doesn't match

Does it work if you source linters_venv/bin/active before starting nvim?

rhusiev commented 3 weeks ago

It does not work even with the environment sourced before starting neovim.

hbibel commented 3 weeks ago

@rhusiev Can you post your relevant config? I have set up my nvim to use mypy from a virtual environment and it works as expected.

This is essentially what I'm doing:

local nvim_lint = require("lint")

local venv_dir = "path/to/my/venv" -- computed during startup

nvim_lint.linters.mypy.cmd = venv_dir .. "/bin/mypy"
-- args copied from https://github.com/mfussenegger/nvim-lint/blob/master/lua/lint/linters/mypy.lua
nvim_lint.linters.mypy.args = {
  mypy_path,
  "--show-column-numbers",
  "--show-error-end",
  "--hide-error-context",
  "--no-color-output",
  "--no-error-summary",
  "--no-pretty",
  "--python-executable",
  venv_dir .. "/bin/python",
}

nvim_lint.linters_by_ft = {
  python = { "mypy" },
}

Note that I only do this because I'm too lazy to activate the environment. If you activate your environment setting nvim_lint.linters.mypy.cmd and nvim_lint.linters.mypy.args should not be required.

rhusiev commented 3 weeks ago

@hbibel Here you are:

local lint = require("lint")
local mypy = lint.linters.mypy
local mypy_path = vim.fn.expand("$HOME/.local/share/venvs/linters_venv/")
mypy.cmd = mypy_path .. "bin/mypy"
mypy.args = vim.list_extend(mypy.args, {
    function()
        local filename = vim.api.nvim_buf_get_name(0)
        local root_dir
        root_dir = lspconfig_util.find_git_ancestor(filename)
        root_dir = root_dir
            or lspconfig_util.root_pattern("setup.py", "pyproject.toml", "setup.cfg", "requirements.txt")(filename)
        root_dir = root_dir or lspconfig_util.root_pattern("*.py")(filename)
        local cache_dir = vim.fn.expand("$HOME/.cache/mypy/") .. root_dir
        return "--cache-dir=" .. cache_dir .. " --python-executable=" .. mypy_path .. "bin/python"
    end
})
...
lint.linters_by_ft = {
    python = { "flake8", "mypy" },
    ...
}
hbibel commented 3 weeks ago

@rhusiev can you make two changes:

  1. Don't extend the args with a function, but with values
  2. Don't concatenate args into a single string, --cache-dir=... and --python-executable=... should be separate entries in the table

Something like this:

    mypy.args = vim.list_extend(mypy.args, {
        "--cache-dir=" .. cache_dir,
        "--python-executable=" .. mypy_path .. "bin/python",
    })

Apart from that I think it should work. Also make sure you're not using a very old mypy version. Adding vim.print(mypy.args) should also help with debugging.

rhusiev commented 2 weeks ago

Even when I do it like this:

local mypy = lint.linters.mypy
local mypy_path = vim.fn.expand("$HOME/.local/share/venvs/linters_venv/")
mypy.cmd = mypy_path .. "bin/mypy"
mypy.args = {
    "--python-executable",
    mypy_path .. "bin/python",
    "--show-column-numbers",
    "--show-error-end",
    "--hide-error-codes",
    "--hide-error-context",
    "--no-color-output",
    "--no-error-summary",
    "--no-pretty",
}

Without extending mypy.args and a function, it still does not work.

the-citto commented 1 week ago

still a Lua noob here so thank you very much @hbibel's for the hint on how to amend mypy's args

same, I don't activate virtual environments, preferring to refer to the executables within

I'm always using pyproject.toml, and global mypy installed with my package manager

running mypy from command line, it was correctly picking up python_executable from pyproject.toml, but nvim.lint wasn't

I ended up removing all args, relying on pyproject.toml as the only source for my settings

local M = {
    "mfussenegger/nvim-lint",
    dependencies = {
        "williamboman/mason.nvim",
    },
}

M.config = function()
    local lint = require("lint")
    lint.linters.mypy.args = {}
    lint.linters_by_ft = {
        python = {
            "mypy",
        },
    }
    local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true })
    vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, {
        group = lint_augroup,
        callback = function()
            lint.try_lint()
        end,
    })
end

return M

I think some default setting are very good to have, even if not for me, but considering that, for mypy, --python-executable is optional, I think it could not be there at all?