python-lsp / pylsp-mypy

Mypy plugin for the Python LSP Server.
MIT License
118 stars 35 forks source link

Used within `eglot` pylsp-mypy only uses base mypy #41

Closed timlod closed 2 months ago

timlod commented 1 year ago

Hi,

I work will multiple python projects and virtual environments within Emacs. I use eglot, and have it set up such that it picks the correct pylsp based on python-shell-virtualenv-root. mypy and pylsp-mypy are installed in my virtualenv, however, the mypy that actually runs when checking my files is the mypy installed in my base python, not the virtualenv. I did try to use the --python-executable override to provide the virtualenv's python executable directly, but that doesn't appear to work in this setup (tried both pyproject.toml and pylsp-mypy.cfg).

Any suggestions on how I may get this working?

Richardk2n commented 1 year ago

Do you have your venv active? By default, the mypy on PATH is used and if you have your venv active (and mypy not on PATH otherwise) that should be the one used.

The executable override should work. Maybe post the contents of your config to make sure there is no error. Are you sure the config option was actually set (as in was the file found)?

timlod commented 1 year ago

Activating a venv inside Emacs isn't really done - I use Emacs in a daemon which starts up at login, so it'll use the base environment. That's why I wanted to use --python-executable.

I have a pylsp-mypy.cfg at the root of my project which has:

{
    "enabled": True,
    "overrides": ["--python-executable", "/home/tim/miniconda3/envs/bm/bin/mypy", True]
}

I also tried it in the pyproject.toml, however I think that this doesn't really work, as it doesn't appear to allow lists with mixed types, i.e. strings and a bool.

Richardk2n commented 1 year ago

--python-executable has to point to your python executable not to mypy

timlod commented 1 year ago

Sorry, I didn't realize I hadn't changed it back. I did/do have it at python, but it didn't work, so I had tried mypy directly as well (which is wrong).

Richardk2n commented 1 year ago

This is odd and I am not quite sure what is happening here. Yesterday I released an update that also informs the user about general issues with mypy (in the first line). Try updating and see if it complains about anything.

The plugin logs debug output. Are you able to read that? (gets stored in different files depending on very many factors (OS, distribution, IDE, ...), you can always hook into the stdout of the process)

timlod commented 1 year ago

Hi, just checking in to say that it's a busy time right now, but that I'll do this once I have time to work on my config again.

petergaultney commented 1 year ago

Out of curiosity, would the maintainers be open to a PR to set the python venv up a little bit more dynamically?

The config option does function on my machine (the above config seems right), but I maintain nearly a hundred different venvs, and creating a configuration file for each is out of the question.

At the moment, I've patched the plugin to automatically derive --python-executable based on the presence of pyproject.toml or Pipfile depending on the type of venv and which tool manages it (and knows how to identify its location). I'd be happy to contribute a more polished version of what I have to the community now that I've got my bearings with pylsp-server and this plugin.

I'm happy to discuss different approaches, etc.

AdamMomen commented 1 year ago

@petergaultney that would be really helpful, I have the same issue with multiple venvs. Automating it would be convenient.

saucoide commented 1 year ago

Posting since I had the same problem, I was trying to set --python-executable in pyslp-mypy config for multiple projects using the overrides option, but the plugin uses subprocess.run so environment variables don't get expanded, which would allow me to use the same config without having to hardcode the paths

but if you are already using pyproject.toml, you can specify the executable in mypy's config directly instead, no need to use pylsp-mypy's overrides:

[tool.mypy]
python_executable = "$VIRTUALENV/bin/python"

[tool.pylsp-mypy]
enabled = true
live_mode = true
strict = true

+ if you use envrc or similar to handle envvars per project it all works smoothly

petergaultney commented 1 year ago

I still have my own fork of this repo that has been working well for me for several months.

In my repos, mypy is a dev dependency of the project, so it's always installed inside the environment, which makes things fairly simple as long as you can point pylsp-mypy to run inside the venv.

I just pip install git@github.com:petergaultney/pylsp-mypy.git into the venv where pylsp-server is installed, and then I have a Python script on my PATH called get-venv.py which looks like this:

#!/usr/bin/env python
import argparse
import json
import logging
import os
import typing as ty
from pathlib import Path

logging.basicConfig(
    format="[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s",
    filename=Path(__file__).parent / "getvenv.log",
    level=logging.INFO,
)

logger = logging.getLogger(__name__)

POETRY = ("poetry", "run", "mypy")
PIPENV = ("pipenv", "run", "mypy")

def get_correct_invocation(cmd: ty.List[str], path: str, workspace: str = ""):
    assert isinstance(cmd, list), f"Command must be a list of strings but is {cmd}"
    if cmd == ["mypy"]:
        if "my-monorepo" in str(path):
            logger.info(f"Using poetry for {path}")
            return dict(cmd=POETRY, path=path, workspace=workspace)
        if path.startswith(os.path.expanduser("~/work/")):
            logger.info(f"Using pipenv for {path}")
            return dict(cmd=PIPENV, path=path, workspace=workspace)
    logger.warning(f"Using raw mypy for {path}")
    return dict(cmd=cmd, path=path, workspace=workspace)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("json")
    args = json.loads(parser.parse_args().json)

    print(json.dumps(get_correct_invocation(args["cmd"], args["path"], args["workspace"])))

if __name__ == "__main__":
    main()

As you can see, you can handle something arbitrarily simple or complex by having this plugin essentially ask the environment to tell it how to run mypy inside a venv.

baco commented 6 months ago

Some insights on the issue:

The workaround is to use the mypy installed within the virtual environment, hence the need to add to the pylsp-mypy plugin the option pylsp_mypy.executable.

The explicit option would allow to overcome this issue calling the mypy executable able to load the plugins.

doolio commented 4 months ago

I had a similar issue where I install the python-lsp-server with pipx and then injected pylsp-mypy into the the python-lsp-server venv created by pipx without exposing the mypy app. The suggestion by @saucoide to set python_executable in the pyproject.toml worked for me. I tried setting it in ~/.config/mypy/config to have it set for all projects but that did not work which I don't understand.

doolio commented 4 months ago

I tried setting it in ~/.config/mypy/config to have it set for all projects but that did not work which I don't understand.

OK, it turns out using quotes in the value in this file is not allowed. See mypy#17205.