astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
24.52k stars 710 forks source link

`uv pip install -e` and its PEP-660-style editable installs break vscode import resolution (and probably static type checkers) #3898

Closed ThiefMaster closed 3 months ago

ThiefMaster commented 5 months ago

My context is that I have a main package and some related packages. Everything is installed in editable mode for development.

When using standard pip with setuptools installed, this creates an egg-link file inside site-packages which is looked up just fine by type checkers including Pyright (which powers the vscode Python/Pylance extension).

However, when using uv pip install -e, the package is installed in PEP-660 mode with a __editable__.<pkgname+version>.pth and __editable___<pkgname+version>_finder.py, ie using a dynamic import hook.

Of course static analyzers generally do not understand those, and don't even try to extract the information from the "dynamic" code even though it would be trivial to do (by simply parsing the MAPPING dict from the ..._finder.py).

While this is not directly uv's fault, and I generally agree with not outputting legacy stuff, this is causing a problem when IDEs can no longer properly resolve imports. And at least the pyright/pylance developers don't seem to be willing to add any workarounds on their side, so they'd rather wait for the Python ecosystem to agree on something that does not require dynamic import lookups. But that probably needs someone to be willing to write a PEP and get it accepted which all takes some time.

Some related issues/comments:

Is there any chance uv can do something about this, such as providing an option to generate an egg-link instead of a PEP660-style __editable__*.pth, even though it's slightly more legacy?

h-mayorquin commented 3 months ago

To be honest I am bit confused. Pip passess the implementation responsability of editable installs to the backend:

https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs

Doesn't uv does the same?

For packages built with setuptools there are a coupe of configuration options used at installation time. That said, I am not sure if the latest version of setuptools works the way that OP proposes here anymore.

For reference, when building with hatch works with the default that allows static analysis tools to work by default: https://github.com/pypa/hatch/issues/1629#issuecomment-2237849607 I am not sure what uv pip install -e would do if the build backend was hatchling.

Any chance a mantainer could chime in, clarify the state of affairs and say whether this is:

zanieb commented 3 months ago

I agree this issue is not clear. I'm not the expert on this area, but a hatch build backend doesn't use a dynamic .pth

❯ uv venv
Using Python 3.12.3 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtualenv at: .venv
Activate with: source .venv/bin/activate
❯ grep "build-system" -A 2 ../packse/pyproject.toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
❯ uv pip install -e ../packse -q                                                                                      
❯ cat .venv/lib/python3.12/site-packages/_packse.pth
/Users/zb/workspace/packse/src%     

This seems like a problem with setuptools? In their documentation they note:

Setuptools offers no guarantee of which technique will be used to perform an editable installation. This will vary from project to project and may change depending on the specific version of setuptools being used.

It seems possible that you're getting different versions of setuptools depending on if you're using uv or pip? Having you tried using --config-settings to configure this?

konstin commented 3 months ago

This is a known problem with setuptools: https://github.com/pypa/setuptools/issues/3518, it also affects e.g. mypy: https://github.com/python/mypy/issues/13392. It's unfortunately not something we can do anything about, i recommend using one of the workarounds in the linked issues or switching to a different backend such as hatchling or flit.

ThiefMaster commented 3 months ago

It's unfortunately not something we can do anything about

Why not offer a way to do an editable install using the classic static resolution (egg-link) instead of the dynamic one? A while ago I noticed that pip does this when setuptools is installed, while it uses the dynamic resolve when setuptools is not installed.

I never really looked into alternative build backends, but I assume this also means changing all the related configs (setup.cfg etc.) in the project, which is a mess if you have many projects and you either end up with one using something different than all the others, or having to update all of them for consistency...

konstin commented 3 months ago

The old egg mechanism was never standardized and is basically pip-setuptools special casing; in uv, we support PEP 660, the standard editable installs that work across build backends. Pip has also deprecated its current behavior and will remove it in the 25.0 release (https://github.com/pypa/pip/issues/11457).