mirror of https://github.com/astral-sh/uv
Use a boxed slice for various requirement types (#12514)
## Summary Sorry I had five mins in between things.
This commit is contained in:
parent
daeae612aa
commit
50cf7d19b0
|
|
@ -100,7 +100,7 @@ pub struct StaticMetadata {
|
||||||
pub version: Option<Version>,
|
pub version: Option<Version>,
|
||||||
// Optional fields
|
// Optional fields
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>,
|
pub requires_dist: Box<[Requirement<VerbatimParsedUrl>]>,
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "schemars",
|
feature = "schemars",
|
||||||
schemars(
|
schemars(
|
||||||
|
|
@ -110,5 +110,5 @@ pub struct StaticMetadata {
|
||||||
)]
|
)]
|
||||||
pub requires_python: Option<VersionSpecifiers>,
|
pub requires_python: Option<VersionSpecifiers>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub provides_extras: Vec<ExtraName>,
|
pub provides_extras: Box<[ExtraName]>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ pub struct Metadata {
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
// Optional fields
|
// Optional fields
|
||||||
pub requires_dist: Vec<Requirement>,
|
pub requires_dist: Box<[Requirement]>,
|
||||||
pub requires_python: Option<VersionSpecifiers>,
|
pub requires_python: Option<VersionSpecifiers>,
|
||||||
pub provides_extras: Vec<ExtraName>,
|
pub provides_extras: Box<[ExtraName]>,
|
||||||
pub dependency_groups: BTreeMap<GroupName, Vec<Requirement>>,
|
pub dependency_groups: BTreeMap<GroupName, Box<[Requirement]>>,
|
||||||
pub dynamic: bool,
|
pub dynamic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,9 +60,7 @@ impl Metadata {
|
||||||
Self {
|
Self {
|
||||||
name: metadata.name,
|
name: metadata.name,
|
||||||
version: metadata.version,
|
version: metadata.version,
|
||||||
requires_dist: metadata
|
requires_dist: Box::into_iter(metadata.requires_dist)
|
||||||
.requires_dist
|
|
||||||
.into_iter()
|
|
||||||
.map(Requirement::from)
|
.map(Requirement::from)
|
||||||
.collect(),
|
.collect(),
|
||||||
requires_python: metadata.requires_python,
|
requires_python: metadata.requires_python,
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ use crate::Metadata;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RequiresDist {
|
pub struct RequiresDist {
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
pub requires_dist: Vec<Requirement>,
|
pub requires_dist: Box<[Requirement]>,
|
||||||
pub provides_extras: Vec<ExtraName>,
|
pub provides_extras: Box<[ExtraName]>,
|
||||||
pub dependency_groups: BTreeMap<GroupName, Vec<Requirement>>,
|
pub dependency_groups: BTreeMap<GroupName, Box<[Requirement]>>,
|
||||||
pub dynamic: bool,
|
pub dynamic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,9 +30,7 @@ impl RequiresDist {
|
||||||
pub fn from_metadata23(metadata: uv_pypi_types::RequiresDist) -> Self {
|
pub fn from_metadata23(metadata: uv_pypi_types::RequiresDist) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: metadata.name,
|
name: metadata.name,
|
||||||
requires_dist: metadata
|
requires_dist: Box::into_iter(metadata.requires_dist)
|
||||||
.requires_dist
|
|
||||||
.into_iter()
|
|
||||||
.map(Requirement::from)
|
.map(Requirement::from)
|
||||||
.collect(),
|
.collect(),
|
||||||
provides_extras: metadata.provides_extras,
|
provides_extras: metadata.provides_extras,
|
||||||
|
|
@ -183,17 +181,17 @@ impl RequiresDist {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>(),
|
.collect::<Result<Box<_>, _>>(),
|
||||||
SourceStrategy::Disabled => {
|
SourceStrategy::Disabled => {
|
||||||
Ok(requirements.into_iter().map(Requirement::from).collect())
|
Ok(requirements.into_iter().map(Requirement::from).collect())
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
Ok::<(GroupName, Vec<Requirement>), MetadataError>((name, requirements))
|
Ok::<(GroupName, Box<_>), MetadataError>((name, requirements))
|
||||||
})
|
})
|
||||||
.collect::<Result<BTreeMap<_, _>, _>>()?;
|
.collect::<Result<BTreeMap<_, _>, _>>()?;
|
||||||
|
|
||||||
// Lower the requirements.
|
// Lower the requirements.
|
||||||
let requires_dist = metadata.requires_dist.into_iter();
|
let requires_dist = Box::into_iter(metadata.requires_dist);
|
||||||
let requires_dist = match source_strategy {
|
let requires_dist = match source_strategy {
|
||||||
SourceStrategy::Enabled => requires_dist
|
SourceStrategy::Enabled => requires_dist
|
||||||
.flat_map(|requirement| {
|
.flat_map(|requirement| {
|
||||||
|
|
@ -220,7 +218,7 @@ impl RequiresDist {
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Box<_>, _>>()?,
|
||||||
SourceStrategy::Disabled => requires_dist.into_iter().map(Requirement::from).collect(),
|
SourceStrategy::Disabled => requires_dist.into_iter().map(Requirement::from).collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -351,11 +349,11 @@ impl From<Metadata> for RequiresDist {
|
||||||
/// The [`FlatRequiresDist`] struct is used to flatten out the recursive dependencies, i.e., convert
|
/// The [`FlatRequiresDist`] struct is used to flatten out the recursive dependencies, i.e., convert
|
||||||
/// from the former to the latter.
|
/// from the former to the latter.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct FlatRequiresDist(Vec<Requirement>);
|
pub struct FlatRequiresDist(Box<[Requirement]>);
|
||||||
|
|
||||||
impl FlatRequiresDist {
|
impl FlatRequiresDist {
|
||||||
/// Flatten a set of requirements, resolving any self-references.
|
/// Flatten a set of requirements, resolving any self-references.
|
||||||
pub fn from_requirements(requirements: Vec<Requirement>, name: &PackageName) -> Self {
|
pub fn from_requirements(requirements: Box<[Requirement]>, name: &PackageName) -> Self {
|
||||||
// If there are no self-references, we can return early.
|
// If there are no self-references, we can return early.
|
||||||
if requirements.iter().all(|req| req.name != *name) {
|
if requirements.iter().all(|req| req.name != *name) {
|
||||||
return Self(requirements);
|
return Self(requirements);
|
||||||
|
|
@ -368,7 +366,7 @@ impl FlatRequiresDist {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Transitively process all extras that are recursively included.
|
// Transitively process all extras that are recursively included.
|
||||||
let mut flattened = requirements.clone();
|
let mut flattened = requirements.to_vec();
|
||||||
let mut seen = FxHashSet::<(ExtraName, MarkerTree)>::default();
|
let mut seen = FxHashSet::<(ExtraName, MarkerTree)>::default();
|
||||||
let mut queue: VecDeque<_> = flattened
|
let mut queue: VecDeque<_> = flattened
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -434,21 +432,21 @@ impl FlatRequiresDist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self(flattened)
|
Self(flattened.into_boxed_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the [`FlatRequiresDist`] and return the inner vector.
|
/// Consume the [`FlatRequiresDist`] and return the inner requirements.
|
||||||
pub fn into_inner(self) -> Vec<Requirement> {
|
pub fn into_inner(self) -> Box<[Requirement]> {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for FlatRequiresDist {
|
impl IntoIterator for FlatRequiresDist {
|
||||||
type Item = Requirement;
|
type Item = Requirement;
|
||||||
type IntoIter = std::vec::IntoIter<Requirement>;
|
type IntoIter = <Box<[Requirement]> as IntoIterator>::IntoIter;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.0.into_iter()
|
Box::into_iter(self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -748,7 +746,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flat_requires_dist_noop() {
|
fn test_flat_requires_dist_noop() {
|
||||||
let name = PackageName::from_str("pkg").unwrap();
|
let name = PackageName::from_str("pkg").unwrap();
|
||||||
let requirements = vec![
|
let requirements = [
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -758,17 +756,20 @@ mod test {
|
||||||
.into(),
|
.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let expected = FlatRequiresDist(vec![
|
let expected = FlatRequiresDist(
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
[
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
.unwrap()
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("black; extra == 'dev'")
|
.into(),
|
||||||
.unwrap()
|
Requirement::from_str("black; extra == 'dev'")
|
||||||
.into(),
|
.unwrap()
|
||||||
]);
|
.into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
let actual = FlatRequiresDist::from_requirements(requirements, &name);
|
let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
@ -776,7 +777,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flat_requires_dist_basic() {
|
fn test_flat_requires_dist_basic() {
|
||||||
let name = PackageName::from_str("pkg").unwrap();
|
let name = PackageName::from_str("pkg").unwrap();
|
||||||
let requirements = vec![
|
let requirements = [
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -789,20 +790,23 @@ mod test {
|
||||||
.into(),
|
.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let expected = FlatRequiresDist(vec![
|
let expected = FlatRequiresDist(
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
[
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
.unwrap()
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("black; extra == 'dev'")
|
.into(),
|
||||||
.unwrap()
|
Requirement::from_str("black; extra == 'dev'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("black; extra == 'test'")
|
.into(),
|
||||||
.unwrap()
|
Requirement::from_str("black; extra == 'test'")
|
||||||
.into(),
|
.unwrap()
|
||||||
]);
|
.into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
let actual = FlatRequiresDist::from_requirements(requirements, &name);
|
let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
@ -823,20 +827,23 @@ mod test {
|
||||||
.into(),
|
.into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let expected = FlatRequiresDist(vec![
|
let expected = FlatRequiresDist(
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
[
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
.unwrap()
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("black; extra == 'dev' and sys_platform == 'win32'")
|
.into(),
|
||||||
.unwrap()
|
Requirement::from_str("black; extra == 'dev' and sys_platform == 'win32'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("black; extra == 'test' and sys_platform == 'win32'")
|
.into(),
|
||||||
.unwrap()
|
Requirement::from_str("black; extra == 'test' and sys_platform == 'win32'")
|
||||||
.into(),
|
.unwrap()
|
||||||
]);
|
.into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
let actual = FlatRequiresDist::from_requirements(requirements, &name);
|
let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
@ -844,7 +851,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flat_requires_dist_self_constraint() {
|
fn test_flat_requires_dist_self_constraint() {
|
||||||
let name = PackageName::from_str("pkg").unwrap();
|
let name = PackageName::from_str("pkg").unwrap();
|
||||||
let requirements = vec![
|
let requirements = [
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -855,18 +862,21 @@ mod test {
|
||||||
Requirement::from_str("pkg[async]==1.0.0").unwrap().into(),
|
Requirement::from_str("pkg[async]==1.0.0").unwrap().into(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let expected = FlatRequiresDist(vec![
|
let expected = FlatRequiresDist(
|
||||||
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
[
|
||||||
Requirement::from_str("pytest; extra == 'test'")
|
Requirement::from_str("requests>=2.0.0").unwrap().into(),
|
||||||
.unwrap()
|
Requirement::from_str("pytest; extra == 'test'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("black; extra == 'dev'")
|
.into(),
|
||||||
.unwrap()
|
Requirement::from_str("black; extra == 'dev'")
|
||||||
.into(),
|
.unwrap()
|
||||||
Requirement::from_str("pkg==1.0.0").unwrap().into(),
|
.into(),
|
||||||
]);
|
Requirement::from_str("pkg==1.0.0").unwrap().into(),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
|
||||||
let actual = FlatRequiresDist::from_requirements(requirements, &name);
|
let actual = FlatRequiresDist::from_requirements(requirements.into(), &name);
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ pub struct ResolutionMetadata {
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
// Optional fields
|
// Optional fields
|
||||||
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>,
|
pub requires_dist: Box<[Requirement<VerbatimParsedUrl>]>,
|
||||||
pub requires_python: Option<VersionSpecifiers>,
|
pub requires_python: Option<VersionSpecifiers>,
|
||||||
pub provides_extras: Vec<ExtraName>,
|
pub provides_extras: Box<[ExtraName]>,
|
||||||
/// Whether the version field is dynamic.
|
/// Whether the version field is dynamic.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub dynamic: bool,
|
pub dynamic: bool,
|
||||||
|
|
@ -55,7 +55,7 @@ impl ResolutionMetadata {
|
||||||
.get_all_values("Requires-Dist")
|
.get_all_values("Requires-Dist")
|
||||||
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
||||||
.map_ok(Requirement::from)
|
.map_ok(Requirement::from)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Box<_>, _>>()?;
|
||||||
let requires_python = headers
|
let requires_python = headers
|
||||||
.get_first_value("Requires-Python")
|
.get_first_value("Requires-Python")
|
||||||
.map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python))
|
.map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python))
|
||||||
|
|
@ -72,7 +72,7 @@ impl ResolutionMetadata {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Box<_>>();
|
||||||
let dynamic = headers
|
let dynamic = headers
|
||||||
.get_all_values("Dynamic")
|
.get_all_values("Dynamic")
|
||||||
.any(|field| field == "Version");
|
.any(|field| field == "Version");
|
||||||
|
|
@ -135,7 +135,7 @@ impl ResolutionMetadata {
|
||||||
.get_all_values("Requires-Dist")
|
.get_all_values("Requires-Dist")
|
||||||
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
||||||
.map_ok(Requirement::from)
|
.map_ok(Requirement::from)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Box<_>, _>>()?;
|
||||||
let requires_python = headers
|
let requires_python = headers
|
||||||
.get_first_value("Requires-Python")
|
.get_first_value("Requires-Python")
|
||||||
.map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python))
|
.map(|requires_python| LenientVersionSpecifiers::from_str(&requires_python))
|
||||||
|
|
@ -152,7 +152,7 @@ impl ResolutionMetadata {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Box<_>>();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
|
|
@ -223,27 +223,35 @@ impl ResolutionMetadata {
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
// Extract the requirements.
|
// Extract the requirements.
|
||||||
let mut requires_dist = project
|
let requires_dist = project
|
||||||
.dependencies
|
.dependencies
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
||||||
.map_ok(Requirement::from)
|
.map_ok(Requirement::from)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.chain(
|
||||||
|
project
|
||||||
|
.optional_dependencies
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|index| {
|
||||||
|
index.iter().flat_map(|(extras, requirements)| {
|
||||||
|
requirements
|
||||||
|
.iter()
|
||||||
|
.map(|requires_dist| LenientRequirement::from_str(requires_dist))
|
||||||
|
.map_ok(Requirement::from)
|
||||||
|
.map_ok(move |requirement| requirement.with_extra_marker(extras))
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.collect::<Result<Box<_>, _>>()?;
|
||||||
|
|
||||||
// Extract the optional dependencies.
|
// Extract the optional dependencies.
|
||||||
let mut provides_extras: Vec<ExtraName> = Vec::new();
|
let provides_extras = project
|
||||||
for (extra, requirements) in project.optional_dependencies.unwrap_or_default() {
|
.optional_dependencies
|
||||||
requires_dist.extend(
|
.unwrap_or_default()
|
||||||
requirements
|
.into_keys()
|
||||||
.into_iter()
|
.collect::<Box<_>>();
|
||||||
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
|
||||||
.map_ok(Requirement::from)
|
|
||||||
.map_ok(|requirement| requirement.with_extra_marker(&extra))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
|
||||||
);
|
|
||||||
provides_extras.push(extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
|
|
@ -326,7 +334,7 @@ mod tests {
|
||||||
let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap();
|
let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap();
|
||||||
assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());
|
assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());
|
||||||
assert_eq!(meta.version, Version::new([1, 0]));
|
assert_eq!(meta.version, Version::new([1, 0]));
|
||||||
assert_eq!(meta.requires_dist, vec!["foo".parse().unwrap()]);
|
assert_eq!(*meta.requires_dist, ["foo".parse().unwrap()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -387,7 +395,7 @@ mod tests {
|
||||||
assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());
|
assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());
|
||||||
assert_eq!(meta.version, Version::new([1, 0]));
|
assert_eq!(meta.version, Version::new([1, 0]));
|
||||||
assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap()));
|
assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap()));
|
||||||
assert_eq!(meta.requires_dist, vec!["foo".parse().unwrap()]);
|
assert_eq!(*meta.requires_dist, ["foo".parse().unwrap()]);
|
||||||
assert!(meta.provides_extras.is_empty());
|
assert!(meta.provides_extras.is_empty());
|
||||||
|
|
||||||
let s = r#"
|
let s = r#"
|
||||||
|
|
@ -406,12 +414,12 @@ mod tests {
|
||||||
assert_eq!(meta.version, Version::new([1, 0]));
|
assert_eq!(meta.version, Version::new([1, 0]));
|
||||||
assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap()));
|
assert_eq!(meta.requires_python, Some(">=3.6".parse().unwrap()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
meta.requires_dist,
|
*meta.requires_dist,
|
||||||
vec![
|
[
|
||||||
"foo".parse().unwrap(),
|
"foo".parse().unwrap(),
|
||||||
"bar; extra == \"dotenv\"".parse().unwrap()
|
"bar; extra == \"dotenv\"".parse().unwrap()
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert_eq!(meta.provides_extras, vec!["dotenv".parse().unwrap()]);
|
assert_eq!(*meta.provides_extras, ["dotenv".parse().unwrap()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ use crate::{LenientRequirement, MetadataError, VerbatimParsedUrl};
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct RequiresDist {
|
pub struct RequiresDist {
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
pub requires_dist: Vec<Requirement<VerbatimParsedUrl>>,
|
pub requires_dist: Box<[Requirement<VerbatimParsedUrl>]>,
|
||||||
pub provides_extras: Vec<ExtraName>,
|
pub provides_extras: Box<[ExtraName]>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub dynamic: bool,
|
pub dynamic: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -62,27 +62,35 @@ impl RequiresDist {
|
||||||
let name = project.name;
|
let name = project.name;
|
||||||
|
|
||||||
// Extract the requirements.
|
// Extract the requirements.
|
||||||
let mut requires_dist = project
|
let requires_dist = project
|
||||||
.dependencies
|
.dependencies
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
||||||
.map_ok(Requirement::from)
|
.map_ok(Requirement::from)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.chain(
|
||||||
|
project
|
||||||
|
.optional_dependencies
|
||||||
|
.as_ref()
|
||||||
|
.iter()
|
||||||
|
.flat_map(|index| {
|
||||||
|
index.iter().flat_map(|(extras, requirements)| {
|
||||||
|
requirements
|
||||||
|
.iter()
|
||||||
|
.map(|requires_dist| LenientRequirement::from_str(requires_dist))
|
||||||
|
.map_ok(Requirement::from)
|
||||||
|
.map_ok(move |requirement| requirement.with_extra_marker(extras))
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.collect::<Result<Box<_>, _>>()?;
|
||||||
|
|
||||||
// Extract the optional dependencies.
|
// Extract the optional dependencies.
|
||||||
let mut provides_extras: Vec<ExtraName> = Vec::new();
|
let provides_extras = project
|
||||||
for (extra, requirements) in project.optional_dependencies.unwrap_or_default() {
|
.optional_dependencies
|
||||||
requires_dist.extend(
|
.unwrap_or_default()
|
||||||
requirements
|
.into_keys()
|
||||||
.into_iter()
|
.collect::<Box<_>>();
|
||||||
.map(|requires_dist| LenientRequirement::from_str(&requires_dist))
|
|
||||||
.map_ok(Requirement::from)
|
|
||||||
.map_ok(|requirement| requirement.with_extra_marker(&extra))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
|
||||||
);
|
|
||||||
provides_extras.push(extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ impl<'a, Context: BuildContext> ExtrasResolver<'a, Context> {
|
||||||
|
|
||||||
// Sort extras for consistency.
|
// Sort extras for consistency.
|
||||||
let extras = {
|
let extras = {
|
||||||
let mut extras = metadata.provides_extras;
|
let mut extras = metadata.provides_extras.to_vec();
|
||||||
extras.sort_unstable();
|
extras.sort_unstable();
|
||||||
extras
|
extras
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -178,9 +178,7 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Respect recursive extras by propagating the source extras to the dependencies.
|
// Respect recursive extras by propagating the source extras to the dependencies.
|
||||||
let requires_dist = metadata
|
let requires_dist = Box::into_iter(metadata.requires_dist)
|
||||||
.requires_dist
|
|
||||||
.into_iter()
|
|
||||||
.chain(
|
.chain(
|
||||||
metadata
|
metadata
|
||||||
.dependency_groups
|
.dependency_groups
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,11 @@ use uv_types::{BuildContext, HashStrategy};
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SourceTreeResolution {
|
pub struct SourceTreeResolution {
|
||||||
/// The requirements sourced from the source trees.
|
/// The requirements sourced from the source trees.
|
||||||
pub requirements: Vec<Requirement>,
|
pub requirements: Box<[Requirement]>,
|
||||||
/// The names of the projects that were resolved.
|
/// The names of the projects that were resolved.
|
||||||
pub project: PackageName,
|
pub project: PackageName,
|
||||||
/// The extras used when resolving the requirements.
|
/// The extras used when resolving the requirements.
|
||||||
pub extras: Vec<ExtraName>,
|
pub extras: Box<[ExtraName]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A resolver for requirements specified via source trees.
|
/// A resolver for requirements specified via source trees.
|
||||||
|
|
@ -141,6 +141,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let requirements = requirements.into_boxed_slice();
|
||||||
let project = metadata.name;
|
let project = metadata.name;
|
||||||
let extras = metadata.provides_extras;
|
let extras = metadata.provides_extras;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1072,7 +1072,7 @@ impl Lock {
|
||||||
/// Return a [`SatisfiesResult`] if the given extras do not match the [`Package`] metadata.
|
/// Return a [`SatisfiesResult`] if the given extras do not match the [`Package`] metadata.
|
||||||
fn satisfies_provides_extra<'lock>(
|
fn satisfies_provides_extra<'lock>(
|
||||||
&self,
|
&self,
|
||||||
provides_extra: Vec<ExtraName>,
|
provides_extra: Box<[ExtraName]>,
|
||||||
package: &'lock Package,
|
package: &'lock Package,
|
||||||
) -> SatisfiesResult<'lock> {
|
) -> SatisfiesResult<'lock> {
|
||||||
if !self.supports_provides_extra() {
|
if !self.supports_provides_extra() {
|
||||||
|
|
@ -1083,7 +1083,7 @@ impl Lock {
|
||||||
let actual: BTreeSet<_> = package.metadata.provides_extras.iter().collect();
|
let actual: BTreeSet<_> = package.metadata.provides_extras.iter().collect();
|
||||||
|
|
||||||
if expected != actual {
|
if expected != actual {
|
||||||
let expected = provides_extra.into_iter().collect();
|
let expected = Box::into_iter(provides_extra).collect();
|
||||||
return SatisfiesResult::MismatchedPackageProvidesExtra(
|
return SatisfiesResult::MismatchedPackageProvidesExtra(
|
||||||
&package.id.name,
|
&package.id.name,
|
||||||
package.id.version.as_ref(),
|
package.id.version.as_ref(),
|
||||||
|
|
@ -1099,8 +1099,8 @@ impl Lock {
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
fn satisfies_requires_dist<'lock>(
|
fn satisfies_requires_dist<'lock>(
|
||||||
&self,
|
&self,
|
||||||
requires_dist: Vec<Requirement>,
|
requires_dist: Box<[Requirement]>,
|
||||||
dependency_groups: BTreeMap<GroupName, Vec<Requirement>>,
|
dependency_groups: BTreeMap<GroupName, Box<[Requirement]>>,
|
||||||
package: &'lock Package,
|
package: &'lock Package,
|
||||||
root: &Path,
|
root: &Path,
|
||||||
) -> Result<SatisfiesResult<'lock>, LockError> {
|
) -> Result<SatisfiesResult<'lock>, LockError> {
|
||||||
|
|
@ -1117,8 +1117,7 @@ impl Lock {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate the `requires-dist` metadata.
|
// Validate the `requires-dist` metadata.
|
||||||
let expected: BTreeSet<_> = requires_dist
|
let expected: BTreeSet<_> = Box::into_iter(requires_dist)
|
||||||
.into_iter()
|
|
||||||
.map(|requirement| normalize_requirement(requirement, root))
|
.map(|requirement| normalize_requirement(requirement, root))
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
let actual: BTreeSet<_> = package
|
let actual: BTreeSet<_> = package
|
||||||
|
|
@ -1145,8 +1144,7 @@ impl Lock {
|
||||||
.map(|(group, requirements)| {
|
.map(|(group, requirements)| {
|
||||||
Ok::<_, LockError>((
|
Ok::<_, LockError>((
|
||||||
group,
|
group,
|
||||||
requirements
|
Box::into_iter(requirements)
|
||||||
.into_iter()
|
|
||||||
.map(|requirement| normalize_requirement(requirement, root))
|
.map(|requirement| normalize_requirement(requirement, root))
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
))
|
))
|
||||||
|
|
@ -1977,7 +1975,7 @@ impl Package {
|
||||||
.map_err(LockErrorKind::RequirementRelativePath)?
|
.map_err(LockErrorKind::RequirementRelativePath)?
|
||||||
};
|
};
|
||||||
let provides_extras = if id.source.is_immutable() {
|
let provides_extras = if id.source.is_immutable() {
|
||||||
Vec::default()
|
Box::default()
|
||||||
} else {
|
} else {
|
||||||
annotated_dist
|
annotated_dist
|
||||||
.metadata
|
.metadata
|
||||||
|
|
@ -2863,7 +2861,7 @@ struct PackageMetadata {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
requires_dist: BTreeSet<Requirement>,
|
requires_dist: BTreeSet<Requirement>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
provides_extras: Vec<ExtraName>,
|
provides_extras: Box<[ExtraName]>,
|
||||||
#[serde(default, rename = "requires-dev", alias = "dependency-groups")]
|
#[serde(default, rename = "requires-dev", alias = "dependency-groups")]
|
||||||
dependency_groups: BTreeMap<GroupName, BTreeSet<Requirement>>,
|
dependency_groups: BTreeMap<GroupName, BTreeSet<Requirement>>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,9 @@ impl PubGrubDependency {
|
||||||
} else {
|
} else {
|
||||||
Either::Right(iter::empty())
|
Either::Right(iter::empty())
|
||||||
};
|
};
|
||||||
let extras = requirement.extras.to_vec();
|
Either::Left(Either::Left(base.chain(
|
||||||
Either::Left(Either::Left(
|
Box::into_iter(requirement.extras.clone()).map(|extra| (Some(extra), None)),
|
||||||
base.chain(extras.into_iter().map(|extra| (Some(extra), None))),
|
)))
|
||||||
))
|
|
||||||
} else if !requirement.groups.is_empty() {
|
} else if !requirement.groups.is_empty() {
|
||||||
let base = if requirement
|
let base = if requirement
|
||||||
.groups
|
.groups
|
||||||
|
|
@ -72,10 +71,9 @@ impl PubGrubDependency {
|
||||||
} else {
|
} else {
|
||||||
Either::Right(iter::empty())
|
Either::Right(iter::empty())
|
||||||
};
|
};
|
||||||
let groups = requirement.groups.to_vec();
|
Either::Left(Either::Right(base.chain(
|
||||||
Either::Left(Either::Right(
|
Box::into_iter(requirement.groups.clone()).map(|group| (None, Some(group))),
|
||||||
base.chain(groups.into_iter().map(|group| (None, Some(group)))),
|
)))
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Either::Right(iter::once((None, None)))
|
Either::Right(iter::once((None, None)))
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1849,7 +1849,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
||||||
fn flatten_requirements<'a>(
|
fn flatten_requirements<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
dependencies: &'a [Requirement],
|
dependencies: &'a [Requirement],
|
||||||
dev_dependencies: &'a BTreeMap<GroupName, Vec<Requirement>>,
|
dev_dependencies: &'a BTreeMap<GroupName, Box<[Requirement]>>,
|
||||||
extra: Option<&'a ExtraName>,
|
extra: Option<&'a ExtraName>,
|
||||||
dev: Option<&'a GroupName>,
|
dev: Option<&'a GroupName>,
|
||||||
name: Option<&PackageName>,
|
name: Option<&PackageName>,
|
||||||
|
|
|
||||||
|
|
@ -97,9 +97,7 @@ pub(crate) fn pip_show(
|
||||||
if let Ok(metadata) = dist.metadata() {
|
if let Ok(metadata) = dist.metadata() {
|
||||||
requires_map.insert(
|
requires_map.insert(
|
||||||
dist.name(),
|
dist.name(),
|
||||||
metadata
|
Box::into_iter(metadata.requires_dist)
|
||||||
.requires_dist
|
|
||||||
.into_iter()
|
|
||||||
.filter(|req| req.evaluate_markers(&markers, &[]))
|
.filter(|req| req.evaluate_markers(&markers, &[]))
|
||||||
.map(|req| req.name)
|
.map(|req| req.name)
|
||||||
.sorted_unstable()
|
.sorted_unstable()
|
||||||
|
|
@ -115,9 +113,7 @@ pub(crate) fn pip_show(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Ok(metadata) = installed.metadata() {
|
if let Ok(metadata) = installed.metadata() {
|
||||||
let requires = metadata
|
let requires = Box::into_iter(metadata.requires_dist)
|
||||||
.requires_dist
|
|
||||||
.into_iter()
|
|
||||||
.filter(|req| req.evaluate_markers(&markers, &[]))
|
.filter(|req| req.evaluate_markers(&markers, &[]))
|
||||||
.map(|req| req.name)
|
.map(|req| req.name)
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue