diff --git a/Cargo.lock b/Cargo.lock index fffe7dce8..ce0be253b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -737,6 +737,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.28" @@ -1795,6 +1801,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.0.2", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2139,9 +2155,11 @@ dependencies = [ "bitflags 2.4.1", "colored", "futures", + "insta", "once_cell", "pep440_rs 0.3.12", "pep508_rs", + "petgraph", "platform-host", "platform-tags", "pubgrub", diff --git a/crates/puffin-cli/src/commands/pip_compile.rs b/crates/puffin-cli/src/commands/pip_compile.rs index 6de07c0f5..b7ecc675c 100644 --- a/crates/puffin-cli/src/commands/pip_compile.rs +++ b/crates/puffin-cli/src/commands/pip_compile.rs @@ -71,11 +71,11 @@ pub(crate) async fn pip_compile( derivation_tree.collapse_no_versions(); #[allow(clippy::print_stderr)] { - eprintln!("{}: {}", "error".red().bold(), "no solution found".bold()); - eprintln!( - "{}", - pubgrub::report::DefaultStringReporter::report(&derivation_tree) - ); + let report = miette::Report::msg(pubgrub::report::DefaultStringReporter::report( + &derivation_tree, + )) + .context("No solution found when resolving dependencies:"); + eprint!("{report:?}"); } return Ok(ExitStatus::Failure); } @@ -111,7 +111,7 @@ pub(crate) async fn pip_compile( "{}", format!("# {}", env::args().join(" ")).green() )?; - writeln!(writer, "{resolution}")?; + write!(writer, "{resolution}")?; Ok(ExitStatus::Success) } diff --git a/crates/puffin-cli/src/commands/pip_sync.rs b/crates/puffin-cli/src/commands/pip_sync.rs index e9926aca9..ed0cc01f5 100644 --- a/crates/puffin-cli/src/commands/pip_sync.rs +++ b/crates/puffin-cli/src/commands/pip_sync.rs @@ -16,7 +16,6 @@ use puffin_installer::{ }; use puffin_interpreter::PythonExecutable; use puffin_package::package_name::PackageName; -use puffin_resolver::Resolution; use crate::commands::reporters::{ DownloadReporter, InstallReporter, UnzipReporter, WheelFinderReporter, @@ -93,8 +92,8 @@ pub(crate) async fn sync_requirements( let client = PypiClientBuilder::default().cache(cache).build(); // Resolve the dependencies. - let resolution = if remote.is_empty() { - Resolution::default() + let remote = if remote.is_empty() { + Vec::new() } else { let start = std::time::Instant::now(); @@ -115,33 +114,32 @@ pub(crate) async fn sync_requirements( )?; resolution + .into_files() + .map(RemoteDistribution::from_file) + .collect::>>()? }; // Download any missing distributions. let staging = tempfile::tempdir()?; - let uncached = resolution - .into_files() - .map(RemoteDistribution::from_file) - .collect::>>()?; - let downloads = if uncached.is_empty() { + let downloads = if remote.is_empty() { vec![] } else { let start = std::time::Instant::now(); let downloader = puffin_installer::Downloader::new(&client, cache) - .with_reporter(DownloadReporter::from(printer).with_length(uncached.len() as u64)); + .with_reporter(DownloadReporter::from(printer).with_length(remote.len() as u64)); let downloads = downloader - .download(&uncached, cache.unwrap_or(staging.path())) + .download(&remote, cache.unwrap_or(staging.path())) .await?; - let s = if uncached.len() == 1 { "" } else { "s" }; + let s = if remote.len() == 1 { "" } else { "s" }; writeln!( printer, "{}", format!( "Downloaded {} in {}", - format!("{} package{}", uncached.len(), s).bold(), + format!("{} package{}", remote.len(), s).bold(), elapsed(start.elapsed()) ) .dimmed() diff --git a/crates/puffin-resolver/Cargo.toml b/crates/puffin-resolver/Cargo.toml index b2de93e2c..b189d379e 100644 --- a/crates/puffin-resolver/Cargo.toml +++ b/crates/puffin-resolver/Cargo.toml @@ -28,6 +28,8 @@ thiserror = { workspace = true } tokio = { workspace = true } tracing = { workspace = true } waitmap = { workspace = true } +petgraph = "0.6.4" [dev-dependencies] once_cell = { version = "1.18.0" } +insta = { version = "1.34.0" } diff --git a/crates/puffin-resolver/src/lib.rs b/crates/puffin-resolver/src/lib.rs index 2bf55e9ed..c5fc93bbe 100644 --- a/crates/puffin-resolver/src/lib.rs +++ b/crates/puffin-resolver/src/lib.rs @@ -1,5 +1,5 @@ pub use error::ResolveError; -pub use resolution::{PinnedPackage, Resolution}; +pub use resolution::PinnedPackage; pub use resolver::Resolver; pub use wheel_finder::{Reporter, WheelFinder}; diff --git a/crates/puffin-resolver/src/pubgrub/version.rs b/crates/puffin-resolver/src/pubgrub/version.rs index 0829472b2..5f6ca2435 100644 --- a/crates/puffin-resolver/src/pubgrub/version.rs +++ b/crates/puffin-resolver/src/pubgrub/version.rs @@ -38,12 +38,6 @@ impl pubgrub::version::Version for PubGrubVersion { } } -// impl From for Range { -// fn from(value: PubGrubVersion) -> Self { -// Range::from(value) -// } -// } - impl<'a> From<&'a PubGrubVersion> for &'a pep440_rs::Version { fn from(version: &'a PubGrubVersion) -> Self { &version.0 diff --git a/crates/puffin-resolver/src/resolution.rs b/crates/puffin-resolver/src/resolution.rs index ed7eed29d..1d38e2a81 100644 --- a/crates/puffin-resolver/src/resolution.rs +++ b/crates/puffin-resolver/src/resolution.rs @@ -1,53 +1,17 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; + +use colored::Colorize; +use petgraph::visit::EdgeRef; +use pubgrub::range::Range; +use pubgrub::solver::{Kind, State}; +use pubgrub::type_aliases::SelectedDependencies; use pep440_rs::Version; use puffin_client::File; use puffin_package::package_name::PackageName; -#[derive(Debug, Default)] -pub struct Resolution(BTreeMap); - -impl Resolution { - /// Create a new resolution from the given pinned packages. - pub(crate) fn new(packages: BTreeMap) -> Self { - Self(packages) - } - - /// Iterate over the pinned packages in this resolution. - pub fn iter(&self) -> impl Iterator { - self.0.iter() - } - - /// Iterate over the wheels in this resolution. - pub fn into_files(self) -> impl Iterator { - self.0.into_values().map(|package| package.file) - } - - /// Return the number of pinned packages in this resolution. - pub fn len(&self) -> usize { - self.0.len() - } - - /// Return `true` if there are no pinned packages in this resolution. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -/// Write the resolution in the `{name}=={version}` format of requirements.txt that pip uses. -impl std::fmt::Display for Resolution { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut first = true; - for (name, pin) in self.iter() { - if !first { - writeln!(f)?; - } - first = false; - write!(f, "{}=={}", name, pin.version())?; - } - Ok(()) - } -} +use crate::pubgrub::package::PubGrubPackage; +use crate::pubgrub::version::PubGrubVersion; /// A package pinned at a specific version. #[derive(Debug)] @@ -82,3 +46,146 @@ impl PinnedPackage { &self.file } } + +/// A set of packages pinned at specific versions. +#[derive(Debug, Default)] +pub struct Resolution(BTreeMap); + +impl Resolution { + /// Create a new resolution from the given pinned packages. + pub(crate) fn new(packages: BTreeMap) -> Self { + Self(packages) + } + + /// Iterate over the pinned packages in this resolution. + pub fn iter(&self) -> impl Iterator { + self.0.iter() + } + + /// Iterate over the wheels in this resolution. + pub fn into_files(self) -> impl Iterator { + self.0.into_values().map(|package| package.file) + } + + /// Return the number of pinned packages in this resolution. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Return `true` if there are no pinned packages in this resolution. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +/// A complete resolution graph in which every node represents a pinned package and every edge +/// represents a dependency between two pinned packages. +#[derive(Debug)] +pub struct Graph(petgraph::graph::Graph); + +impl Graph { + /// Create a new graph from the resolved `PubGrub` state. + pub fn from_state( + selection: &SelectedDependencies, + pins: &HashMap>, + state: &State>, + ) -> Self { + // TODO(charlie): petgraph is a really heavy and unnecessary dependency here. We should + // write our own graph, given that our requirements are so simple. + let mut graph = petgraph::graph::Graph::with_capacity(selection.len(), selection.len()); + + // Add every package to the graph. + let mut inverse = HashMap::with_capacity(selection.len()); + for (package, version) in selection { + let PubGrubPackage::Package(package_name, None) = package else { + continue; + }; + let version = Version::from(version.clone()); + let file = pins + .get(package_name) + .and_then(|versions| versions.get(&version)) + .unwrap() + .clone(); + let pinned_package = PinnedPackage::new(package_name.clone(), version, file); + let index = graph.add_node(pinned_package); + + inverse.insert(package_name, index); + } + + // Add every edge to the graph. + for (package, version) in selection { + for id in &state.incompatibilities[package] { + if let Kind::FromDependencyOf(self_package, self_version, dependency_package, _) = + &state.incompatibility_store[*id].kind + { + let PubGrubPackage::Package(self_package, None) = self_package else { + continue; + }; + let PubGrubPackage::Package(dependency_package, None) = dependency_package + else { + continue; + }; + if self_version.contains(version) { + let self_index = &inverse[self_package]; + let dependency_index = &inverse[dependency_package]; + graph.add_edge(*dependency_index, *self_index, ()); + } + } + } + } + + Self(graph) + } + + /// Return the number of packages in the graph. + pub fn len(&self) -> usize { + self.0.node_count() + } + + /// Return `true` if there are no packages in the graph. + pub fn is_empty(&self) -> bool { + self.0.node_count() == 0 + } +} + +/// Write the graph in the `{name}=={version}` format of requirements.txt that pip uses. +impl std::fmt::Display for Graph { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Collect and sort all packages. + let mut nodes = self + .0 + .node_indices() + .map(|node| (node, &self.0[node])) + .collect::>(); + nodes.sort_unstable_by_key(|(_, package)| package.name()); + + // Print out the dependency graph. + for (index, package) in nodes { + writeln!(f, "{}=={}", package.name(), package.version())?; + + let mut edges = self + .0 + .edges(index) + .map(|edge| &self.0[edge.target()]) + .collect::>(); + edges.sort_unstable_by_key(|package| package.name()); + + match edges.len() { + 0 => {} + 1 => { + for dependency in edges { + writeln!(f, "{}", format!(" # via {}", dependency.name()).green())?; + } + } + _ => { + writeln!(f, "{}", " # via".green())?; + for dependency in edges { + writeln!(f, "{}", format!(" # {}", dependency.name()).green())?; + } + } + } + } + + Ok(()) + } +} diff --git a/crates/puffin-resolver/src/resolver.rs b/crates/puffin-resolver/src/resolver.rs index 5fa62f56d..23e2328d3 100644 --- a/crates/puffin-resolver/src/resolver.rs +++ b/crates/puffin-resolver/src/resolver.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::collections::hash_map::Entry; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{HashMap, HashSet}; use std::str::FromStr; use std::sync::Arc; @@ -13,7 +13,7 @@ use futures::{pin_mut, FutureExt, StreamExt, TryFutureExt}; use pubgrub::error::PubGrubError; use pubgrub::range::Range; use pubgrub::solver::{Incompatibility, State}; -use pubgrub::type_aliases::{DependencyConstraints, SelectedDependencies}; +use pubgrub::type_aliases::DependencyConstraints; use tokio::select; use tracing::{debug, trace}; use waitmap::WaitMap; @@ -30,7 +30,7 @@ use crate::error::ResolveError; use crate::pubgrub::package::PubGrubPackage; use crate::pubgrub::version::{PubGrubVersion, MIN_VERSION}; use crate::pubgrub::{iter_requirements, version_range}; -use crate::resolution::{PinnedPackage, Resolution}; +use crate::resolution::Graph; pub struct Resolver<'a> { requirements: Vec, @@ -61,7 +61,7 @@ impl<'a> Resolver<'a> { } /// Resolve a set of requirements into a set of pinned versions. - pub async fn resolve(self) -> Result { + pub async fn resolve(self) -> Result { // A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version // metadata (e.g., given `flask==1.0.0`, fetch the metadata for that version). let (request_sink, request_stream) = futures::channel::mpsc::unbounded(); @@ -93,14 +93,14 @@ impl<'a> Resolver<'a> { } }; - Ok(resolution.into()) + Ok(resolution) } /// Run the `PubGrub` solver. async fn solve( &self, request_sink: &futures::channel::mpsc::UnboundedSender, - ) -> Result { + ) -> Result { let root = PubGrubPackage::Root; // Keep track of the packages for which we've requested metadata. @@ -126,7 +126,8 @@ impl<'a> Resolver<'a> { ) .into()); }; - return Ok(PubGrubResolution { selection, pins }); + + return Ok(Graph::from_state(&selection, &pins, &state)); }; // Choose a package version. @@ -306,8 +307,6 @@ impl<'a> Resolver<'a> { PubGrubPackage::Root => Ok((package, Some(MIN_VERSION.clone()))), PubGrubPackage::Package(package_name, _) => { // Wait for the metadata to be available. - // TODO(charlie): Ideally, we'd choose the first package for which metadata is - // available. let entry = self.cache.packages.wait(package_name).await.unwrap(); let simple_json = entry.value(); @@ -572,33 +571,3 @@ enum Dependencies { /// Container for all available package versions. Known(DependencyConstraints>), } - -#[derive(Debug)] -struct PubGrubResolution { - /// The selected dependencies. - selection: SelectedDependencies, - /// The selected file (source or built distribution) for each package. - pins: HashMap>, -} - -impl From for Resolution { - fn from(value: PubGrubResolution) -> Self { - let mut packages = BTreeMap::new(); - for (package, version) in value.selection { - let PubGrubPackage::Package(package_name, None) = package else { - continue; - }; - - let version = pep440_rs::Version::from(version); - let file = value - .pins - .get(&package_name) - .and_then(|versions| versions.get(&version)) - .unwrap() - .clone(); - let pinned_package = PinnedPackage::new(package_name.clone(), version, file); - packages.insert(package_name, pinned_package); - } - Resolution::new(packages) - } -} diff --git a/crates/puffin-resolver/tests/resolver.rs b/crates/puffin-resolver/tests/resolver.rs index df7738867..8e7a7de18 100644 --- a/crates/puffin-resolver/tests/resolver.rs +++ b/crates/puffin-resolver/tests/resolver.rs @@ -14,6 +14,8 @@ use puffin_resolver::Resolver; #[tokio::test] async fn pylint() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("pylint==2.3.0").unwrap()]; @@ -21,22 +23,15 @@ async fn pylint() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "astroid==3.0.1", - "isort==6.0.0b2", - "mccabe==0.7.0", - "pylint==2.3.0" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } #[tokio::test] async fn black() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; @@ -44,24 +39,15 @@ async fn black() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "black==23.9.1", - "click==8.1.7", - "mypy-extensions==1.0.0", - "packaging==23.2", - "pathspec==0.11.2", - "platformdirs==3.11.0" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } #[tokio::test] async fn black_colorama() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("black[colorama]<=23.9.1").unwrap()]; @@ -69,25 +55,15 @@ async fn black_colorama() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "black==23.9.1", - "click==8.1.7", - "colorama==0.4.6", - "mypy-extensions==1.0.0", - "packaging==23.2", - "pathspec==0.11.2", - "platformdirs==3.11.0" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } #[tokio::test] async fn black_python_310() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; @@ -95,20 +71,7 @@ async fn black_python_310() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_310, &TAGS_310, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "black==23.9.1", - "click==8.1.7", - "mypy-extensions==1.0.0", - "packaging==23.2", - "pathspec==0.11.2", - "platformdirs==3.11.0", - "tomli==2.0.1", - "typing-extensions==4.8.0" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } @@ -117,6 +80,8 @@ async fn black_python_310() -> Result<()> { /// respected. #[tokio::test] async fn black_mypy_extensions() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; @@ -124,18 +89,7 @@ async fn black_mypy_extensions() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "black==23.9.1", - "click==8.1.7", - "mypy-extensions==0.4.3", - "packaging==23.2", - "pathspec==0.11.2", - "platformdirs==3.11.0" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } @@ -144,6 +98,8 @@ async fn black_mypy_extensions() -> Result<()> { /// ignored when resolving constraints. #[tokio::test] async fn black_mypy_extensions_extra() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; @@ -151,18 +107,7 @@ async fn black_mypy_extensions_extra() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "black==23.9.1", - "click==8.1.7", - "mypy-extensions==0.4.3", - "packaging==23.2", - "pathspec==0.11.2", - "platformdirs==3.11.0" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } @@ -171,6 +116,8 @@ async fn black_mypy_extensions_extra() -> Result<()> { /// introduce new dependencies. #[tokio::test] async fn black_flake8() -> Result<()> { + colored::control::set_override(false); + let client = PypiClientBuilder::default().build(); let requirements = vec![Requirement::from_str("black<=23.9.1").unwrap()]; @@ -178,49 +125,7 @@ async fn black_flake8() -> Result<()> { let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); let resolution = resolver.resolve().await?; - assert_eq!( - format!("{resolution}"), - [ - "black==23.9.1", - "click==8.1.7", - "mypy-extensions==1.0.0", - "packaging==23.2", - "pathspec==0.11.2", - "platformdirs==3.11.0" - ] - .join("\n") - ); - - Ok(()) -} - -#[tokio::test] -async fn htmldate() -> Result<()> { - let client = PypiClientBuilder::default().build(); - - let requirements = vec![Requirement::from_str("htmldate<=1.5.0").unwrap()]; - let constraints = vec![]; - let resolver = Resolver::new(requirements, constraints, &MARKERS_311, &TAGS_311, &client); - let resolution = resolver.resolve().await?; - - // Resolves to `htmldate==1.4.3` (rather than `htmldate==1.5.2`) because `htmldate==1.5.2` has - // a dependency on `lxml` versions that don't provide universal wheels. - assert_eq!( - format!("{resolution}"), - [ - "charset-normalizer==3.3.0", - "dateparser==1.1.8", - "htmldate==1.4.3", - "lxml==4.9.3", - "python-dateutil==2.8.2", - "pytz==2023.3.post1", - "regex==2023.10.3", - "six==1.16.0", - "tzlocal==5.1", - "urllib3==2.0.7" - ] - .join("\n") - ); + insta::assert_display_snapshot!(resolution); Ok(()) } diff --git a/crates/puffin-resolver/tests/snapshots/resolver__black.snap b/crates/puffin-resolver/tests/snapshots/resolver__black.snap new file mode 100644 index 000000000..828a086c9 --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__black.snap @@ -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 + diff --git a/crates/puffin-resolver/tests/snapshots/resolver__black_colorama.snap b/crates/puffin-resolver/tests/snapshots/resolver__black_colorama.snap new file mode 100644 index 000000000..b783dcc75 --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__black_colorama.snap @@ -0,0 +1,17 @@ +--- +source: crates/puffin-resolver/tests/resolver.rs +expression: resolution +--- +black==23.9.1 +click==8.1.7 + # via black +colorama==0.4.6 +mypy-extensions==1.0.0 + # via black +packaging==23.2 + # via black +pathspec==0.11.2 + # via black +platformdirs==3.11.0 + # via black + diff --git a/crates/puffin-resolver/tests/snapshots/resolver__black_flake8.snap b/crates/puffin-resolver/tests/snapshots/resolver__black_flake8.snap new file mode 100644 index 000000000..828a086c9 --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__black_flake8.snap @@ -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 + diff --git a/crates/puffin-resolver/tests/snapshots/resolver__black_mypy_extensions.snap b/crates/puffin-resolver/tests/snapshots/resolver__black_mypy_extensions.snap new file mode 100644 index 000000000..a2c3ed058 --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__black_mypy_extensions.snap @@ -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==0.4.3 + # via black +packaging==23.2 + # via black +pathspec==0.11.2 + # via black +platformdirs==3.11.0 + # via black + diff --git a/crates/puffin-resolver/tests/snapshots/resolver__black_mypy_extensions_extra.snap b/crates/puffin-resolver/tests/snapshots/resolver__black_mypy_extensions_extra.snap new file mode 100644 index 000000000..a2c3ed058 --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__black_mypy_extensions_extra.snap @@ -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==0.4.3 + # via black +packaging==23.2 + # via black +pathspec==0.11.2 + # via black +platformdirs==3.11.0 + # via black + diff --git a/crates/puffin-resolver/tests/snapshots/resolver__black_python_310.snap b/crates/puffin-resolver/tests/snapshots/resolver__black_python_310.snap new file mode 100644 index 000000000..49309d2c4 --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__black_python_310.snap @@ -0,0 +1,20 @@ +--- +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 +tomli==2.0.1 + # via black +typing-extensions==4.8.0 + # via black + diff --git a/crates/puffin-resolver/tests/snapshots/resolver__pylint.snap b/crates/puffin-resolver/tests/snapshots/resolver__pylint.snap new file mode 100644 index 000000000..0fb2b52cd --- /dev/null +++ b/crates/puffin-resolver/tests/snapshots/resolver__pylint.snap @@ -0,0 +1,12 @@ +--- +source: crates/puffin-resolver/tests/resolver.rs +expression: resolution +--- +astroid==3.0.1 + # via pylint +isort==6.0.0b2 + # via pylint +mccabe==0.7.0 + # via pylint +pylint==2.3.0 + diff --git a/vendor/pubgrub/src/internal/core.rs b/vendor/pubgrub/src/internal/core.rs index f54ae8600..47d022dd1 100644 --- a/vendor/pubgrub/src/internal/core.rs +++ b/vendor/pubgrub/src/internal/core.rs @@ -24,7 +24,7 @@ pub struct State { root_package: P, root_version: VS::V, - incompatibilities: Map>>, + pub incompatibilities: Map>>, /// Store the ids of incompatibilities that are already contradicted /// and will stay that way until the next conflict and backtrack is operated. diff --git a/vendor/pubgrub/src/internal/incompatibility.rs b/vendor/pubgrub/src/internal/incompatibility.rs index 93861621c..fc742b461 100644 --- a/vendor/pubgrub/src/internal/incompatibility.rs +++ b/vendor/pubgrub/src/internal/incompatibility.rs @@ -30,15 +30,15 @@ use crate::version_set::VersionSet; /// [PubGrub documentation](https://github.com/dart-lang/pub/blob/master/doc/solver.md#incompatibility). #[derive(Debug, Clone)] pub struct Incompatibility { - package_terms: SmallMap>, - kind: Kind, + pub package_terms: SmallMap>, + pub kind: Kind, } /// Type alias of unique identifiers for incompatibilities. pub type IncompId = Id>; #[derive(Debug, Clone)] -enum Kind { +pub enum Kind { /// Initial incompatibility aiming at picking the root package for the first decision. NotRoot(P, VS::V), /// There are no versions in the given range for this package. diff --git a/vendor/pubgrub/src/lib.rs b/vendor/pubgrub/src/lib.rs index 158f7fb05..fb34c68a8 100644 --- a/vendor/pubgrub/src/lib.rs +++ b/vendor/pubgrub/src/lib.rs @@ -215,9 +215,6 @@ //! with a cache, you may want to know that some versions //! do not exist in your cache. -#![allow(clippy::rc_buffer)] -#![warn(missing_docs)] - pub mod error; pub mod package; pub mod range; diff --git a/vendor/pubgrub/src/solver.rs b/vendor/pubgrub/src/solver.rs index 7ad09d687..124b68d7a 100644 --- a/vendor/pubgrub/src/solver.rs +++ b/vendor/pubgrub/src/solver.rs @@ -74,7 +74,7 @@ use std::error::Error; use crate::error::PubGrubError; pub use crate::internal::core::State; -pub use crate::internal::incompatibility::Incompatibility; +pub use crate::internal::incompatibility::{Incompatibility, Kind}; use crate::package::Package; use crate::type_aliases::{DependencyConstraints, Map, SelectedDependencies}; use crate::version_set::VersionSet;