-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Fix uv sync --no-sources
not switching from editable to registry installations
#15234
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
Fix uv sync --no-sources
not switching from editable to registry installations
#15234
Conversation
Hey thanks for taking a swing at this! Naively, I think I'd expect this to be implemented in uv/crates/uv-installer/src/site_packages.rs Lines 291 to 298 in c19a294
uv/crates/uv-installer/src/site_packages.rs Lines 386 to 393 in c19a294
Did you look at that? Does that not work for some reason? |
After reviewing the
The bug is in uv/crates/uv-installer/src/satisfies.rs Lines 33 to 38 in c19a294
Why Not Pass SourceStrategy? Initially, I considered passing
|
same problem use (test_uv_pip_no_sources) ➜ test_uv_pip_no_sources git:(fix/sync-no-sources-editable-switch) ✗ cat pyproject.toml
[project]
name = "test_no_sources"
version = "0.0.1"
dependencies = ["git_mcp_server"]
[tool.uv.sources]
git_mcp_server = { path = "./git_mcp", editable = true }
(test_uv_pip_no_sources) ➜ test_uv_pip_no_sources git:(fix/sync-no-sources-editable-switch) ✗ head git_mcp/pyproject.toml
[project]
name = "git_mcp_server"
version = "0.1.9"
description = "Git MCP Server - Unified command-line tool for managing Git repositories across GitHub and GitLab"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"python-gitlab>=4.4.0",
"PyGithub>=2.1.0",
"click>=8.1.0",
(test_uv_pip_no_sources) ➜ test_uv_pip_no_sources git:(fix/sync-no-sources-editable-switch) ✗ uv pip install --no-sources git_mcp_server
Resolved 64 packages in 48ms
Installed 1 package in 7ms
+ git-mcp-server==0.1.8
(test_uv_pip_no_sources) ➜ test_uv_pip_no_sources git:(fix/sync-no-sources-editable-switch) ✗ uv pip install -e .
Resolved 65 packages in 24ms
Built test-no-sources @ file:///Users/wingmunfung/workspace/uv/test_uv_pip_no_sources
Prepared 1 package in 520ms
Uninstalled 2 packages in 4ms
Installed 2 packages in 3ms
- git-mcp-server==0.1.8
+ git-mcp-server==0.1.9 (from file:///Users/wingmunfung/workspace/uv/test_uv_pip_no_sources/git_mcp)
~ test-no-sources==0.0.1 (from file:///Users/wingmunfung/workspace/uv/test_uv_pip_no_sources)
(test_uv_pip_no_sources) ➜ test_uv_pip_no_sources git:(fix/sync-no-sources-editable-switch) ✗ uv pip install --no-sources git_mcp_server
Audited 1 package in 15ms
(test_uv_pip_no_sources) ➜ test_uv_pip_no_sources git:(fix/sync-no-sources-editable-switch) ✗ uv pip show git_mcp_server
Name: git-mcp-server
Version: 0.1.9
Location: /Users/wingmunfung/workspace/uv/test_uv_pip_no_sources/.venv/lib/python3.13/site-packages
Editable project location: /Users/wingmunfung/workspace/uv/test_uv_pip_no_sources/git_mcp
Requires: click, gitpython, httpx, keyring, mcp, pre-commit, pydantic, pygithub, python-gitlab, pyyaml, rich, tool
Required-by: test-no-sources
(test_uv_pip_no_sources) ➜ I think the |
Yes sorry, I'm not sure if we need to propagate the source strategy? That should be reflected in the resolution? I think we should be able to tell if an installed distribution matches the resolution. Naively, I'd image we want something like this? diff --git a/crates/uv-installer/src/satisfies.rs b/crates/uv-installer/src/satisfies.rs
index b7e824202..48709e2cc 100644
--- a/crates/uv-installer/src/satisfies.rs
+++ b/crates/uv-installer/src/satisfies.rs
@@ -31,7 +31,9 @@ impl RequirementSatisfaction {
match source {
// If the requirement comes from a registry, check by name.
RequirementSource::Registry { specifier, .. } => {
- if specifier.contains(distribution.version()) {
+ if matches!(distribution, InstalledDist::Registry { .. })
+ && specifier.contains(distribution.version())
+ {
return Self::Satisfied;
}
Self::Mismatch |
1f43846
to
b552e40
Compare
Thank you for your feedback. After applying your modification, I was able to install the package again using However, running Upon closer inspection, I found that the call chains for This mismatch causes the resolver to treat the package as
|
uv/crates/uv-installer/src/plan.rs Lines 94 to 102 in 78c8c71
Doesn’t the log above violate the assumption in the comment #15234 (comment)?
|
Could you help me look into this issue? |
Hey, I'll look when I get a chance — I've been a bit busy and don't know the answer off the top of my head so I'll need to dig into the problem. |
I think that comment is probably wrong. I think I think the error you're seeing is because you changed the logic in the install plan, but you need to make a corresponding change in the resolver, such that when resolving, we don't choose the already-installed URL distribution if the user didn't request a URL. In other words: you need to reflect the change in both the install plan and the resolver, and modifying It's not totally clear to me whether we want that behavior, though. It's clear for the (Alternatively, if we could somehow make this change only for the |
My current change is limited to handling
Do you think this scoped fix is small enough for now? I also experimented with modifying the resolver. Specifically, I tried passing
|
@yumeminami -- Sorry, will get back to you soon, this is on my list. |
@yumeminami -- What do you think of #15450? It's a slightly different approach whereby the |
Thanks your feedback! I took a look of #15450 and I think it did the thing like as discussed in #15234 (comment) by passing the I have some suggestions:
/// Defines the strategy for determining whether an installed package satisfies a requirement.
///
/// This enum controls how the package installer validates existing installations against
/// new requirements, particularly when there are differences in source types (registry vs local).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InstallationStrategy {
/// Permissive strategy: Accept existing installations even if source type differs.
///
/// This strategy mirrors traditional pip behavior, where already-installed packages
/// are reused if they satisfy the version requirements, regardless of how they were
/// originally installed. For example:
/// - If `./path/to/package` is installed and later `package` is requested from registry,
/// the existing installation will be reused if the version matches.
/// - This enables incremental package management where users can mix installation sources.
///
/// Used by: `uv pip install`, `uv pip sync`
Permissive,
/// Strict strategy: Require exact source type matching between installed and requested packages.
///
/// This strategy enforces that the installation source must match the requirement source.
/// It prevents reusing packages that were installed from different sources, ensuring
/// declarative and reproducible environments. For example:
/// - If an editable package is installed but a registry version is requested,
/// the editable installation will be replaced with the registry version.
/// - This is essential for `--no-sources` scenarios where local installations
/// should be replaced with registry equivalents.
///
/// Used by: `uv sync`, `uv run`, `uv tool run`
Strict,
}
|
I’ve attempted to add And I found Rust does not support default parameters in functions—by default, 😢 😢 |
Yeah I think your names are better (mine were sort of lazy, to validate the idea). I think this should only apply to We might (?) need to thread this through to the candidate selector / resolver as well, is the only other downside... That's why some tests are failing, I think. |
Yeah, I agree. If we want the |
Later, I will base #15450 then modify the candidate selector strategy and new a pr again.(maybe Tuesday or Wednesday) |
When --no-sources is used, both uv sync and uv pip install should prefer registry installations over editable/URL installations. Previously, the resolver would still select installed editable packages even when sources were disabled, causing inconsistent behavior. This fix modifies both the resolver's candidate selector and the installer's satisfaction checker to reject non-registry installations when sources are disabled, ensuring proper switching from editable to registry packages.
849071e
to
9b89f34
Compare
…rom editable to registry installations
Now th PR should fix |
how to rerun the CI and why the |
@yumeminami -- Sorry, I was trying to convey that I think this should only affect |
Agree.
…On Sun, 14 Sept 2025 at 10:06, Charlie Marsh ***@***.***> wrote:
*charliermarsh* left a comment (astral-sh/uv#15234)
<#15234 (comment)>
@yumeminami <https://github.com/yumeminami> -- Sorry, I was trying to
convey that I think this should *only* affect uv sync (and uv pip install
should be unchanged). Do you agree?
—
Reply to this email directly, view it on GitHub
<#15234 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AQDB34QOSDH6KYLOJZ6Q7EL3STER3AVCNFSM6AAAAACDV3WXSKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTEOBZGA4DONJSG4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Okay thanks. I will revisit this and look to get it merged. |
Okay, this should be good to go. It only changes the behavior for |
@charliermarsh thanks! |
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.8.17` -> `0.8.22` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>astral-sh/uv (astral-sh/uv)</summary> ### [`v0.8.22`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0822) [Compare Source](astral-sh/uv@0.8.21...0.8.22) Released on 2025-09-23. ##### Python - Upgrade Pyodide to 0.28.3 ([#​15999](astral-sh/uv#15999)) ##### Security - Upgrade `astral-tokio-tar` to 0.5.5 which [hardens tar archive extraction](GHSA-3wgq-wrwc-vqmv) ([#​16004](astral-sh/uv#16004)) ### [`v0.8.21`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0821) [Compare Source](astral-sh/uv@0.8.20...0.8.21) Released on 2025-09-23. ##### Enhancements - Refresh lockfile when `--refresh` is provided ([#​15994](astral-sh/uv#15994)) ##### Preview features Add support for S3 request signing ([#​15925](astral-sh/uv#15925)) ### [`v0.8.20`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0820) [Compare Source](astral-sh/uv@0.8.19...0.8.20) Released on 2025-09-22. ##### Enhancements - Add `--force` flag for `uv cache clean` ([#​15992](astral-sh/uv#15992)) - Improve resolution errors with proxied packages ([#​15200](astral-sh/uv#15200)) ##### Preview features - Allow upgrading pre-release versions of the same minor Python version ([#​15959](astral-sh/uv#15959)) ##### Bug fixes - Hide `freethreaded+debug` Python downloads in `uv python list` ([#​15985](astral-sh/uv#15985)) - Retain the cache lock and temporary caches during `uv run` and `uvx` ([#​15990](astral-sh/uv#15990)) ##### Documentation - Add `package` level conflicts to the conflicting dependencies docs ([#​15963](astral-sh/uv#15963)) - Document pyodide support ([#​15962](astral-sh/uv#15962)) - Document support for free-threaded and debug Python versions ([#​15961](astral-sh/uv#15961)) - Expand the contribution docs on issue selection ([#​15966](astral-sh/uv#15966)) - Tweak title for viewing version in project guide ([#​15964](astral-sh/uv#15964)) ### [`v0.8.19`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0819) [Compare Source](astral-sh/uv@0.8.18...0.8.19) Released on 2025-09-19. ##### Python - Add CPython 3.14.0rc3 - Upgrade OpenSSL to 3.5.3 See the [python-build-standalone release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250918) for more details. ##### Bug fixes - Make `uv cache clean` parallel process safe ([#​15888](astral-sh/uv#15888)) - Fix implied `platform_machine` marker for `win_arm64` platform tag ([#​15921](astral-sh/uv#15921)) ### [`v0.8.18`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0818) [Compare Source](astral-sh/uv@0.8.17...0.8.18) Released on 2025-09-17. ##### Enhancements - Add PyG packages to torch backend ([#​15911](astral-sh/uv#15911)) - Add handling for unnamed conda environments in base environment detection ([#​15681](astral-sh/uv#15681)) - Allow selection of debug build interpreters ([#​11520](astral-sh/uv#11520)) - Improve `uv init` defaults for native build backend cache keys ([#​15705](astral-sh/uv#15705)) - Error when `pyproject.toml` target does not exist for dependency groups ([#​15831](astral-sh/uv#15831)) - Infer check URL from publish URL when known ([#​15886](astral-sh/uv#15886)) - Support Gitlab CI/CD as a trusted publisher ([#​15583](astral-sh/uv#15583)) - Add GraalPy 25.0.0 with support for Python 3.12 ([#​15900](astral-sh/uv#15900)) - Add `--no-clear` to `uv venv` to disable removal prompts ([#​15795](astral-sh/uv#15795)) - Add conflict detection between `--only-group` and `--extra` flags ([#​15788](astral-sh/uv#15788)) - Allow `[project]` to be missing from a `pyproject.toml` ([#​14113](astral-sh/uv#14113)) - Always treat conda environments named `base` and `root` as base environments ([#​15682](astral-sh/uv#15682)) - Improve log message when direct build for `uv_build` is skipped ([#​15898](astral-sh/uv#15898)) - Log when the cache is disabled ([#​15828](astral-sh/uv#15828)) - Show pyx organization name after authenticating ([#​15823](astral-sh/uv#15823)) - Use `_CONDA_ROOT` to detect Conda base environments ([#​15680](astral-sh/uv#15680)) - Include blake2b hash in `uv publish` upload form ([#​15794](astral-sh/uv#15794)) - Fix misleading debug message when removing environments in `uv sync` ([#​15881](astral-sh/uv#15881)) ##### Deprecations - Deprecate `tool.uv.dev-dependencies` ([#​15469](astral-sh/uv#15469)) - Revert "feat(ci): build loongarch64 binaries in CI ([#​15387](astral-sh/uv#15387))" ([#​15820](astral-sh/uv#15820)) ##### Preview features - Propagate preview flag to client for `native-auth` feature ([#​15872](astral-sh/uv#15872)) - Store native credentials for realms with the https scheme stripped ([#​15879](astral-sh/uv#15879)) - Use the root index URL when retrieving credentials from the native store ([#​15873](astral-sh/uv#15873)) ##### Bug fixes - Fix `uv sync --no-sources` not switching from editable to registry installations ([#​15234](astral-sh/uv#15234)) - Avoid display of an empty string when a path is the working directory ([#​15897](astral-sh/uv#15897)) - Allow cached environment reuse with `@latest` ([#​15827](astral-sh/uv#15827)) - Allow escaping spaces in --env-file handling ([#​15815](astral-sh/uv#15815)) - Avoid ANSI codes in debug! messages ([#​15843](astral-sh/uv#15843)) - Improve BSD tag construction ([#​15829](astral-sh/uv#15829)) - Include SHA when listing lockfile changes ([#​15817](astral-sh/uv#15817)) - Invert the logic for determining if a path is a base conda environment ([#​15679](astral-sh/uv#15679)) - Load credentials for explicit members when lowering ([#​15844](astral-sh/uv#15844)) - Re-add `triton` as a torch backend package ([#​15910](astral-sh/uv#15910)) - Respect `UV_INSECURE_NO_ZIP_VALIDATION=1` in duplicate header errors ([#​15912](astral-sh/uv#15912)) ##### Documentation - Add GitHub Actions to PyPI trusted publishing example ([#​15753](astral-sh/uv#15753)) - Add Coiled integration documentation ([#​14430](astral-sh/uv#14430)) - Add verbose output to the getting help section ([#​15915](astral-sh/uv#15915)) - Document `NO_PROXY` support ([#​15816](astral-sh/uv#15816)) - Document cache-keys for native build backends ([#​15811](astral-sh/uv#15811)) - Add documentation for dependency group `requires-python` ([#​14282](astral-sh/uv#14282)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xMTUuNiIsInVwZGF0ZWRJblZlciI6IjQxLjEyNS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Summary
Fixes issue #15190 where
uv sync --no-sources
fails to switch from editable to registry package installations. The problem occurred because the installer's satisfaction check didn't consider the--no-sources
flag when determining if an existing editable installation was compatible with a registry requirement.Solution
Modified
RequirementSatisfaction::check()
to reject non-registry installations whenSourceStrategy::Disabled
and the requirement is from registry. AddedSourceStrategy
parameter threading through the entire call chain from commands to the satisfaction check to ensure consistent behavior betweenuv sync --no-sources
anduv pip install --no-sources
.