Respect existing versions in "lockfile" (#187)

Like `pip-compile`, we now respect existing versions from the
`requirements.txt` provided via `--output-file`, unless you pass a
`--upgrade` flag.

Closes #166.
This commit is contained in:
Charlie Marsh 2023-10-25 21:28:58 -07:00 committed by GitHub
parent 9f894213e0
commit 6faaf4bc24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 347 additions and 122 deletions

View file

@ -7,15 +7,16 @@ use anyhow::Result;
use colored::Colorize; use colored::Colorize;
use fs_err::File; use fs_err::File;
use itertools::Itertools; use itertools::Itertools;
use pubgrub::report::Reporter;
use tracing::debug;
use pep508_rs::Requirement; use pep508_rs::Requirement;
use platform_host::Platform; use platform_host::Platform;
use platform_tags::Tags; use platform_tags::Tags;
use pubgrub::report::Reporter;
use puffin_client::RegistryClientBuilder; use puffin_client::RegistryClientBuilder;
use puffin_dispatch::BuildDispatch; use puffin_dispatch::BuildDispatch;
use puffin_interpreter::Virtualenv; use puffin_interpreter::Virtualenv;
use puffin_resolver::ResolutionMode; use puffin_resolver::{Manifest, ResolutionMode};
use tracing::debug;
use crate::commands::{elapsed, ExitStatus}; use crate::commands::{elapsed, ExitStatus};
use crate::index_urls::IndexUrls; use crate::index_urls::IndexUrls;
@ -25,11 +26,13 @@ use crate::requirements::RequirementsSource;
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Resolve a set of requirements into a set of pinned versions. /// Resolve a set of requirements into a set of pinned versions.
#[allow(clippy::too_many_arguments)]
pub(crate) async fn pip_compile( pub(crate) async fn pip_compile(
requirements: &[RequirementsSource], requirements: &[RequirementsSource],
constraints: &[RequirementsSource], constraints: &[RequirementsSource],
output_file: Option<&Path>, output_file: Option<&Path>,
mode: ResolutionMode, resolution_mode: ResolutionMode,
upgrade_mode: UpgradeMode,
index_urls: Option<IndexUrls>, index_urls: Option<IndexUrls>,
cache: Option<&Path>, cache: Option<&Path>,
mut printer: Printer, mut printer: Printer,
@ -47,6 +50,19 @@ pub(crate) async fn pip_compile(
.map(RequirementsSource::requirements) .map(RequirementsSource::requirements)
.flatten_ok() .flatten_ok()
.collect::<Result<Vec<Requirement>>>()?; .collect::<Result<Vec<Requirement>>>()?;
let preferences: Vec<Requirement> = output_file
.filter(|_| upgrade_mode.is_prefer_pinned())
.filter(|output_file| output_file.exists())
.map(Path::to_path_buf)
.map(RequirementsSource::from)
.as_ref()
.map(RequirementsSource::requirements)
.transpose()?
.map(Iterator::collect)
.unwrap_or_default();
// Create a manifest of the requirements.
let manifest = Manifest::new(requirements, constraints, preferences, resolution_mode);
// Detect the current Python interpreter. // Detect the current Python interpreter.
let platform = Platform::current()?; let platform = Platform::current()?;
@ -88,9 +104,7 @@ pub(crate) async fn pip_compile(
// Resolve the dependencies. // Resolve the dependencies.
let resolver = puffin_resolver::Resolver::new( let resolver = puffin_resolver::Resolver::new(
requirements, manifest,
constraints,
mode,
venv.interpreter_info().markers(), venv.interpreter_info().markers(),
&tags, &tags,
&client, &client,
@ -155,3 +169,28 @@ pub(crate) async fn pip_compile(
Ok(ExitStatus::Success) Ok(ExitStatus::Success)
} }
/// Whether to allow package upgrades.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum UpgradeMode {
/// Allow package upgrades, ignoring the existing lockfile.
AllowUpgrades,
/// Prefer pinned versions from the existing lockfile, if possible.
PreferPinned,
}
impl UpgradeMode {
fn is_prefer_pinned(self) -> bool {
self == Self::PreferPinned
}
}
impl From<bool> for UpgradeMode {
fn from(value: bool) -> Self {
if value {
Self::AllowUpgrades
} else {
Self::PreferPinned
}
}
}

View file

@ -89,6 +89,10 @@ struct PipCompileArgs {
/// Ignore the package index, instead relying on local archives and caches. /// Ignore the package index, instead relying on local archives and caches.
#[clap(long, conflicts_with = "index_url", conflicts_with = "extra_index_url")] #[clap(long, conflicts_with = "index_url", conflicts_with = "extra_index_url")]
no_index: bool, no_index: bool,
/// Allow package upgrades, ignoring pinned versions in the existing output file.
#[clap(long)]
upgrade: bool,
} }
#[derive(Args)] #[derive(Args)]
@ -196,6 +200,7 @@ async fn main() -> ExitCode {
&constraints, &constraints,
args.output_file.as_deref(), args.output_file.as_deref(),
args.resolution.unwrap_or_default(), args.resolution.unwrap_or_default(),
args.upgrade.into(),
index_urls, index_urls,
cache_dir, cache_dir,
printer, printer,

View file

@ -18,7 +18,7 @@ use puffin_installer::{
uninstall, Downloader, Installer, PartitionedRequirements, RemoteDistribution, Unzipper, uninstall, Downloader, Installer, PartitionedRequirements, RemoteDistribution, Unzipper,
}; };
use puffin_interpreter::{InterpreterInfo, Virtualenv}; use puffin_interpreter::{InterpreterInfo, Virtualenv};
use puffin_resolver::{ResolutionMode, Resolver, WheelFinder}; use puffin_resolver::{Manifest, ResolutionMode, Resolver, WheelFinder};
use puffin_traits::BuildContext; use puffin_traits::BuildContext;
use tracing::debug; use tracing::debug;
@ -70,9 +70,12 @@ impl BuildContext for BuildDispatch {
self.interpreter_info.simple_version(), self.interpreter_info.simple_version(),
)?; )?;
let resolver = Resolver::new( let resolver = Resolver::new(
requirements.to_vec(), Manifest::new(
Vec::default(), requirements.to_vec(),
ResolutionMode::Highest, Vec::default(),
Vec::default(),
ResolutionMode::default(),
),
self.interpreter_info.markers(), self.interpreter_info.markers(),
&tags, &tags,
&self.client, &self.client,

View file

@ -66,6 +66,19 @@ impl From<SdistFile> for DistributionFile {
} }
} }
impl From<File> for DistributionFile {
fn from(file: File) -> Self {
if std::path::Path::new(file.filename.as_str())
.extension()
.map_or(false, |ext| ext.eq_ignore_ascii_case("whl"))
{
Self::Wheel(WheelFile::from(file))
} else {
Self::Sdist(SdistFile::from(file))
}
}
}
impl DistributionFile { impl DistributionFile {
pub(crate) fn filename(&self) -> &str { pub(crate) fn filename(&self) -> &str {
match self { match self {

View file

@ -1,6 +1,6 @@
pub use error::ResolveError; pub use error::ResolveError;
pub use resolution::PinnedPackage; pub use resolution::PinnedPackage;
pub use resolver::Resolver; pub use resolver::{Manifest, Resolver};
pub use selector::ResolutionMode; pub use selector::ResolutionMode;
pub use source_distribution::BuiltSourceDistributionCache; pub use source_distribution::BuiltSourceDistributionCache;
pub use wheel_finder::{Reporter, WheelFinder}; pub use wheel_finder::{Reporter, WheelFinder};

View file

@ -69,6 +69,11 @@ impl Resolution {
self.0.into_values().map(|package| package.file) self.0.into_values().map(|package| package.file)
} }
/// Return the pinned package for the given package name, if it exists.
pub fn get(&self, package_name: &PackageName) -> Option<&PinnedPackage> {
self.0.get(package_name)
}
/// Return the number of pinned packages in this resolution. /// Return the number of pinned packages in this resolution.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.0.len() self.0.len()

View file

@ -34,15 +34,39 @@ use crate::error::ResolveError;
use crate::pubgrub::package::PubGrubPackage; use crate::pubgrub::package::PubGrubPackage;
use crate::pubgrub::version::{PubGrubVersion, MIN_VERSION}; use crate::pubgrub::version::{PubGrubVersion, MIN_VERSION};
use crate::pubgrub::{iter_requirements, version_range}; use crate::pubgrub::{iter_requirements, version_range};
use crate::resolution::{Graph, Resolution}; use crate::resolution::Graph;
use crate::selector::{CandidateSelector, ResolutionMode}; use crate::selector::{CandidateSelector, ResolutionMode};
use crate::source_distribution::{download_and_build_sdist, read_dist_info}; use crate::source_distribution::{download_and_build_sdist, read_dist_info};
use crate::BuiltSourceDistributionCache; use crate::BuiltSourceDistributionCache;
/// A manifest of requirements, constraints, and preferences.
#[derive(Debug)]
pub struct Manifest {
requirements: Vec<Requirement>,
constraints: Vec<Requirement>,
preferences: Vec<Requirement>,
mode: ResolutionMode,
}
impl Manifest {
pub fn new(
requirements: Vec<Requirement>,
constraints: Vec<Requirement>,
preferences: Vec<Requirement>,
mode: ResolutionMode,
) -> Self {
Self {
requirements,
constraints,
preferences,
mode,
}
}
}
pub struct Resolver<'a, Context: BuildContext> { pub struct Resolver<'a, Context: BuildContext> {
requirements: Vec<Requirement>, requirements: Vec<Requirement>,
constraints: Vec<Requirement>, constraints: Vec<Requirement>,
resolution: Option<Resolution>,
markers: &'a MarkerEnvironment, markers: &'a MarkerEnvironment,
tags: &'a Tags, tags: &'a Tags,
client: &'a RegistryClient, client: &'a RegistryClient,
@ -54,20 +78,21 @@ pub struct Resolver<'a, Context: BuildContext> {
impl<'a, Context: BuildContext> Resolver<'a, Context> { impl<'a, Context: BuildContext> Resolver<'a, Context> {
/// Initialize a new resolver. /// Initialize a new resolver.
pub fn new( pub fn new(
requirements: Vec<Requirement>, manifest: Manifest,
constraints: Vec<Requirement>,
mode: ResolutionMode,
markers: &'a MarkerEnvironment, markers: &'a MarkerEnvironment,
tags: &'a Tags, tags: &'a Tags,
client: &'a RegistryClient, client: &'a RegistryClient,
build_context: &'a Context, build_context: &'a Context,
) -> Self { ) -> Self {
Self { Self {
selector: CandidateSelector::from_mode(mode, &requirements), selector: CandidateSelector::from_mode(
manifest.mode,
&manifest.requirements,
&manifest.preferences,
),
index: Arc::new(Index::default()), index: Arc::new(Index::default()),
resolution: None, requirements: manifest.requirements,
requirements, constraints: manifest.constraints,
constraints,
markers, markers,
tags, tags,
client, client,
@ -75,12 +100,6 @@ impl<'a, Context: BuildContext> Resolver<'a, Context> {
} }
} }
#[must_use]
pub fn with_resolution(mut self, resolution: Resolution) -> Self {
self.resolution = Some(resolution);
self
}
/// Resolve a set of requirements into a set of pinned versions. /// Resolve a set of requirements into a set of pinned versions.
pub async fn resolve(self) -> Result<Graph, ResolveError> { pub async fn resolve(self) -> Result<Graph, ResolveError> {
// A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version // A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version

View file

@ -1,11 +1,10 @@
use fxhash::FxHashSet; use fxhash::{FxHashMap, FxHashSet};
use pubgrub::range::Range; use pubgrub::range::Range;
use crate::distribution::DistributionFile; use pep508_rs::{Requirement, VersionOrUrl};
use pep508_rs::Requirement;
use puffin_package::package_name::PackageName; use puffin_package::package_name::PackageName;
use crate::distribution::DistributionFile;
use crate::pubgrub::version::PubGrubVersion; use crate::pubgrub::version::PubGrubVersion;
use crate::resolver::VersionMap; use crate::resolver::VersionMap;
@ -22,8 +21,10 @@ pub enum ResolutionMode {
LowestDirect, LowestDirect,
} }
#[derive(Debug, Clone)] /// Like [`ResolutionMode`], but with any additional information required to select a candidate,
pub(crate) enum CandidateSelector { /// like the set of direct dependencies.
#[derive(Debug)]
enum ResolutionStrategy {
/// Resolve the highest compatible version of each package. /// Resolve the highest compatible version of each package.
Highest, Highest,
/// Resolve the lowest compatible version of each package. /// Resolve the lowest compatible version of each package.
@ -33,9 +34,8 @@ pub(crate) enum CandidateSelector {
LowestDirect(FxHashSet<PackageName>), LowestDirect(FxHashSet<PackageName>),
} }
impl CandidateSelector { impl ResolutionStrategy {
/// Return a candidate selector for the given resolution mode. fn from_mode(mode: ResolutionMode, direct_dependencies: &[Requirement]) -> Self {
pub(crate) fn from_mode(mode: ResolutionMode, direct_dependencies: &[Requirement]) -> Self {
match mode { match mode {
ResolutionMode::Highest => Self::Highest, ResolutionMode::Highest => Self::Highest,
ResolutionMode::Lowest => Self::Lowest, ResolutionMode::Lowest => Self::Lowest,
@ -49,26 +49,87 @@ impl CandidateSelector {
} }
} }
/// A set of pinned packages that should be preserved during resolution, if possible.
#[derive(Debug)]
struct Preferences(FxHashMap<PackageName, PubGrubVersion>);
impl Preferences {
fn get(&self, package_name: &PackageName) -> Option<&PubGrubVersion> {
self.0.get(package_name)
}
}
impl From<&[Requirement]> for Preferences {
fn from(requirements: &[Requirement]) -> Self {
Self(
requirements
.iter()
.filter_map(|requirement| {
let Some(VersionOrUrl::VersionSpecifier(version_specifiers)) =
requirement.version_or_url.as_ref()
else {
return None;
};
let [version_specifier] = &**version_specifiers else {
return None;
};
let package_name = PackageName::normalize(&requirement.name);
let version = PubGrubVersion::from(version_specifier.version().clone());
Some((package_name, version))
})
.collect(),
)
}
}
#[derive(Debug)]
pub(crate) struct CandidateSelector {
strategy: ResolutionStrategy,
preferences: Preferences,
}
impl CandidateSelector {
/// Return a candidate selector for the given resolution mode.
pub(crate) fn from_mode(
mode: ResolutionMode,
direct_dependencies: &[Requirement],
resolution: &[Requirement],
) -> Self {
Self {
strategy: ResolutionStrategy::from_mode(mode, direct_dependencies),
preferences: Preferences::from(resolution),
}
}
}
impl CandidateSelector { impl CandidateSelector {
/// Select a [`Candidate`] from a set of candidate versions and files. /// Select a [`Candidate`] from a set of candidate versions and files.
pub(crate) fn select<'a>( pub(crate) fn select(
&self, &self,
package_name: &'a PackageName, package_name: &PackageName,
range: &'a Range<PubGrubVersion>, range: &Range<PubGrubVersion>,
version_map: &'a VersionMap, version_map: &VersionMap,
) -> Option<Candidate<'a>> { ) -> Option<Candidate> {
match self { if let Some(version) = self.preferences.get(package_name) {
CandidateSelector::Highest => { if range.contains(version) {
CandidateSelector::select_highest(package_name, range, version_map) if let Some(file) = version_map.get(version) {
return Some(Candidate {
package_name: package_name.clone(),
version: version.clone(),
file: file.clone(),
});
}
} }
CandidateSelector::Lowest => { }
CandidateSelector::select_lowest(package_name, range, version_map)
} match &self.strategy {
CandidateSelector::LowestDirect(direct_dependencies) => { ResolutionStrategy::Highest => Self::select_highest(package_name, range, version_map),
ResolutionStrategy::Lowest => Self::select_lowest(package_name, range, version_map),
ResolutionStrategy::LowestDirect(direct_dependencies) => {
if direct_dependencies.contains(package_name) { if direct_dependencies.contains(package_name) {
CandidateSelector::select_lowest(package_name, range, version_map) Self::select_lowest(package_name, range, version_map)
} else { } else {
CandidateSelector::select_highest(package_name, range, version_map) Self::select_highest(package_name, range, version_map)
} }
} }
} }
@ -76,27 +137,27 @@ impl CandidateSelector {
/// Select the highest-compatible [`Candidate`] from a set of candidate versions and files, /// Select the highest-compatible [`Candidate`] from a set of candidate versions and files,
/// preferring wheels over sdists. /// preferring wheels over sdists.
fn select_highest<'a>( fn select_highest(
package_name: &'a PackageName, package_name: &PackageName,
range: &'a Range<PubGrubVersion>, range: &Range<PubGrubVersion>,
version_map: &'a VersionMap, version_map: &VersionMap,
) -> Option<Candidate<'a>> { ) -> Option<Candidate> {
let mut sdist = None; let mut sdist = None;
for (version, file) in version_map.iter().rev() { for (version, file) in version_map.iter().rev() {
if range.contains(version) { if range.contains(version) {
match file { match file {
DistributionFile::Wheel(_) => { DistributionFile::Wheel(_) => {
return Some(Candidate { return Some(Candidate {
package_name, package_name: package_name.clone(),
version, version: version.clone(),
file, file: file.clone(),
}); });
} }
DistributionFile::Sdist(_) => { DistributionFile::Sdist(_) => {
sdist = Some(Candidate { sdist = Some(Candidate {
package_name, package_name: package_name.clone(),
version, version: version.clone(),
file, file: file.clone(),
}); });
} }
} }
@ -107,27 +168,27 @@ impl CandidateSelector {
/// Select the highest-compatible [`Candidate`] from a set of candidate versions and files, /// Select the highest-compatible [`Candidate`] from a set of candidate versions and files,
/// preferring wheels over sdists. /// preferring wheels over sdists.
fn select_lowest<'a>( fn select_lowest(
package_name: &'a PackageName, package_name: &PackageName,
range: &'a Range<PubGrubVersion>, range: &Range<PubGrubVersion>,
version_map: &'a VersionMap, version_map: &VersionMap,
) -> Option<Candidate<'a>> { ) -> Option<Candidate> {
let mut sdist = None; let mut sdist = None;
for (version, file) in version_map { for (version, file) in version_map {
if range.contains(version) { if range.contains(version) {
match file { match file {
DistributionFile::Wheel(_) => { DistributionFile::Wheel(_) => {
return Some(Candidate { return Some(Candidate {
package_name, package_name: package_name.clone(),
version, version: version.clone(),
file, file: file.clone(),
}); });
} }
DistributionFile::Sdist(_) => { DistributionFile::Sdist(_) => {
sdist = Some(Candidate { sdist = Some(Candidate {
package_name, package_name: package_name.clone(),
version, version: version.clone(),
file, file: file.clone(),
}); });
} }
} }
@ -138,11 +199,11 @@ impl CandidateSelector {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct Candidate<'a> { pub(crate) struct Candidate {
/// The name of the package. /// The name of the package.
pub(crate) package_name: &'a PackageName, pub(crate) package_name: PackageName,
/// The version of the package. /// The version of the package.
pub(crate) version: &'a PubGrubVersion, pub(crate) version: PubGrubVersion,
/// The file of the package. /// The file of the package.
pub(crate) file: &'a DistributionFile, pub(crate) file: DistributionFile,
} }

View file

@ -16,7 +16,7 @@ use platform_host::{Arch, Os, Platform};
use platform_tags::Tags; use platform_tags::Tags;
use puffin_client::RegistryClientBuilder; use puffin_client::RegistryClientBuilder;
use puffin_interpreter::{InterpreterInfo, Virtualenv}; use puffin_interpreter::{InterpreterInfo, Virtualenv};
use puffin_resolver::{ResolutionMode, Resolver}; use puffin_resolver::{Manifest, ResolutionMode, Resolver};
use puffin_traits::BuildContext; use puffin_traits::BuildContext;
struct DummyContext; struct DummyContext;
@ -66,15 +66,15 @@ async fn pylint() -> Result<()> {
let requirements = vec![Requirement::from_str("pylint==2.3.0").unwrap()]; let requirements = vec![Requirement::from_str("pylint==2.3.0").unwrap()];
let constraints = vec![]; let constraints = vec![];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -90,15 +90,15 @@ async fn black() -> Result<()> {
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![]; let constraints = vec![];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -114,15 +114,15 @@ async fn black_colorama() -> Result<()> {
let requirements = vec![Requirement::from_str("black[colorama]<=23.9.1").unwrap()]; let requirements = vec![Requirement::from_str("black[colorama]<=23.9.1").unwrap()];
let constraints = vec![]; let constraints = vec![];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -138,15 +138,15 @@ async fn black_python_310() -> Result<()> {
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![]; let constraints = vec![];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_310,
&TAGS_310,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_310, &TAGS_310, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -164,15 +164,15 @@ async fn black_mypy_extensions() -> Result<()> {
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![Requirement::from_str("mypy-extensions<1").unwrap()]; let constraints = vec![Requirement::from_str("mypy-extensions<1").unwrap()];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -190,15 +190,15 @@ async fn black_mypy_extensions_extra() -> Result<()> {
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![Requirement::from_str("mypy-extensions[extra]<1").unwrap()]; let constraints = vec![Requirement::from_str("mypy-extensions[extra]<1").unwrap()];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -216,15 +216,15 @@ async fn black_flake8() -> Result<()> {
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![Requirement::from_str("flake8<1").unwrap()]; let constraints = vec![Requirement::from_str("flake8<1").unwrap()];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::default(), ResolutionMode::default(),
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -240,15 +240,15 @@ async fn black_lowest() -> Result<()> {
let requirements = vec![Requirement::from_str("black>21").unwrap()]; let requirements = vec![Requirement::from_str("black>21").unwrap()];
let constraints = vec![]; let constraints = vec![];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::Lowest, ResolutionMode::Lowest,
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);
@ -264,15 +264,63 @@ async fn black_lowest_direct() -> Result<()> {
let requirements = vec![Requirement::from_str("black>21").unwrap()]; let requirements = vec![Requirement::from_str("black>21").unwrap()];
let constraints = vec![]; let constraints = vec![];
let resolver = Resolver::new( let preferences = vec![];
let manifest = Manifest::new(
requirements, requirements,
constraints, constraints,
preferences,
ResolutionMode::LowestDirect, ResolutionMode::LowestDirect,
&MARKERS_311,
&TAGS_311,
&client,
&DummyContext,
); );
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution);
Ok(())
}
#[tokio::test]
async fn black_respect_preference() -> Result<()> {
colored::control::set_override(false);
let client = RegistryClientBuilder::default().build();
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![];
let preferences = vec![Requirement::from_str("black==23.9.0").unwrap()];
let manifest = Manifest::new(
requirements,
constraints,
preferences,
ResolutionMode::default(),
);
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution);
Ok(())
}
#[tokio::test]
async fn black_ignore_preference() -> Result<()> {
colored::control::set_override(false);
let client = RegistryClientBuilder::default().build();
let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()];
let constraints = vec![];
let preferences = vec![Requirement::from_str("black==23.9.2").unwrap()];
let manifest = Manifest::new(
requirements,
constraints,
preferences,
ResolutionMode::default(),
);
let resolver = Resolver::new(manifest, &MARKERS_311, &TAGS_311, &client, &DummyContext);
let resolution = resolver.resolve().await?; let resolution = resolver.resolve().await?;
insta::assert_display_snapshot!(resolution); insta::assert_display_snapshot!(resolution);

View file

@ -0,0 +1,16 @@
---
source: crates/puffin-resolver/tests/resolver.rs
expression: resolution
---
black==23.9.1
click==8.1.7
# via black
mypy-extensions==1.0.0
# via black
packaging==23.2
# via black
pathspec==0.11.2
# via black
platformdirs==3.11.0
# via black

View file

@ -0,0 +1,16 @@
---
source: crates/puffin-resolver/tests/resolver.rs
expression: resolution
---
black==23.9.0
click==8.1.7
# via black
mypy-extensions==1.0.0
# via black
packaging==23.2
# via black
pathspec==0.11.2
# via black
platformdirs==3.11.0
# via black