mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-23 16:51:40 +00:00
Store resolution options in lockfile (#5264)
## Summary This PR modifies the lockfile to include the impactful resolution settings, like the resolution and pre-release mode. If any of those values change, we want to ignore the existing lockfile. Otherwise, `--resolution lowest-direct` will typically have no effect, which is really unintuitive. Closes https://github.com/astral-sh/uv/issues/5226.
This commit is contained in:
parent
178300d16b
commit
5a23f05799
23 changed files with 406 additions and 16 deletions
|
@ -305,7 +305,7 @@ impl NoBuild {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq, serde::Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
|
||||
pub enum DependencyMode {
|
||||
/// Include all dependencies, whether direct or transitive.
|
||||
#[default]
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
|||
use chrono::{DateTime, Days, NaiveDate, NaiveTime, Utc};
|
||||
|
||||
/// A timestamp that excludes files newer than it.
|
||||
#[derive(Debug, Copy, Clone, serde::Deserialize, serde::Serialize)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
pub struct ExcludeNewer(DateTime<Utc>);
|
||||
|
||||
impl ExcludeNewer {
|
||||
|
|
|
@ -42,7 +42,8 @@ use uv_workspace::VirtualProject;
|
|||
use crate::resolution::{AnnotatedDist, ResolutionGraphNode};
|
||||
use crate::resolver::FxOnceMap;
|
||||
use crate::{
|
||||
InMemoryIndex, MetadataResponse, RequiresPython, ResolutionGraph, VersionMap, VersionsResponse,
|
||||
ExcludeNewer, InMemoryIndex, MetadataResponse, PreReleaseMode, RequiresPython, ResolutionGraph,
|
||||
ResolutionMode, VersionMap, VersionsResponse,
|
||||
};
|
||||
|
||||
/// The current version of the lock file format.
|
||||
|
@ -55,6 +56,12 @@ pub struct Lock {
|
|||
distributions: Vec<Distribution>,
|
||||
/// The range of supported Python versions.
|
||||
requires_python: Option<RequiresPython>,
|
||||
/// The [`ResolutionMode`] used to generate this lock.
|
||||
resolution_mode: ResolutionMode,
|
||||
/// The [`PreReleaseMode`] used to generate this lock.
|
||||
prerelease_mode: PreReleaseMode,
|
||||
/// The [`ExcludeNewer`] used to generate this lock.
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
/// A map from distribution ID to index in `distributions`.
|
||||
///
|
||||
/// This can be used to quickly lookup the full distribution for any ID
|
||||
|
@ -144,7 +151,15 @@ impl Lock {
|
|||
|
||||
let distributions = locked_dists.into_values().collect();
|
||||
let requires_python = graph.requires_python.clone();
|
||||
let lock = Self::new(VERSION, distributions, requires_python)?;
|
||||
let options = graph.options;
|
||||
let lock = Self::new(
|
||||
VERSION,
|
||||
distributions,
|
||||
requires_python,
|
||||
options.resolution_mode,
|
||||
options.prerelease_mode,
|
||||
options.exclude_newer,
|
||||
)?;
|
||||
Ok(lock)
|
||||
}
|
||||
|
||||
|
@ -153,6 +168,9 @@ impl Lock {
|
|||
version: u32,
|
||||
mut distributions: Vec<Distribution>,
|
||||
requires_python: Option<RequiresPython>,
|
||||
resolution_mode: ResolutionMode,
|
||||
prerelease_mode: PreReleaseMode,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
) -> Result<Self, LockError> {
|
||||
// Put all dependencies for each distribution in a canonical order and
|
||||
// check for duplicates.
|
||||
|
@ -307,10 +325,13 @@ impl Lock {
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(Lock {
|
||||
Ok(Self {
|
||||
version,
|
||||
distributions,
|
||||
requires_python,
|
||||
resolution_mode,
|
||||
prerelease_mode,
|
||||
exclude_newer,
|
||||
by_id,
|
||||
})
|
||||
}
|
||||
|
@ -330,6 +351,21 @@ impl Lock {
|
|||
self.requires_python.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the resolution mode used to generate this lock.
|
||||
pub fn resolution_mode(&self) -> ResolutionMode {
|
||||
self.resolution_mode
|
||||
}
|
||||
|
||||
/// Returns the pre-release mode used to generate this lock.
|
||||
pub fn prerelease_mode(&self) -> PreReleaseMode {
|
||||
self.prerelease_mode
|
||||
}
|
||||
|
||||
/// Returns the exclude newer setting used to generate this lock.
|
||||
pub fn exclude_newer(&self) -> Option<ExcludeNewer> {
|
||||
self.exclude_newer
|
||||
}
|
||||
|
||||
/// Convert the [`Lock`] to a [`Resolution`] using the given marker environment, tags, and root.
|
||||
pub fn to_resolution(
|
||||
&self,
|
||||
|
@ -419,6 +455,19 @@ impl Lock {
|
|||
doc.insert("requires-python", value(requires_python.to_string()));
|
||||
}
|
||||
|
||||
// Write the settings that were used to generate the resolution.
|
||||
// This enables us to invalidate the lockfile if the user changes
|
||||
// their settings.
|
||||
if self.resolution_mode != ResolutionMode::default() {
|
||||
doc.insert("resolution-mode", value(self.resolution_mode.to_string()));
|
||||
}
|
||||
if self.prerelease_mode != PreReleaseMode::default() {
|
||||
doc.insert("prerelease-mode", value(self.prerelease_mode.to_string()));
|
||||
}
|
||||
if let Some(exclude_newer) = self.exclude_newer {
|
||||
doc.insert("exclude-newer", value(exclude_newer.to_string()));
|
||||
}
|
||||
|
||||
// Count the number of distributions for each package name. When
|
||||
// there's only one distribution for a particular package name (the
|
||||
// overwhelmingly common case), we can omit some data (like source and
|
||||
|
@ -522,12 +571,18 @@ impl Lock {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
struct LockWire {
|
||||
version: u32,
|
||||
#[serde(rename = "distribution")]
|
||||
distributions: Vec<DistributionWire>,
|
||||
#[serde(rename = "requires-python")]
|
||||
requires_python: Option<RequiresPython>,
|
||||
#[serde(default)]
|
||||
resolution_mode: ResolutionMode,
|
||||
#[serde(default)]
|
||||
prerelease_mode: PreReleaseMode,
|
||||
#[serde(default)]
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
}
|
||||
|
||||
impl From<Lock> for LockWire {
|
||||
|
@ -540,6 +595,9 @@ impl From<Lock> for LockWire {
|
|||
.map(DistributionWire::from)
|
||||
.collect(),
|
||||
requires_python: lock.requires_python,
|
||||
resolution_mode: lock.resolution_mode,
|
||||
prerelease_mode: lock.prerelease_mode,
|
||||
exclude_newer: lock.exclude_newer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -570,7 +628,14 @@ impl TryFrom<LockWire> for Lock {
|
|||
.into_iter()
|
||||
.map(|dist| dist.unwire(&unambiguous_dist_ids))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Lock::new(wire.version, distributions, wire.requires_python)
|
||||
Lock::new(
|
||||
wire.version,
|
||||
distributions,
|
||||
wire.requires_python,
|
||||
wire.resolution_mode,
|
||||
wire.prerelease_mode,
|
||||
wire.exclude_newer,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use uv_configuration::IndexStrategy;
|
|||
use crate::{DependencyMode, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
|
||||
/// Options for resolving a manifest.
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
|
||||
pub struct Options {
|
||||
pub resolution_mode: ResolutionMode,
|
||||
pub prerelease_mode: PreReleaseMode,
|
||||
|
|
|
@ -30,6 +30,18 @@ pub enum PreReleaseMode {
|
|||
IfNecessaryOrExplicit,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for PreReleaseMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Disallow => write!(f, "disallow"),
|
||||
Self::Allow => write!(f, "allow"),
|
||||
Self::IfNecessary => write!(f, "if-necessary"),
|
||||
Self::Explicit => write!(f, "explicit"),
|
||||
Self::IfNecessaryOrExplicit => write!(f, "if-necessary-or-explicit"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like [`PreReleaseMode`], but with any additional information required to select a candidate,
|
||||
/// like the set of direct dependencies.
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -22,7 +22,7 @@ use crate::redirect::url_to_precise;
|
|||
use crate::resolution::AnnotatedDist;
|
||||
use crate::resolver::{Resolution, ResolutionPackage};
|
||||
use crate::{
|
||||
InMemoryIndex, MetadataResponse, PythonRequirement, RequiresPython, ResolveError,
|
||||
InMemoryIndex, MetadataResponse, Options, PythonRequirement, RequiresPython, ResolveError,
|
||||
VersionsResponse,
|
||||
};
|
||||
|
||||
|
@ -42,6 +42,8 @@ pub struct ResolutionGraph {
|
|||
pub(crate) constraints: Constraints,
|
||||
/// The overrides that were used to build the graph.
|
||||
pub(crate) overrides: Overrides,
|
||||
/// The options that were used to build the graph.
|
||||
pub(crate) options: Options,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -53,6 +55,7 @@ pub(crate) enum ResolutionGraphNode {
|
|||
impl ResolutionGraph {
|
||||
/// Create a new graph from the resolved PubGrub state.
|
||||
pub(crate) fn from_state(
|
||||
resolution: Resolution,
|
||||
requirements: &[Requirement],
|
||||
constraints: &Constraints,
|
||||
overrides: &Overrides,
|
||||
|
@ -60,7 +63,7 @@ impl ResolutionGraph {
|
|||
index: &InMemoryIndex,
|
||||
git: &GitResolver,
|
||||
python: &PythonRequirement,
|
||||
resolution: Resolution,
|
||||
options: Options,
|
||||
) -> Result<Self, ResolveError> {
|
||||
type NodeKey<'a> = (
|
||||
&'a PackageName,
|
||||
|
@ -308,6 +311,7 @@ impl ResolutionGraph {
|
|||
requirements: requirements.to_vec(),
|
||||
constraints: constraints.clone(),
|
||||
overrides: overrides.clone(),
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use uv_normalize::PackageName;
|
|||
|
||||
use crate::{DependencyMode, Manifest};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
|
@ -20,6 +20,16 @@ pub enum ResolutionMode {
|
|||
LowestDirect,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ResolutionMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Highest => write!(f, "highest"),
|
||||
Self::Lowest => write!(f, "lowest"),
|
||||
Self::LowestDirect => write!(f, "lowest-direct"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Like [`ResolutionMode`], but with any additional information required to select a candidate,
|
||||
/// like the set of direct dependencies.
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -116,6 +116,9 @@ struct ResolverState<InstalledPackages: InstalledPackagesProvider> {
|
|||
unavailable_packages: DashMap<PackageName, UnavailablePackage>,
|
||||
/// Incompatibilities for packages that are unavailable at specific versions.
|
||||
incomplete_packages: DashMap<PackageName, DashMap<Version, IncompletePackage>>,
|
||||
/// The options that were used to configure this resolver.
|
||||
options: Options,
|
||||
/// The reporter to use for this resolver.
|
||||
reporter: Option<Arc<dyn Reporter>>,
|
||||
}
|
||||
|
||||
|
@ -202,8 +205,6 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
|
|||
let state = ResolverState {
|
||||
index: index.clone(),
|
||||
git: git.clone(),
|
||||
unavailable_packages: DashMap::default(),
|
||||
incomplete_packages: DashMap::default(),
|
||||
selector: CandidateSelector::for_resolution(
|
||||
options,
|
||||
&manifest,
|
||||
|
@ -236,8 +237,11 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
|
|||
},
|
||||
markers,
|
||||
python_requirement: python_requirement.clone(),
|
||||
reporter: None,
|
||||
installed_packages,
|
||||
unavailable_packages: DashMap::default(),
|
||||
incomplete_packages: DashMap::default(),
|
||||
options,
|
||||
reporter: None,
|
||||
};
|
||||
Ok(Self { state, provider })
|
||||
}
|
||||
|
@ -677,6 +681,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
}
|
||||
}
|
||||
ResolutionGraph::from_state(
|
||||
combined,
|
||||
&self.requirements,
|
||||
&self.constraints,
|
||||
&self.overrides,
|
||||
|
@ -684,7 +689,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
&self.index,
|
||||
&self.git,
|
||||
&self.python_requirement,
|
||||
combined,
|
||||
self.options,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -69,6 +69,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -55,6 +55,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -134,6 +134,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -134,6 +134,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -134,6 +134,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -43,6 +43,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -41,6 +41,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -24,6 +24,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -24,6 +24,9 @@ Ok(
|
|||
},
|
||||
],
|
||||
requires_python: None,
|
||||
resolution_mode: Highest,
|
||||
prerelease_mode: IfNecessaryOrExplicit,
|
||||
exclude_newer: None,
|
||||
by_id: {
|
||||
DistributionId {
|
||||
name: PackageName(
|
||||
|
|
|
@ -267,6 +267,58 @@ pub(super) async fn do_lock(
|
|||
FlatIndex::from_entries(entries, None, &hasher, build_options)
|
||||
};
|
||||
|
||||
// If any of the resolution-determining settings changed, invalidate the lock.
|
||||
let existing_lock = existing_lock.filter(|lock| {
|
||||
if lock.resolution_mode() != options.resolution_mode {
|
||||
let _ = writeln!(
|
||||
printer.stderr(),
|
||||
"Ignoring existing lockfile due to change in resolution mode: `{}` vs. `{}`",
|
||||
lock.resolution_mode().cyan(),
|
||||
options.resolution_mode.cyan()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if lock.prerelease_mode() != options.prerelease_mode {
|
||||
let _ = writeln!(
|
||||
printer.stderr(),
|
||||
"Ignoring existing lockfile due to change in prerelease mode: `{}` vs. `{}`",
|
||||
lock.prerelease_mode().cyan(),
|
||||
options.prerelease_mode.cyan()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
match (lock.exclude_newer(), options.exclude_newer) {
|
||||
(None, None) => (),
|
||||
(Some(existing), Some(provided)) if existing == provided => (),
|
||||
(Some(existing), Some(provided)) => {
|
||||
let _ = writeln!(
|
||||
printer.stderr(),
|
||||
"Ignoring existing lockfile due to change in timestamp cutoff: `{}` vs. `{}`",
|
||||
existing.cyan(),
|
||||
provided.cyan()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
(Some(existing), None) => {
|
||||
let _ = writeln!(
|
||||
printer.stderr(),
|
||||
"Ignoring existing lockfile due to removal of timestamp cutoff: `{}`",
|
||||
existing.cyan(),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
(None, Some(provided)) => {
|
||||
let _ = writeln!(
|
||||
printer.stderr(),
|
||||
"Ignoring existing lockfile due to addition of timestamp cutoff: `{}`",
|
||||
provided.cyan()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
|
||||
// If an existing lockfile exists, build up a set of preferences.
|
||||
let LockedRequirements { preferences, git } = existing_lock
|
||||
.as_ref()
|
||||
|
|
|
@ -208,6 +208,7 @@ fn root_package_splits_transitive_too() -> Result<()> {
|
|||
assert_snapshot!(fs_err::read_to_string(context.temp_dir.join("uv.lock"))?, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "a"
|
||||
|
@ -365,6 +366,7 @@ fn root_package_splits_other_dependencies_too() -> Result<()> {
|
|||
assert_snapshot!(fs_err::read_to_string(context.temp_dir.join("uv.lock"))?, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "a"
|
||||
|
@ -493,6 +495,7 @@ fn branching_between_registry_and_direct_url() -> Result<()> {
|
|||
assert_snapshot!(fs_err::read_to_string(context.temp_dir.join("uv.lock"))?, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "a"
|
||||
|
@ -559,6 +562,7 @@ fn branching_urls_of_different_sources_disjoint() -> Result<()> {
|
|||
assert_snapshot!(fs_err::read_to_string(context.temp_dir.join("uv.lock"))?, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "a"
|
||||
|
@ -667,6 +671,7 @@ fn dont_pre_visit_url_packages() -> Result<()> {
|
|||
assert_snapshot!(fs_err::read_to_string(context.temp_dir.join("uv.lock"))?, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "a"
|
||||
|
|
|
@ -68,6 +68,7 @@ fn add_registry() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -220,6 +221,7 @@ fn add_git() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -366,6 +368,7 @@ fn add_git_raw() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -488,6 +491,7 @@ fn add_unnamed() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -580,6 +584,7 @@ fn add_remove_dev() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -695,6 +700,7 @@ fn add_remove_dev() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -776,6 +782,7 @@ fn add_remove_optional() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -852,6 +859,7 @@ fn add_remove_optional() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -975,6 +983,7 @@ fn add_remove_workspace() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "child1"
|
||||
|
@ -1047,6 +1056,7 @@ fn add_remove_workspace() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "child1"
|
||||
|
@ -1155,6 +1165,7 @@ fn add_workspace_editable() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "child1"
|
||||
|
@ -1348,6 +1359,7 @@ fn update() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "certifi"
|
||||
|
@ -1555,6 +1567,7 @@ fn add_no_clean() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -1686,6 +1699,7 @@ fn remove_registry() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
|
|
@ -65,6 +65,7 @@ fn lock_wheel_registry() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -236,6 +237,7 @@ fn lock_sdist_git() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -307,6 +309,7 @@ fn lock_wheel_url() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -405,6 +408,7 @@ fn lock_sdist_url() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -504,6 +508,7 @@ fn lock_project_extra() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
|
@ -729,6 +734,7 @@ fn lock_dependency_extra() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "blinker"
|
||||
|
@ -915,6 +921,7 @@ fn lock_conditional_dependency_extra() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.7"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "certifi"
|
||||
|
@ -1165,6 +1172,7 @@ fn lock_dependency_non_existent_extra() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "blinker"
|
||||
|
@ -1334,6 +1342,7 @@ fn lock_upgrade_log() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "blinker"
|
||||
|
@ -1487,6 +1496,7 @@ fn lock_upgrade_log() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "blinker"
|
||||
|
@ -1636,6 +1646,7 @@ fn lock_upgrade_log_multi_version() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "blinker"
|
||||
|
@ -1806,6 +1817,7 @@ fn lock_upgrade_log_multi_version() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "blinker"
|
||||
|
@ -1954,6 +1966,7 @@ fn lock_preference() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -2009,6 +2022,7 @@ fn lock_preference() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -2055,6 +2069,7 @@ fn lock_preference() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -2117,6 +2132,7 @@ fn lock_git_sha() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -2173,6 +2189,7 @@ fn lock_git_sha() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -2213,6 +2230,7 @@ fn lock_git_sha() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
|
@ -2311,6 +2329,7 @@ fn lock_requires_python() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.7"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "attrs"
|
||||
|
@ -2459,6 +2478,7 @@ fn lock_requires_python() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.7.9"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "attrs"
|
||||
|
@ -2597,6 +2617,7 @@ fn lock_requires_python() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "attrs"
|
||||
|
@ -2726,6 +2747,7 @@ fn lock_requires_python_wheels() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "frozenlist"
|
||||
|
@ -2795,6 +2817,7 @@ fn lock_requires_python_wheels() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "frozenlist"
|
||||
|
@ -2874,6 +2897,7 @@ fn lock_requires_python_star() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "attrs"
|
||||
|
@ -2983,6 +3007,7 @@ fn lock_requires_python_pre() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "attrs"
|
||||
|
@ -3091,6 +3116,7 @@ fn lock_requires_python_unbounded() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = "<=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -3167,6 +3193,7 @@ fn lock_python_version_marker_complement() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.8"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "attrs"
|
||||
|
@ -3251,6 +3278,7 @@ fn lock_dev() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -3351,6 +3379,7 @@ fn lock_conditional_unconditional() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -3412,6 +3441,7 @@ fn lock_multiple_markers() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "iniconfig"
|
||||
|
@ -3513,6 +3543,7 @@ fn relative_and_absolute_paths() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.11, <3.13"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "a"
|
||||
|
@ -3576,6 +3607,7 @@ fn lock_cycles() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "argparse"
|
||||
|
@ -3763,6 +3795,7 @@ fn lock_new_extras() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "certifi"
|
||||
|
@ -3872,6 +3905,7 @@ fn lock_new_extras() -> Result<()> {
|
|||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "certifi"
|
||||
|
@ -4053,3 +4087,162 @@ fn lock_invalid_hash() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Vary the `--resolution-mode`, and ensure that the lockfile is updated.
|
||||
#[test]
|
||||
fn lock_resolution_mode() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["anyio>=3"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: `uv lock` is experimental and may change without warning
|
||||
Resolved 4 packages in [TIME]
|
||||
"###);
|
||||
|
||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
version = "4.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6", size = 159642 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", size = 85584 },
|
||||
]
|
||||
|
||||
[[distribution]]
|
||||
name = "idna"
|
||||
version = "3.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", size = 175426 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567 },
|
||||
]
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
|
||||
[[distribution]]
|
||||
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 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
||||
]
|
||||
"###
|
||||
);
|
||||
});
|
||||
|
||||
// Locking again should be a no-op.
|
||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: `uv lock` is experimental and may change without warning
|
||||
Resolved 4 packages in [TIME]
|
||||
"###);
|
||||
|
||||
// Locking with `lowest-direct` should ignore the existing lockfile.
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--resolution").arg("lowest-direct"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: `uv lock` is experimental and may change without warning
|
||||
Ignoring existing lockfile due to change in resolution mode: `highest` vs. `lowest-direct`
|
||||
Resolved 4 packages in [TIME]
|
||||
"###);
|
||||
|
||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
resolution-mode = "lowest-direct"
|
||||
exclude-newer = "2024-03-25 00:00:00 UTC"
|
||||
|
||||
[[distribution]]
|
||||
name = "anyio"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/99/0d/65165f99e5f4f3b4c43a5ed9db0fb7aa655f5a58f290727a30528a87eb45/anyio-3.0.0.tar.gz", hash = "sha256:b553598332c050af19f7d41f73a7790142f5bc3d5eb8bd82f5e515ec22019bd9", size = 116952 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/49/ebee263b69fe243bd1fd0a88bc6bb0f7732bf1794ba3273cb446351f9482/anyio-3.0.0-py3-none-any.whl", hash = "sha256:e71c3d9d72291d12056c0265d07c6bbedf92332f78573e278aeb116f24f30395", size = 72182 },
|
||||
]
|
||||
|
||||
[[distribution]]
|
||||
name = "idna"
|
||||
version = "3.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", size = 175426 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f", size = 61567 },
|
||||
]
|
||||
|
||||
[[distribution]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
|
||||
[[distribution]]
|
||||
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 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
||||
]
|
||||
"###
|
||||
);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue