astral-sh/ruff-lsp

No falling back to the bundled executable

Nefendi opened this issue · 4 comments

Hi, first of all I would like to say that I love the speed of ruff so much that I have nearly forgotten that pylint exists!

I am using ruff_lsp with Mason and lspconfig in Neovim. I have been trying to create a configuration that would basically pick up a local ruff executable if it exists in the environment of the current interpreter and fall back to the bundled one otherwise. I have been playing with the path and interpreter options and arrived at this:

{
    init_options = {
        settings = { interpreter = { "python3" } },
    },
}

It works perfectly if the ruff executable is present in the environment of my current interpreter, under the assumption that I always activate my local venv when working on a project. However, if I remove it, I would expect ruff_lsp to fall back to the bundled executable as implemented in

def _find_ruff_binary_path(settings: WorkspaceSettings) -> str:
with multiple if-statements, but it seems like the bundle variable is always None and the body of the if-statement with the # Third choice comment never gets executed.

As a result, the line

log_to_output(f"Unable to find interpreter executable: {path}")
executes and ruff_lsp throws an exception, because there is no available ruff executable.

I have also checked that when ruff is installed globally, the second choice:

environment_path = shutil.which("ruff")
works perfectly as a fallback.

I have found that this function

def set_bundle(path: str) -> None:
sets the path to the bundled executable, but I think it is never called.

Thank you in advance for your time, and let me know if you need something else from me!

Hey, thanks! I don't believe we ship a bundled executable with the LSP. We ship a bundled executable with the VS Code extension, which uses that set_bundle hook to tell the LSP that it exists; but for the LSP, I believe we expect that you'll install Ruff separately, alongside it.

I see, that would explain this behaviour 😄 So the fact that everything works without a “local” executable may be a result of Mason doing something under the hood. Here are the logs:

[INFO][2024-03-03 21:17:26] ...lsp/handlers.lua:539	"Using interpreter executable: /home/nefendi/.local/share/nvim/mason/packages/ruff-lsp/venv/bin/ruff"
[INFO][2024-03-03 21:17:26] ...lsp/handlers.lua:539	"Inferred version 0.3.0 for: /home/nefendi/.local/share/nvim/mason/packages/ruff-lsp/venv/bin/ruff"

which indicate that ruff got installed in the same venv that ruff_lsp.

Thanks for the clarification! I have one more question before I close this issue: do you know a way to achieve what I want (this fallback behaviour to the executable installed by Mason) using the path or interpreter setting? I would like to avoid modifying local configuration files such pyproject.toml.

The need for this is possibly a little stupid: basically, if I want to use ruff in a project, then I install it as a dependency, but sometimes I only write a little script and I don't create any virtual environment for it. In that case, I would like ruff_lsp to automatically pick up this executable installed by Mason.

Is it possible to give a list of paths to interpreters that can be tried one at a time, or something like that?

I have found a solution to my problem, albeit not an ideal one, using the path setting:

{
    init_options = {
        settings = {
            path = { "$VIRTUAL_ENV/bin/ruff" },
        },
    },
}

Thanks for all the help!

Oh nice!