Skip to content

Commit 1a61f34

Browse files
committed
Add note about using the explicit bounds over the preferences
1 parent 527b855 commit 1a61f34

File tree

3 files changed

+83
-8
lines changed

3 files changed

+83
-8
lines changed

crates/uv-workspace/src/pyproject_mut.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
use itertools::Itertools;
2+
use serde::{Deserialize, Serialize};
3+
use std::fmt::{Display, Formatter};
14
use std::path::Path;
25
use std::str::FromStr;
36
use std::{fmt, iter, mem};
4-
5-
use itertools::Itertools;
6-
use serde::{Deserialize, Serialize};
77
use thiserror::Error;
88
use toml_edit::{
99
Array, ArrayOfTables, DocumentMut, Formatted, Item, RawString, Table, TomlError, Value,
@@ -112,6 +112,17 @@ pub enum AddBoundsKind {
112112
Exact,
113113
}
114114

115+
impl Display for AddBoundsKind {
116+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117+
match self {
118+
Self::Lower => write!(f, "lower"),
119+
Self::Major => write!(f, "major"),
120+
Self::Minor => write!(f, "minor"),
121+
Self::Exact => write!(f, "exact"),
122+
}
123+
}
124+
}
125+
115126
impl AddBoundsKind {
116127
fn specifiers(self, version: Version) -> VersionSpecifiers {
117128
// Nomenclature: "major" is the most significant component of the version, "minor" is the
@@ -680,7 +691,7 @@ impl PyProjectTomlMut {
680691
dependency_type: &DependencyType,
681692
index: usize,
682693
version: Version,
683-
bound_kind: &AddBoundsKind,
694+
bound_kind: AddBoundsKind,
684695
) -> Result<(), Error> {
685696
let group = match dependency_type {
686697
DependencyType::Production => self.dependencies_array()?,

crates/uv/src/commands/project/add.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ pub(crate) async fn add(
527527
locked,
528528
&dependency_type,
529529
raw,
530-
&bounds.unwrap_or_default(),
530+
bounds,
531531
constraints,
532532
&settings,
533533
&network_settings,
@@ -752,7 +752,7 @@ async fn lock_and_sync(
752752
locked: bool,
753753
dependency_type: &DependencyType,
754754
raw: bool,
755-
bound_kind: &AddBoundsKind,
755+
bound_kind: Option<AddBoundsKind>,
756756
constraints: Vec<NameRequirementSpecification>,
757757
settings: &ResolverInstallerSettings,
758758
network_settings: &NetworkSettings,
@@ -828,6 +828,15 @@ async fn lock_and_sync(
828828
None => true,
829829
};
830830
if !is_empty {
831+
if let Some(bound_kind) = bound_kind {
832+
writeln!(
833+
printer.stderr(),
834+
"{} Using explicit requirement `{}` over bounds preference `{}`",
835+
"note:".bold(),
836+
edit.requirement,
837+
bound_kind
838+
)?;
839+
}
831840
continue;
832841
}
833842

@@ -840,7 +849,12 @@ async fn lock_and_sync(
840849
// For example, convert `1.2.3+local` to `1.2.3`.
841850
let minimum = (*minimum).clone().without_local();
842851

843-
toml.set_dependency_bound(&edit.dependency_type, *index, minimum, bound_kind)?;
852+
toml.set_dependency_bound(
853+
&edit.dependency_type,
854+
*index,
855+
minimum,
856+
bound_kind.unwrap_or_default(),
857+
)?;
844858

845859
modified = true;
846860
}

crates/uv/tests/it/edit.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11727,7 +11727,7 @@ fn add_optional_normalize() -> Result<()> {
1172711727
Ok(())
1172811728
}
1172911729

11730-
/// Add a PyPI requirement with the given bounds.
11730+
/// Test `uv add` with different kinds of bounds and constraints.
1173111731
#[test]
1173211732
fn add_bounds() -> Result<()> {
1173311733
let context = TestContext::new("3.12");
@@ -11905,3 +11905,53 @@ fn add_bounds() -> Result<()> {
1190511905

1190611906
Ok(())
1190711907
}
11908+
11909+
/// Hint that we're using an explicit bound over the preferred bounds.
11910+
#[test]
11911+
fn add_bounds_requirement_over_bounds_kind() -> Result<()> {
11912+
let context = TestContext::new("3.12");
11913+
11914+
// Set bounds in `uv.toml`
11915+
let uv_toml = context.temp_dir.child("uv.toml");
11916+
uv_toml.write_str(indoc! {r#"
11917+
add-bounds = "exact"
11918+
"#})?;
11919+
let pyproject_toml = context.temp_dir.child("pyproject.toml");
11920+
pyproject_toml.write_str(indoc! {r#"
11921+
[project]
11922+
name = "project"
11923+
version = "0.1.0"
11924+
requires-python = ">=3.12"
11925+
"#})?;
11926+
11927+
uv_snapshot!(context.filters(), context.add().arg("anyio==4.2").arg("idna").arg("--bounds").arg("minor").arg("--preview"), @r"
11928+
success: true
11929+
exit_code: 0
11930+
----- stdout -----
11931+
11932+
----- stderr -----
11933+
Resolved 4 packages in [TIME]
11934+
note: Using explicit requirement `anyio==4.2` over bounds preference `minor`
11935+
Prepared 3 packages in [TIME]
11936+
Installed 3 packages in [TIME]
11937+
+ anyio==4.2.0
11938+
+ idna==3.6
11939+
+ sniffio==1.3.1
11940+
");
11941+
11942+
let pyproject_toml = context.read("pyproject.toml");
11943+
assert_snapshot!(
11944+
pyproject_toml, @r#"
11945+
[project]
11946+
name = "project"
11947+
version = "0.1.0"
11948+
requires-python = ">=3.12"
11949+
dependencies = [
11950+
"anyio==4.2",
11951+
"idna>=3.6,<3.7",
11952+
]
11953+
"#
11954+
);
11955+
11956+
Ok(())
11957+
}

0 commit comments

Comments
 (0)