Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strict uv pip install -e doesn't update symlinks when files change. #10946

Open
charlesnicholson opened this issue Jan 24, 2025 · 13 comments
Open
Labels
bug Something isn't working compatibility Compatibility with a specification or another tool

Comments

@charlesnicholson
Copy link

charlesnicholson commented Jan 24, 2025

Summary

Both pip and uv implement "strict" editable installations for source-layout packages as follows (roughly, I might be missing steps!):

  1. An editable-install directory is created under the source package's build directory, with a name similar to __editable__.package-0.0.1-py3-none-any. Inside of this directory, 1 symlink is created per source file, that links to the source file contents. (This allows authors to edit source files rapidly without having to deal with the editable install process after the initial setup)
  2. A .pth file is created in the venv's site packages library directory, that contains the absolute path to the source package's symlink directory under its build directory.

This structure and definition allows Python and tooling (LSPs etc) to resolve import statements directly into the source directory of a package being developed.

When programmers add new files to their package, or rename files in their package, the symlinks in this special directory must be updated. If a developer renames foo.py to bar.py, they must re-run the editable install process from their package. This allows Python code from other packages to say from package import bar- under the hood, the import resolver lands in package's symlink directory, and looks for bar.py.
If the symlinks in this directory are not updated, the directory will contain a now-dead symlink to foo.py, and no entry at all for bar.py.

uv pip install -e appears to not update this symlink directory when source files are renamed / added / deleted, but pip install -e does.

I've created a minimal repro case here: https://github.com/charlesnicholson/uv_editable_install_bug_repro

It defines two packages: repro_p1 and repro_p2. repro_p2 depends on repro_p1.

There are two test scripts that do the same thing, one in pip and one in uv. The steps are:

  1. Create a venv.
  2. Editable-install repro_p1 and repro_p2, with strict mode enabled.
  3. Call a simple function in repro_p2 that calls a simple function in repro_p1, to show that the packages work.
  4. Print a new source file into the repro_p1 directory, which has another simple function.
  5. Re-run step 2, which should update the symlinks.
  6. Call a simple function in repro_p2 that calls the new function in the new repro_p1 file

This process succeeds with pip (run ./test_with_pip.sh) and fails with uv (run ./test_with_uv.sh).

I've only tested this on macOS, but if it's helpful I can port this to windows or linux.

pip:
Image

uv:
Image

See how the uv test fails because the repro_p2 script is importing repro_p1's newly-printed file, for which there exists no entry in the symlink directory.

Note that if you add --force-reinstall to step 5, then step 6 will succeed. But, force-reinstall does a whole lot more than just updating the symlinks, so it's a reasonable short-term workaround but this still feels like a bug.

Thanks for reading!

Platform

macOS 15.2 arm64

Version

uv 0.5.23

Python version

Python 3.13.1

@charlesnicholson charlesnicholson added the bug Something isn't working label Jan 24, 2025
@charliermarsh
Copy link
Member

I'm a bit confused. Adding a file should never require re-installing, assuming an editable install. But I'll have to look at your repro more closely when I have time.

@charlesnicholson
Copy link
Author

From https://setuptools.pypa.io/en/latest/userguide/development_mode.html#strict-editable-installs
Image

"... new files won't be exposed and the editable installs will try to mimic as much as possible the behavior of a regular install."

I think your claim that adding a file not requiring re-installing is true for the normal "development" mode, but a bunch of tooling like pyright, which powers our in-editor LSPs, require "strict" mode to function, so we use it.

@charlesnicholson
Copy link
Author

There's a bit of discussion about the VSCode side of things here: mne-tools/mne-python#12169

@zanieb
Copy link
Member

zanieb commented Jan 24, 2025

Ah, the controversial setuptools mode.

@charlesnicholson
Copy link
Author

@zanieb seriously :(

Is there an alternative / better way to do this? We loved the simplicity of "normal" development mode but then all of our LSP tooling stopped working!

@zanieb
Copy link
Member

zanieb commented Jan 24, 2025

Does the "compat" mode not work for you? I think returning to their previous behavior with that flag is a reasonable option. Otherwise, perhaps a different build backend? I wish they had not introduced a new default mode that's so antagonistic to static analysis.

See also pypa/setuptools#3518

@charlesnicholson
Copy link
Author

Thanks for the suggestions! I'm happy to try it- we haven't re-assessed whether compat mode works since we moved to strict a few years ago. Maybe this is a free win :)

(Either way, it still feels like uv should update the symlinks in strict editable re-installs; simply doing it once and then ignoring the symlink directory forever more doesn't seem ideal...)

@zanieb
Copy link
Member

zanieb commented Jan 24, 2025

Yeah it seems like there might be something for us to look into here still

@zanieb zanieb added the compatibility Compatibility with a specification or another tool label Jan 24, 2025
@charliermarsh
Copy link
Member

Hmm, I don't think we can improve anything here without completely reconsidering how we handle caching? We don't re-build on arbitrary code changes.

@charlesnicholson
Copy link
Author

If this can't change easily, maybe consider having uv print a warning when installing, that strict editable installs stop working as soon as you rename a file? That might save a future soul the ~2h that it cost me today :(

@charlesnicholson
Copy link
Author

I don't know the details of how the cache works, but would it be possible to just have uv always redo the symlink work whenever a strict editable install is requested? Maybe it's better that it works but is slow, vs not working at all...

@zanieb
Copy link
Member

zanieb commented Jan 28, 2025

I'm not enthused about adding behaviors that only apply to specific build backend settings.

@charlesnicholson
Copy link
Author

Another thought- just revoke support entirely and explain to users who try to use strict mode that compat mode is probably what they want?

It's kind of a bummer that it exists today but is broken, with no warnings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compatibility Compatibility with a specification or another tool
Projects
None yet
Development

No branches or pull requests

3 participants