From 866a97db9a14387c651e443f61d3c4c1d62026d9 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 22 Jun 2026 00:02:04 +0200 Subject: [PATCH 1/2] Avoid writing redundant lockfile markers with `tool.uv.environments` When using `tool.uv.environments`, uv would repeat the combined marker of the `tool.uv.environments` universe for all dependency edges. We can remove this redundant marker, improving lockfile readability: **Before** ```toml [[package]] name = "accelerate" version = "0.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub", marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, { name = "numpy", marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, { name = "packaging", marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, { name = "psutil", marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, { name = "pyyaml", marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, { name = "safetensors", marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin'" }, { name = "torch", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/24/5e813a41495ec7fdbc6a0f08e38c099caccf49147b8cd84053f4c3007c35/accelerate-0.33.0.tar.gz", hash = "sha256:11ba481ed6ea09191775df55ce464aeeba67a024bd0261a44b77b30fb439e26a", size = 314567, upload-time = "2024-07-23T13:13:57.691Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/15/33/b6b4ad5efa8b9f4275d4ed17ff8a44c97276171341ba565fdffb0e3dc5e8/accelerate-0.33.0-py3-none-any.whl", hash = "sha256:0a7f33d60ba09afabd028d4f0856dd19c5a734b7a596d637d9dd6e3d0eadbaf3", size = 315131, upload-time = "2024-07-23T13:13:55.502Z" }, ] ``` **After** ```toml [[package]] name = "accelerate" version = "0.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, { name = "numpy" }, { name = "packaging" }, { name = "psutil" }, { name = "pyyaml" }, { name = "safetensors" }, { name = "torch", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin'" }, { name = "torch", version = "2.4.0", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d4/24/5e813a41495ec7fdbc6a0f08e38c099caccf49147b8cd84053f4c3007c35/accelerate-0.33.0.tar.gz", hash = "sha256:11ba481ed6ea09191775df55ce464aeeba67a024bd0261a44b77b30fb439e26a", size = 314567, upload-time = "2024-07-23T13:13:57.691Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/15/33/b6b4ad5efa8b9f4275d4ed17ff8a44c97276171341ba565fdffb0e3dc5e8/accelerate-0.33.0-py3-none-any.whl", hash = "sha256:0a7f33d60ba09afabd028d4f0856dd19c5a734b7a596d637d9dd6e3d0eadbaf3", size = 315131, upload-time = "2024-07-23T13:13:55.502Z" }, ] ``` Resolving the transformers test case with the settings shown below, the lockfile shrinks from 920KB to 716KB, a 22% reduction. ```toml [tool.uv] exclude-dependencies = ["decord"] environments = [ "(platform_python_implementation == 'CPython' and platform_machine == 'x86_64' and sys_platform == 'linux')", "(platform_python_implementation == 'CPython' and platform_machine == 'AMD64' and sys_platform == 'win32')", "(platform_python_implementation == 'CPython' and platform_machine == 'x86_64' and sys_platform == 'darwin')", ] ``` This change causes the lockfile to churn significantly for all `tool.uv.environments` users. --- crates/uv-resolver/src/lock/mod.rs | 61 +++--- crates/uv/tests/lock/lock.rs | 40 ++-- .../uv/tests/lock_scenarios/lock_conflict.rs | 193 +++++++++++++++++- 3 files changed, 249 insertions(+), 45 deletions(-) diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index 280e92afa54bc..94a8c3f5edf7f 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -1227,19 +1227,23 @@ impl Lock { self.fork_markers.as_slice() } + /// The marker describing the universe of this resolution. + fn fork_markers_union(&self) -> MarkerTree { + if self.fork_markers.is_empty() { + return self.requires_python.to_marker_tree(); + } + let mut fork_markers_union = MarkerTree::FALSE; + for fork_marker in &self.fork_markers { + fork_markers_union.or(fork_marker.pep508()); + } + fork_markers_union + } + /// Checks whether the fork markers cover the entire supported marker space. /// /// Returns the actually covered and the expected marker space on validation error. pub fn check_marker_coverage(&self) -> Result<(), (MarkerTree, MarkerTree)> { - let fork_markers_union = if self.fork_markers().is_empty() { - self.requires_python.to_marker_tree() - } else { - let mut fork_markers_union = MarkerTree::FALSE; - for fork_marker in self.fork_markers() { - fork_markers_union.or(fork_marker.pep508()); - } - fork_markers_union - }; + let fork_markers_union = self.fork_markers_union(); let mut environments_union = if !self.supported_environments.is_empty() { let mut environments_union = MarkerTree::FALSE; for fork_marker in &self.supported_environments { @@ -1271,15 +1275,7 @@ impl Lock { &self, new_requires_python: &RequiresPython, ) -> Result<(), (MarkerTree, MarkerTree)> { - let fork_markers_union = if self.fork_markers().is_empty() { - self.requires_python.to_marker_tree() - } else { - let mut fork_markers_union = MarkerTree::FALSE; - for fork_marker in self.fork_markers() { - fork_markers_union.or(fork_marker.pep508()); - } - fork_markers_union - }; + let fork_markers_union = self.fork_markers_union(); let new_requires_python = new_requires_python.to_marker_tree(); if fork_markers_union.is_disjoint(new_requires_python) { Err((fork_markers_union, new_requires_python)) @@ -1314,6 +1310,11 @@ impl Lock { } } + // The simplified marker space covered by this resolution. + let simplified_fork_environment = + SimplifiedMarkerTree::new(&self.requires_python, self.fork_markers_union()) + .as_simplified_marker_tree(); + if !self.supported_environments.is_empty() { let supported_environments = each_element_on_its_line_array( self.supported_environments @@ -1626,7 +1627,11 @@ impl Lock { let mut packages = ArrayOfTables::new(); for dist in &self.packages { - packages.push(dist.to_toml(&self.requires_python, &dist_count_by_name)?); + packages.push(dist.to_toml( + &self.requires_python, + simplified_fork_environment, + &dist_count_by_name, + )?); } doc.insert("package", Item::ArrayOfTables(packages)); @@ -3674,6 +3679,7 @@ impl Package { fn to_toml( &self, requires_python: &RequiresPython, + simplified_fork_environment: MarkerTree, dist_count_by_name: &FxHashMap, ) -> Result { let mut table = Table::new(); @@ -3691,7 +3697,7 @@ impl Package { if !self.dependencies.is_empty() { let deps = each_element_on_its_line_array(self.dependencies.iter().map(|dep| { - dep.to_toml(requires_python, dist_count_by_name) + dep.to_toml(simplified_fork_environment, dist_count_by_name) .into_inline_table() })); table.insert("dependencies", value(deps)); @@ -3701,7 +3707,7 @@ impl Package { let mut optional_deps = Table::new(); for (extra, deps) in &self.optional_dependencies { let deps = each_element_on_its_line_array(deps.iter().map(|dep| { - dep.to_toml(requires_python, dist_count_by_name) + dep.to_toml(simplified_fork_environment, dist_count_by_name) .into_inline_table() })); if !deps.is_empty() { @@ -3717,7 +3723,7 @@ impl Package { let mut dependency_groups = Table::new(); for (extra, deps) in &self.dependency_groups { let deps = each_element_on_its_line_array(deps.iter().map(|dep| { - dep.to_toml(requires_python, dist_count_by_name) + dep.to_toml(simplified_fork_environment, dist_count_by_name) .into_inline_table() })); if !deps.is_empty() { @@ -5744,7 +5750,7 @@ impl Dependency { /// Returns the TOML representation of this dependency. fn to_toml( &self, - _requires_python: &RequiresPython, + simplified_fork_environment: MarkerTree, dist_count_by_name: &FxHashMap, ) -> Table { let mut table = Table::new(); @@ -5758,7 +5764,14 @@ impl Dependency { .collect::(); table.insert("extra", value(extra_array)); } - if let Some(marker) = self.simplified_marker.try_to_string() { + // Avoid writing edge markers that are always fulfilled. + if !self + .simplified_marker + .as_simplified_marker_tree() + .negate() + .is_disjoint(simplified_fork_environment) + && let Some(marker) = self.simplified_marker.try_to_string() + { table.insert("marker", value(marker)); } diff --git a/crates/uv/tests/lock/lock.rs b/crates/uv/tests/lock/lock.rs index 863366afae497..228776127f010 100644 --- a/crates/uv/tests/lock/lock.rs +++ b/crates/uv/tests/lock/lock.rs @@ -18341,7 +18341,7 @@ fn lock_narrowed_python_version_upper() -> Result<()> { version = "0.1.0" source = { directory = "dependency" } dependencies = [ - { name = "iniconfig", marker = "python_full_version >= '3.10'" }, + { name = "iniconfig" }, ] [package.metadata] @@ -18361,7 +18361,7 @@ fn lock_narrowed_python_version_upper() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "dependency", marker = "python_full_version >= '3.10'" }, + { name = "dependency" }, ] [package.metadata] @@ -18660,11 +18660,11 @@ fn lock_constrained_environment() -> Result<()> { version = "24.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", marker = "sys_platform != 'win32'" }, - { name = "mypy-extensions", marker = "sys_platform != 'win32'" }, - { name = "packaging", marker = "sys_platform != 'win32'" }, - { name = "pathspec", marker = "sys_platform != 'win32'" }, - { name = "platformdirs", marker = "sys_platform != 'win32'" }, + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8f/5f/bac24a952668c7482cfdb4ebf91ba57a796c9da8829363a772040c1a3312/black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", size = 634292, upload-time = "2024-03-15T19:35:43.699Z" } wheels = [ @@ -18724,7 +18724,7 @@ fn lock_constrained_environment() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "black", marker = "sys_platform != 'win32'" }, + { name = "black" }, ] [package.metadata] @@ -18989,11 +18989,11 @@ fn lock_constrained_environment_non_project() -> Result<()> { version = "24.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click", marker = "sys_platform != 'win32'" }, - { name = "mypy-extensions", marker = "sys_platform != 'win32'" }, - { name = "packaging", marker = "sys_platform != 'win32'" }, - { name = "pathspec", marker = "sys_platform != 'win32'" }, - { name = "platformdirs", marker = "sys_platform != 'win32'" }, + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8f/5f/bac24a952668c7482cfdb4ebf91ba57a796c9da8829363a772040c1a3312/black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f", size = 634292, upload-time = "2024-03-15T19:35:43.699Z" } wheels = [ @@ -19008,7 +19008,7 @@ fn lock_constrained_environment_non_project() -> Result<()> { version = "0.1.0" source = { virtual = "child" } dependencies = [ - { name = "black", marker = "sys_platform != 'win32'" }, + { name = "black" }, ] [package.metadata] @@ -30468,7 +30468,7 @@ fn lock_arm() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "numpy", marker = "platform_machine == 'arm64'" }, + { name = "numpy" }, ] [package.metadata] @@ -30544,7 +30544,7 @@ fn lock_x86_64() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "numpy", marker = "platform_machine == 'x86_64'" }, + { name = "numpy" }, ] [package.metadata] @@ -30617,7 +30617,7 @@ fn lock_x86() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "numpy", marker = "platform_machine == 'i686'" }, + { name = "numpy" }, ] [package.metadata] @@ -35788,7 +35788,7 @@ fn lock_android() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "deltachat-rpc-server", marker = "sys_platform == 'android'" }, + { name = "deltachat-rpc-server" }, ] [package.metadata] @@ -35891,7 +35891,7 @@ fn lock_required_intersection() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "numpy", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "numpy" }, ] [package.metadata] @@ -36560,7 +36560,7 @@ fn lock_supported_environment_abi3_wheel() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "abi3-package", marker = "python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "abi3-package" }, ] [package.metadata] diff --git a/crates/uv/tests/lock_scenarios/lock_conflict.rs b/crates/uv/tests/lock_scenarios/lock_conflict.rs index e3e5744b50ac7..a829a49801b22 100644 --- a/crates/uv/tests/lock_scenarios/lock_conflict.rs +++ b/crates/uv/tests/lock_scenarios/lock_conflict.rs @@ -2413,7 +2413,7 @@ fn groups_respect_supported_environments_when_filtering_wheels() -> Result<()> { version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "markupsafe", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'x86_64' and extra == 'group-7-project-a' and extra == 'group-7-project-b') or (sys_platform != 'linux' and extra == 'group-7-project-a' and extra == 'group-7-project-b')" }, + { name = "markupsafe" }, ] [package.metadata] @@ -2429,6 +2429,197 @@ fn groups_respect_supported_environments_when_filtering_wheels() -> Result<()> { Ok(()) } +/// When using `tool.uv.environments`, do not repeat the marker of the `tool.uv.environments` +/// universe for all dependency edges, even when conflicts are involved. +#[test] +fn extra_conflict_environments_omit_redundant_markers() -> Result<()> { + let context = uv_test::test_context!("3.12").with_exclude_newer("2025-09-28T00:00:00Z"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "bar" + version = "0.1.0" + requires-python = ">=3.10.0" + dependencies = [ + "tqdm", + "anyio", + ] + + [project.optional-dependencies] + a = ["tqdm<2"] + b = ["tqdm>=2"] + + [tool.uv] + conflicts = [ + [{ extra = "a" }, { extra = "b" }], + ] + environments = [ + "sys_platform == 'darwin' and platform_machine == 'x86_64'", + "sys_platform == 'linux' and platform_machine == 'x86_64'", + ] + "#, + )?; + + uv_snapshot!(context.filters(), context.lock(), @" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 8 packages in [TIME] + "); + + let lock = context.read("uv.lock"); + + // The `anyio` dependency is shared by every fork, so it carries no marker, + // while the forked `numpy` dependencies keep theirs. + insta::with_settings!({ + filters => context.filters(), + }, { + assert_snapshot!( + lock, + @r#" + version = 1 + revision = 3 + requires-python = ">=3.10.0" + resolution-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'x86_64' and sys_platform == 'linux'", + ] + supported-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'x86_64' and sys_platform == 'linux'", + ] + conflicts = [[ + { package = "bar", extra = "a" }, + { package = "bar", extra = "b" }, + ]] + + [options] + exclude-newer = "2025-09-28T00:00:00Z" + + [[package]] + name = "anyio" + version = "4.11.0" + source = { registry = "https://pypi.org/simple" } + dependencies = [ + { name = "exceptiongroup", marker = "(python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version < '3.11' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version >= '3.11' and sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (python_full_version >= '3.11' and sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (platform_machine != 'x86_64' and sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (platform_machine != 'x86_64' and sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b')" }, + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "(python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version >= '3.13' and sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (python_full_version >= '3.13' and sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (platform_machine != 'x86_64' and sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (platform_machine != 'x86_64' and sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b')" }, + ] + sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" } + wheels = [ + { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" }, + ] + + [[package]] + name = "bar" + version = "0.1.0" + source = { virtual = "." } + dependencies = [ + { name = "anyio" }, + { name = "tqdm", version = "1.0", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin' and extra == 'extra-3-bar-a') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-3-bar-a') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b')" }, + { name = "tqdm", version = "4.67.1", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin' and extra != 'extra-3-bar-a') or (platform_machine == 'x86_64' and sys_platform == 'linux' and extra != 'extra-3-bar-a') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b')" }, + ] + + [package.optional-dependencies] + a = [ + { name = "tqdm", version = "1.0", source = { registry = "https://pypi.org/simple" } }, + ] + b = [ + { name = "tqdm", version = "4.67.1", source = { registry = "https://pypi.org/simple" } }, + ] + + [package.metadata] + requires-dist = [ + { name = "anyio" }, + { name = "tqdm" }, + { name = "tqdm", marker = "extra == 'a'", specifier = "<2" }, + { name = "tqdm", marker = "extra == 'b'", specifier = ">=2" }, + ] + provides-extras = ["a", "b"] + + [[package]] + name = "exceptiongroup" + version = "1.3.0" + source = { registry = "https://pypi.org/simple" } + dependencies = [ + { name = "typing-extensions", marker = "(python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version < '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version >= '3.13' and sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (python_full_version >= '3.13' and sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (platform_machine != 'x86_64' and sys_platform == 'darwin' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (platform_machine != 'x86_64' and sys_platform == 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-3-bar-a' and extra == 'extra-3-bar-b')" }, + ] + sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } + wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, + ] + + [[package]] + name = "idna" + version = "3.10" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } + wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, + ] + + [[package]] + name = "sniffio" + version = "1.3.1" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } + wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, + ] + + [[package]] + name = "tqdm" + version = "1.0" + source = { registry = "https://pypi.org/simple" } + resolution-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'x86_64' and sys_platform == 'linux'", + ] + sdist = { url = "https://files.pythonhosted.org/packages/ba/50/e6c90ecbc3a736ca8af22a52b3e665d32797b9f0cf6a79b7f4bd95dc2153/tqdm-1.0.tar.gz", hash = "sha256:d4972cfd62cf50bf88f20749b536258a3f48b31515dea3ad5edd5fe52e742c6c", size = 1756, upload-time = "2013-10-26T20:06:45.223Z" } + + [[package]] + name = "tqdm" + version = "4.67.1" + source = { registry = "https://pypi.org/simple" } + resolution-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'darwin'", + "platform_machine == 'x86_64' and sys_platform == 'linux'", + ] + sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } + wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, + ] + + [[package]] + name = "typing-extensions" + version = "4.15.0" + source = { registry = "https://pypi.org/simple" } + sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } + wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + ] + "# + ); + }); + + // Assert the idempotence of `uv lock` when resolving from the lockfile (`--locked`). + uv_snapshot!(context.filters(), context.lock().arg("--locked"), @" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Resolved 8 packages in [TIME] + "); + + Ok(()) +} + /// This tests a case where we declare an extra and a group as conflicting. #[test] fn mixed() -> Result<()> { From 7a852858d2f900bea491784a69df99b45fc408ca Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 23 Jun 2026 09:54:31 +0200 Subject: [PATCH 2/2] renaming --- crates/uv-resolver/src/lock/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/uv-resolver/src/lock/mod.rs b/crates/uv-resolver/src/lock/mod.rs index 94a8c3f5edf7f..f236d486865f7 100644 --- a/crates/uv-resolver/src/lock/mod.rs +++ b/crates/uv-resolver/src/lock/mod.rs @@ -1311,7 +1311,7 @@ impl Lock { } // The simplified marker space covered by this resolution. - let simplified_fork_environment = + let simplified_environment = SimplifiedMarkerTree::new(&self.requires_python, self.fork_markers_union()) .as_simplified_marker_tree(); @@ -1629,7 +1629,7 @@ impl Lock { for dist in &self.packages { packages.push(dist.to_toml( &self.requires_python, - simplified_fork_environment, + simplified_environment, &dist_count_by_name, )?); } @@ -3679,7 +3679,7 @@ impl Package { fn to_toml( &self, requires_python: &RequiresPython, - simplified_fork_environment: MarkerTree, + simplified_environment: MarkerTree, dist_count_by_name: &FxHashMap, ) -> Result { let mut table = Table::new(); @@ -3697,7 +3697,7 @@ impl Package { if !self.dependencies.is_empty() { let deps = each_element_on_its_line_array(self.dependencies.iter().map(|dep| { - dep.to_toml(simplified_fork_environment, dist_count_by_name) + dep.to_toml(simplified_environment, dist_count_by_name) .into_inline_table() })); table.insert("dependencies", value(deps)); @@ -3707,7 +3707,7 @@ impl Package { let mut optional_deps = Table::new(); for (extra, deps) in &self.optional_dependencies { let deps = each_element_on_its_line_array(deps.iter().map(|dep| { - dep.to_toml(simplified_fork_environment, dist_count_by_name) + dep.to_toml(simplified_environment, dist_count_by_name) .into_inline_table() })); if !deps.is_empty() { @@ -3723,7 +3723,7 @@ impl Package { let mut dependency_groups = Table::new(); for (extra, deps) in &self.dependency_groups { let deps = each_element_on_its_line_array(deps.iter().map(|dep| { - dep.to_toml(simplified_fork_environment, dist_count_by_name) + dep.to_toml(simplified_environment, dist_count_by_name) .into_inline_table() })); if !deps.is_empty() { @@ -5750,7 +5750,7 @@ impl Dependency { /// Returns the TOML representation of this dependency. fn to_toml( &self, - simplified_fork_environment: MarkerTree, + simplified_environment: MarkerTree, dist_count_by_name: &FxHashMap, ) -> Table { let mut table = Table::new(); @@ -5769,7 +5769,7 @@ impl Dependency { .simplified_marker .as_simplified_marker_tree() .negate() - .is_disjoint(simplified_fork_environment) + .is_disjoint(simplified_environment) && let Some(marker) = self.simplified_marker.try_to_string() { table.insert("marker", value(marker));