Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
use uv_redacted::DisplaySafeUrl;
use uv_resolver::{
AnnotationStyle, ExcludeNewerOverride, ExcludeNewerPackageEntry, ForkStrategy, PrereleaseMode,
ResolutionMode,
PrereleasePackageEntry, ResolutionMode,
};
use uv_settings::PythonInstallMirrors;
use uv_static::EnvVars;
Expand Down Expand Up @@ -6743,6 +6743,15 @@ pub struct VersionSelectionArgs {
)]
prerelease: Option<PrereleaseMode>,

/// The strategy to use when considering pre-release versions for a specific package.
///
/// Accepts package-mode pairs in the format `PACKAGE=MODE`, where `MODE` is any value
/// accepted by `--prerelease`.
///
/// May be provided multiple times for different packages.
#[arg(long, help_heading = "Resolver options", value_hint = ValueHint::Other)]
prerelease_package: Option<Vec<PrereleasePackageEntry>>,

#[arg(long, hide = true, help_heading = "Resolver options")]
pre: bool,

Expand Down
10 changes: 9 additions & 1 deletion crates/uv-cli/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use anyhow::bail;
use uv_cache::Refresh;
use uv_configuration::{BuildIsolation, Reinstall, Upgrade};
use uv_distribution_types::{ConfigSettings, PackageConfigSettings, Requirement};
use uv_resolver::{ExcludeNewerPackage, PrereleaseMode};
use uv_resolver::{ExcludeNewerPackage, PrereleaseMode, PrereleasePackage};
use uv_settings::{
Combine, EnvFlag, IndexOptions, PipOptions, ResolverInstallerOptions, ResolverOptions,
};
Expand Down Expand Up @@ -254,6 +254,7 @@ impl TryFrom<ResolverArgs> for PipOptions {
VersionSelectionArgs {
resolution,
prerelease,
prerelease_package,
pre,
fork_strategy,
},
Expand Down Expand Up @@ -300,6 +301,7 @@ impl TryFrom<ResolverArgs> for PipOptions {
} else {
prerelease
},
prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
config_settings_package: config_settings_package.map(|config_settings| {
Expand Down Expand Up @@ -418,6 +420,7 @@ impl TryFrom<ResolverInstallerArgs> for PipOptions {
VersionSelectionArgs {
resolution,
prerelease,
prerelease_package,
pre,
fork_strategy,
},
Expand Down Expand Up @@ -470,6 +473,7 @@ impl TryFrom<ResolverInstallerArgs> for PipOptions {
} else {
prerelease
},
prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
fork_strategy,
config_settings: config_setting
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
Expand Down Expand Up @@ -588,6 +592,7 @@ pub fn resolver_options(
VersionSelectionArgs {
resolution,
prerelease,
prerelease_package,
pre,
fork_strategy,
},
Expand Down Expand Up @@ -638,6 +643,7 @@ pub fn resolver_options(
} else {
prerelease
},
prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
fork_strategy,
dependency_metadata: None,
config_settings: config_setting
Expand Down Expand Up @@ -706,6 +712,7 @@ pub fn resolver_installer_options(
VersionSelectionArgs {
resolution,
prerelease,
prerelease_package,
pre,
fork_strategy,
},
Expand Down Expand Up @@ -765,6 +772,7 @@ pub fn resolver_installer_options(
} else {
prerelease
},
prerelease_package: prerelease_package.map(PrereleasePackage::from_iter),
fork_strategy,
dependency_metadata: None,
config_settings: config_setting
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-resolver/src/candidate_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ impl CandidateSelector {
env,
options.dependency_mode,
),
prerelease_strategy: PrereleaseStrategy::from_mode(
options.prerelease_mode,
prerelease_strategy: PrereleaseStrategy::from_prerelease(
&options.prerelease,
manifest,
env,
options.dependency_mode,
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use lock::{
pub use manifest::Manifest;
pub use options::{Flexibility, Options, OptionsBuilder};
pub use preferences::{Preference, PreferenceError, Preferences};
pub use prerelease::PrereleaseMode;
pub use prerelease::{Prerelease, PrereleaseMode, PrereleasePackage, PrereleasePackageEntry};
pub use pubgrub::PubGrubHint;
pub use python_requirement::PythonRequirement;
pub use resolution::{
Expand Down
42 changes: 33 additions & 9 deletions crates/uv-resolver/src/lock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ use crate::resolution::{AnnotatedDist, ResolutionGraphNode};
use crate::universal_marker::{ConflictMarker, UniversalMarker};
use crate::{
ExcludeNewer, ExcludeNewerOverride, ExcludeNewerPackage, ExcludeNewerSpan, ExcludeNewerValue,
InMemoryIndex, MetadataResponse, PrereleaseMode, ResolutionMode, ResolverOutput,
InMemoryIndex, MetadataResponse, Prerelease, PrereleaseMode, PrereleasePackage, ResolutionMode,
ResolverOutput,
};

pub(crate) mod export;
Expand Down Expand Up @@ -1082,7 +1083,7 @@ impl Lock {

let options = ResolverOptions {
resolution_mode: resolution.options.resolution_mode,
prerelease_mode: resolution.options.prerelease_mode,
prerelease: resolution.options.prerelease.clone(),
fork_strategy: resolution.options.fork_strategy,
exclude_newer: resolution.options.exclude_newer.clone(),
};
Expand Down Expand Up @@ -1374,7 +1375,12 @@ impl Lock {

/// Returns the pre-release mode used to generate this lock.
pub fn prerelease_mode(&self) -> PrereleaseMode {
self.options.prerelease_mode
self.options.prerelease.global
}

/// Returns the pre-release policy used to generate this lock.
pub fn prerelease(&self) -> &Prerelease {
&self.options.prerelease
}

/// Returns the multi-version mode used to generate this lock.
Expand Down Expand Up @@ -3196,8 +3202,8 @@ pub enum SatisfiesResult<'lock> {
struct ResolverOptions {
/// The [`ResolutionMode`] used to generate this lock.
resolution_mode: ResolutionMode,
/// The [`PrereleaseMode`] used to generate this lock.
prerelease_mode: PrereleaseMode,
/// The [`Prerelease`] policy used to generate this lock.
prerelease: Prerelease,
/// The [`ForkStrategy`] used to generate this lock.
fork_strategy: ForkStrategy,
/// The [`ExcludeNewer`] setting used to generate this lock.
Expand All @@ -3211,9 +3217,9 @@ struct ResolverOptionsWire {
/// The [`ResolutionMode`] used to generate this lock.
#[serde(default)]
resolution_mode: ResolutionMode,
/// The [`PrereleaseMode`] used to generate this lock.
#[serde(default)]
prerelease_mode: PrereleaseMode,
/// The [`Prerelease`] policy used to generate this lock.
#[serde(flatten)]
prerelease: PrereleaseWire,
/// The [`ForkStrategy`] used to generate this lock.
#[serde(default)]
fork_strategy: ForkStrategy,
Expand All @@ -3222,6 +3228,24 @@ struct ResolverOptionsWire {
exclude_newer: ExcludeNewerWire,
}

#[derive(Clone, Debug, Default, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
struct PrereleaseWire {
#[serde(default)]
prerelease_mode: PrereleaseMode,
#[serde(default)]
prerelease_package: PrereleasePackage,
}

impl From<PrereleaseWire> for Prerelease {
fn from(wire: PrereleaseWire) -> Self {
Self {
global: wire.prerelease_mode,
package: wire.prerelease_package,
}
}
}

#[expect(clippy::struct_field_names)]
#[derive(Clone, Debug, Default, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
Expand Down Expand Up @@ -3475,7 +3499,7 @@ impl TryFrom<LockWire> for Lock {
}
let options = ResolverOptions {
resolution_mode: options_wire.resolution_mode,
prerelease_mode: options_wire.prerelease_mode,
prerelease: options_wire.prerelease.into(),
fork_strategy: options_wire.fork_strategy,
exclude_newer: options_wire.exclude_newer.into(),
};
Expand Down
16 changes: 13 additions & 3 deletions crates/uv-resolver/src/lock/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ fn write_lock(writer: &mut LockWriter, lock: &Lock) -> Result<(), WriteError> {

fn write_options(writer: &mut LockWriter, options: &ResolverOptions) -> Result<(), WriteError> {
let has_options = options.resolution_mode != ResolutionMode::default()
|| options.prerelease_mode != PrereleaseMode::default()
|| options.prerelease.global != PrereleaseMode::default()
|| !options.prerelease.package.is_empty()
|| options.fork_strategy != ForkStrategy::default()
|| !options.exclude_newer.is_empty();
if !has_options {
Expand All @@ -147,8 +148,8 @@ fn write_options(writer: &mut LockWriter, options: &ResolverOptions) -> Result<(
if options.resolution_mode != ResolutionMode::default() {
writer.key_value("resolution-mode", options.resolution_mode.to_string())?;
}
if options.prerelease_mode != PrereleaseMode::default() {
writer.key_value("prerelease-mode", options.prerelease_mode.to_string())?;
if options.prerelease.global != PrereleaseMode::default() {
writer.key_value("prerelease-mode", options.prerelease.global.to_string())?;
}
if options.fork_strategy != ForkStrategy::default() {
writer.key_value("fork-strategy", options.fork_strategy.to_string())?;
Expand All @@ -166,6 +167,15 @@ fn write_options(writer: &mut LockWriter, options: &ResolverOptions) -> Result<(
}
}

if !options.prerelease.package.is_empty() {
writer.table(&["options", "prerelease-package"])?;
let mut packages = options.prerelease.package.iter().collect::<Vec<_>>();
packages.sort_unstable_by_key(|(name, _)| *name);
for (name, mode) in packages {
writer.key_value(name.as_ref(), mode.to_string())?;
}
}

if !exclude_newer.package.is_empty() {
writer.table(&["options", "exclude-newer-package"])?;
for (name, setting) in &exclude_newer.package {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ Ok(
},
options: ResolverOptions {
resolution_mode: Highest,
prerelease_mode: IfNecessary,
prerelease: Prerelease {
global: IfNecessary,
package: PrereleasePackage(
{},
),
},
fork_strategy: RequiresPython,
exclude_newer: ExcludeNewer {
global: None,
Expand Down
Loading
Loading