mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Add support for --no-strip-markers
in pip compile
output (#4503)
## Summary This is an intermediary change in enabling universal resolution for `requirements.txt` files. To start, we need to be able to preserve markers in the `requirements.txt` output _and_ propagate those markers, such that if you have a dependency that's only included with a given marker, the transitive dependencies respect that marker too. Closes #1429.
This commit is contained in:
parent
af1f1369e5
commit
5732209be3
15 changed files with 488 additions and 133 deletions
|
@ -26,12 +26,9 @@ impl Resolution {
|
|||
|
||||
/// Return the remote distribution for the given package name, if it exists.
|
||||
pub fn get_remote(&self, package_name: &PackageName) -> Option<&Dist> {
|
||||
match self.packages.get(package_name) {
|
||||
Some(dist) => match dist {
|
||||
ResolvedDist::Installable(dist) => Some(dist),
|
||||
ResolvedDist::Installed(_) => None,
|
||||
},
|
||||
None => None,
|
||||
match self.packages.get(package_name)? {
|
||||
ResolvedDist::Installable(dist) => Some(dist),
|
||||
ResolvedDist::Installed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -413,6 +413,16 @@ pub struct PipCompileArgs {
|
|||
#[arg(long, overrides_with("no_strip_extras"), hide = true)]
|
||||
pub strip_extras: bool,
|
||||
|
||||
/// Include environment markers in the output file.
|
||||
///
|
||||
/// By default, `uv` strips environment markers, as the resolution generated by `compile` is
|
||||
/// only guaranteed to be correct for the target environment.
|
||||
#[arg(long, overrides_with("strip_markers"))]
|
||||
pub no_strip_markers: bool,
|
||||
|
||||
#[arg(long, overrides_with("no_strip_markers"), hide = true)]
|
||||
pub strip_markers: bool,
|
||||
|
||||
/// Exclude comment annotations indicating the source of each package.
|
||||
#[arg(long, overrides_with("annotate"))]
|
||||
pub no_annotate: bool,
|
||||
|
|
|
@ -31,7 +31,7 @@ use uv_configuration::ExtrasSpecification;
|
|||
use uv_git::{GitReference, GitSha, RepositoryReference, ResolvedRepositoryReference};
|
||||
use uv_normalize::{ExtraName, GroupName, PackageName};
|
||||
|
||||
use crate::resolution::AnnotatedDist;
|
||||
use crate::resolution::{AnnotatedDist, ResolutionGraphNode};
|
||||
use crate::{RequiresPython, ResolutionGraph};
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
|
@ -62,11 +62,16 @@ impl Lock {
|
|||
|
||||
// Lock all base packages.
|
||||
for node_index in graph.petgraph.node_indices() {
|
||||
let dist = &graph.petgraph[node_index];
|
||||
let ResolutionGraphNode::Dist(dist) = &graph.petgraph[node_index] else {
|
||||
continue;
|
||||
};
|
||||
if dist.is_base() {
|
||||
let mut locked_dist = Distribution::from_annotated_dist(dist)?;
|
||||
for edge in graph.petgraph.edges(node_index) {
|
||||
let dependency_dist = &graph.petgraph[edge.target()];
|
||||
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()]
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let marker = edge.weight().as_ref();
|
||||
locked_dist.add_dependency(dependency_dist, marker);
|
||||
}
|
||||
|
@ -82,7 +87,9 @@ impl Lock {
|
|||
|
||||
// Lock all extras and development dependencies.
|
||||
for node_index in graph.petgraph.node_indices() {
|
||||
let dist = &graph.petgraph[node_index];
|
||||
let ResolutionGraphNode::Dist(dist) = &graph.petgraph[node_index] else {
|
||||
continue;
|
||||
};
|
||||
if let Some(extra) = dist.extra.as_ref() {
|
||||
let id = DistributionId::from_annotated_dist(dist);
|
||||
let Some(locked_dist) = locked_dists.get_mut(&id) else {
|
||||
|
@ -93,7 +100,10 @@ impl Lock {
|
|||
.into());
|
||||
};
|
||||
for edge in graph.petgraph.edges(node_index) {
|
||||
let dependency_dist = &graph.petgraph[edge.target()];
|
||||
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()]
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let marker = edge.weight().as_ref();
|
||||
locked_dist.add_optional_dependency(extra.clone(), dependency_dist, marker);
|
||||
}
|
||||
|
@ -108,7 +118,10 @@ impl Lock {
|
|||
.into());
|
||||
};
|
||||
for edge in graph.petgraph.edges(node_index) {
|
||||
let dependency_dist = &graph.petgraph[edge.target()];
|
||||
let ResolutionGraphNode::Dist(dependency_dist) = &graph.petgraph[edge.target()]
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let marker = edge.weight().as_ref();
|
||||
locked_dist.add_dev_dependency(group.clone(), dependency_dist, marker);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use owo_colors::OwoColorize;
|
||||
use petgraph::visit::EdgeRef;
|
||||
use petgraph::visit::{EdgeRef, Topo};
|
||||
use petgraph::Direction;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
|
||||
use distribution_types::{Name, SourceAnnotation, SourceAnnotations};
|
||||
use distribution_types::{DistributionMetadata, Name, SourceAnnotation, SourceAnnotations};
|
||||
use pep508_rs::MarkerEnvironment;
|
||||
use pep508_rs::MarkerTree;
|
||||
use uv_normalize::PackageName;
|
||||
|
||||
use crate::resolution::RequirementsTxtDist;
|
||||
use crate::ResolutionGraph;
|
||||
use crate::resolution::{RequirementsTxtDist, ResolutionGraphNode};
|
||||
use crate::{marker, ResolutionGraph};
|
||||
|
||||
/// A [`std::fmt::Display`] implementation for the resolution graph.
|
||||
#[derive(Debug)]
|
||||
|
@ -26,6 +27,8 @@ pub struct DisplayResolutionGraph<'a> {
|
|||
show_hashes: bool,
|
||||
/// Whether to include extras in the output (e.g., `black[colorama]`).
|
||||
include_extras: bool,
|
||||
/// Whether to include environment markers in the output (e.g., `black ; sys_platform == "win32"`).
|
||||
include_markers: bool,
|
||||
/// Whether to include annotations in the output, to indicate which dependency or dependencies
|
||||
/// requested each package.
|
||||
include_annotations: bool,
|
||||
|
@ -36,6 +39,12 @@ pub struct DisplayResolutionGraph<'a> {
|
|||
annotation_style: AnnotationStyle,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum DisplayResolutionGraphNode {
|
||||
Root,
|
||||
Dist(RequirementsTxtDist),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ResolutionGraph> for DisplayResolutionGraph<'a> {
|
||||
fn from(resolution: &'a ResolutionGraph) -> Self {
|
||||
Self::new(
|
||||
|
@ -44,6 +53,7 @@ impl<'a> From<&'a ResolutionGraph> for DisplayResolutionGraph<'a> {
|
|||
&[],
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
AnnotationStyle::default(),
|
||||
|
@ -60,6 +70,7 @@ impl<'a> DisplayResolutionGraph<'a> {
|
|||
no_emit_packages: &'a [PackageName],
|
||||
show_hashes: bool,
|
||||
include_extras: bool,
|
||||
include_markers: bool,
|
||||
include_annotations: bool,
|
||||
include_index_annotation: bool,
|
||||
annotation_style: AnnotationStyle,
|
||||
|
@ -70,6 +81,7 @@ impl<'a> DisplayResolutionGraph<'a> {
|
|||
no_emit_packages,
|
||||
show_hashes,
|
||||
include_extras,
|
||||
include_markers,
|
||||
include_annotations,
|
||||
include_index_annotation,
|
||||
annotation_style,
|
||||
|
@ -131,49 +143,15 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
|
|||
SourceAnnotations::default()
|
||||
};
|
||||
|
||||
// Convert from `AnnotatedDist` to `RequirementsTxtDist`.
|
||||
let petgraph = to_requirements_txt_graph(&self.resolution.petgraph);
|
||||
|
||||
// Propagate markers across the graph.
|
||||
let petgraph = propagate_markers(petgraph);
|
||||
|
||||
// Reduce the graph, such that all nodes for a single package are combined, regardless of
|
||||
// the extras.
|
||||
//
|
||||
// For example, `flask` and `flask[dotenv]` should be reduced into a single `flask[dotenv]`
|
||||
// node.
|
||||
let petgraph = {
|
||||
let mut petgraph =
|
||||
petgraph::graph::Graph::<RequirementsTxtDist, (), petgraph::Directed>::with_capacity(
|
||||
self.resolution.petgraph.node_count(),
|
||||
self.resolution.petgraph.edge_count(),
|
||||
);
|
||||
let mut inverse = FxHashMap::with_capacity_and_hasher(
|
||||
self.resolution.petgraph.node_count(),
|
||||
FxBuildHasher,
|
||||
);
|
||||
|
||||
// Re-add the nodes to the reduced graph.
|
||||
for index in self.resolution.petgraph.node_indices() {
|
||||
let dist = &self.resolution.petgraph[index];
|
||||
|
||||
if let Some(index) = inverse.get(dist.name()) {
|
||||
if let Some(extra) = dist.extra.as_ref() {
|
||||
let node: &mut RequirementsTxtDist = &mut petgraph[*index];
|
||||
node.extras.push(extra.clone());
|
||||
node.extras.sort_unstable();
|
||||
node.extras.dedup();
|
||||
}
|
||||
} else {
|
||||
let index = petgraph.add_node(RequirementsTxtDist::from(dist));
|
||||
inverse.insert(dist.name(), index);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-add the edges to the reduced graph.
|
||||
for edge in self.resolution.petgraph.edge_indices() {
|
||||
let (source, target) = self.resolution.petgraph.edge_endpoints(edge).unwrap();
|
||||
let source = inverse[self.resolution.petgraph[source].name()];
|
||||
let target = inverse[self.resolution.petgraph[target].name()];
|
||||
petgraph.update_edge(source, target, ());
|
||||
}
|
||||
|
||||
petgraph
|
||||
};
|
||||
let petgraph = combine_extras(&petgraph);
|
||||
|
||||
// Collect all packages.
|
||||
let mut nodes = petgraph
|
||||
|
@ -195,7 +173,9 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> {
|
|||
// Print out the dependency graph.
|
||||
for (index, node) in nodes {
|
||||
// Display the node itself.
|
||||
let mut line = node.to_requirements_txt(self.include_extras).to_string();
|
||||
let mut line = node
|
||||
.to_requirements_txt(self.include_extras, self.include_markers)
|
||||
.to_string();
|
||||
|
||||
// Display the distribution hashes, if any.
|
||||
let mut has_hashes = false;
|
||||
|
@ -319,3 +299,151 @@ pub enum AnnotationStyle {
|
|||
#[default]
|
||||
Split,
|
||||
}
|
||||
|
||||
type ResolutionPetGraph =
|
||||
petgraph::graph::Graph<ResolutionGraphNode, Option<MarkerTree>, petgraph::Directed>;
|
||||
|
||||
type IntermediatePetGraph =
|
||||
petgraph::graph::Graph<DisplayResolutionGraphNode, Option<MarkerTree>, petgraph::Directed>;
|
||||
|
||||
type RequirementsTxtGraph =
|
||||
petgraph::graph::Graph<RequirementsTxtDist, Option<MarkerTree>, petgraph::Directed>;
|
||||
|
||||
/// Convert a [`petgraph::graph::Graph`] based on [`ResolutionGraphNode`] to a graph based on
|
||||
/// [`DisplayResolutionGraphNode`].
|
||||
///
|
||||
/// In other words: converts from [`AnnotatedDist`] to [`RequirementsTxtDist`].
|
||||
fn to_requirements_txt_graph(graph: &ResolutionPetGraph) -> IntermediatePetGraph {
|
||||
let mut next = IntermediatePetGraph::with_capacity(graph.node_count(), graph.edge_count());
|
||||
let mut inverse = FxHashMap::with_capacity_and_hasher(graph.node_count(), FxBuildHasher);
|
||||
|
||||
// Re-add the nodes to the reduced graph.
|
||||
for index in graph.node_indices() {
|
||||
match &graph[index] {
|
||||
ResolutionGraphNode::Root => {
|
||||
inverse.insert(index, next.add_node(DisplayResolutionGraphNode::Root));
|
||||
}
|
||||
ResolutionGraphNode::Dist(dist) => {
|
||||
let dist = RequirementsTxtDist::from(dist);
|
||||
inverse.insert(index, next.add_node(DisplayResolutionGraphNode::Dist(dist)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-add the edges to the reduced graph.
|
||||
for edge in graph.edge_indices() {
|
||||
let (source, target) = graph.edge_endpoints(edge).unwrap();
|
||||
let weight = graph[edge].clone();
|
||||
let source = inverse[&source];
|
||||
let target = inverse[&target];
|
||||
next.update_edge(source, target, weight);
|
||||
}
|
||||
|
||||
next
|
||||
}
|
||||
|
||||
/// Propagate the [`MarkerTree`] qualifiers across the graph.
|
||||
///
|
||||
/// The graph is directed, so if any edge contains a marker, we need to propagate it to all
|
||||
/// downstream nodes.
|
||||
fn propagate_markers(mut graph: IntermediatePetGraph) -> IntermediatePetGraph {
|
||||
let mut topo = Topo::new(&graph);
|
||||
while let Some(index) = topo.next(&graph) {
|
||||
let marker_tree: Option<MarkerTree> = {
|
||||
// Fold over the edges to combine the marker trees. If any edge is `None`, then
|
||||
// the combined marker tree is `None`.
|
||||
let mut edges = graph.edges_directed(index, Direction::Incoming);
|
||||
edges
|
||||
.next()
|
||||
.and_then(|edge| graph.edge_weight(edge.id()).cloned().flatten())
|
||||
.and_then(|initial| {
|
||||
edges.try_fold(initial, |mut acc, edge| {
|
||||
acc.or(graph.edge_weight(edge.id())?.clone()?);
|
||||
Some(acc)
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// Propagate the marker tree to all downstream nodes.
|
||||
if let Some(marker_tree) = marker_tree.as_ref() {
|
||||
let mut walker = graph
|
||||
.neighbors_directed(index, Direction::Outgoing)
|
||||
.detach();
|
||||
while let Some((outgoing, _)) = walker.next(&graph) {
|
||||
if let Some(weight) = graph.edge_weight_mut(outgoing) {
|
||||
if let Some(weight) = weight {
|
||||
weight.and(marker_tree.clone());
|
||||
} else {
|
||||
*weight = Some(marker_tree.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let DisplayResolutionGraphNode::Dist(node) = &mut graph[index] {
|
||||
node.markers = marker_tree.and_then(marker::normalize);
|
||||
};
|
||||
}
|
||||
|
||||
graph
|
||||
}
|
||||
|
||||
/// Reduce the graph, such that all nodes for a single package are combined, regardless of
|
||||
/// the extras.
|
||||
///
|
||||
/// For example, `flask` and `flask[dotenv]` should be reduced into a single `flask[dotenv]`
|
||||
/// node.
|
||||
///
|
||||
/// We also remove the root node, to simplify the graph structure.
|
||||
fn combine_extras(graph: &IntermediatePetGraph) -> RequirementsTxtGraph {
|
||||
let mut next = RequirementsTxtGraph::with_capacity(graph.node_count(), graph.edge_count());
|
||||
let mut inverse = FxHashMap::with_capacity_and_hasher(graph.node_count(), FxBuildHasher);
|
||||
|
||||
// Re-add the nodes to the reduced graph.
|
||||
for index in graph.node_indices() {
|
||||
let DisplayResolutionGraphNode::Dist(dist) = &graph[index] else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(index) = inverse.get(&dist.version_id()) {
|
||||
let node: &mut RequirementsTxtDist = &mut next[*index];
|
||||
node.extras.extend(dist.extras.iter().cloned());
|
||||
node.extras.sort_unstable();
|
||||
node.extras.dedup();
|
||||
} else {
|
||||
let index = next.add_node(dist.clone());
|
||||
inverse.insert(dist.version_id(), index);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-add the edges to the reduced graph.
|
||||
for edge in graph.edge_indices() {
|
||||
let (source, target) = graph.edge_endpoints(edge).unwrap();
|
||||
let DisplayResolutionGraphNode::Dist(source_node) = &graph[source] else {
|
||||
continue;
|
||||
};
|
||||
let DisplayResolutionGraphNode::Dist(target_node) = &graph[target] else {
|
||||
continue;
|
||||
};
|
||||
let weight = graph[edge].clone();
|
||||
let source = inverse[&source_node.version_id()];
|
||||
let target = inverse[&target_node.version_id()];
|
||||
|
||||
// If either the existing marker or new marker is `None`, then the dependency is
|
||||
// included unconditionally, and so the combined marker should be `None`.
|
||||
if let Some(edge) = next
|
||||
.find_edge(source, target)
|
||||
.and_then(|edge| next.edge_weight_mut(edge))
|
||||
{
|
||||
if let (Some(marker), Some(ref version_marker)) = (edge.as_mut(), weight) {
|
||||
marker.and(version_marker.clone());
|
||||
} else {
|
||||
*edge = None;
|
||||
}
|
||||
} else {
|
||||
next.update_edge(source, target, weight);
|
||||
}
|
||||
}
|
||||
|
||||
next
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ use crate::{
|
|||
#[derive(Debug)]
|
||||
pub struct ResolutionGraph {
|
||||
/// The underlying graph.
|
||||
pub(crate) petgraph: Graph<AnnotatedDist, Option<MarkerTree>, Directed>,
|
||||
pub(crate) petgraph: Graph<ResolutionGraphNode, Option<MarkerTree>, Directed>,
|
||||
/// The range of supported Python versions.
|
||||
pub(crate) requires_python: Option<RequiresPython>,
|
||||
/// Any diagnostics that were encountered while building the graph.
|
||||
|
@ -44,12 +44,11 @@ pub struct ResolutionGraph {
|
|||
pub(crate) overrides: Overrides,
|
||||
}
|
||||
|
||||
type NodeKey<'a> = (
|
||||
&'a PackageName,
|
||||
&'a Version,
|
||||
Option<&'a ExtraName>,
|
||||
Option<&'a GroupName>,
|
||||
);
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ResolutionGraphNode {
|
||||
Root,
|
||||
Dist(AnnotatedDist),
|
||||
}
|
||||
|
||||
impl ResolutionGraph {
|
||||
/// Create a new graph from the resolved PubGrub state.
|
||||
|
@ -64,12 +63,22 @@ impl ResolutionGraph {
|
|||
python: &PythonRequirement,
|
||||
resolution: Resolution,
|
||||
) -> Result<Self, ResolveError> {
|
||||
let mut petgraph: Graph<AnnotatedDist, Option<MarkerTree>, Directed> =
|
||||
type NodeKey<'a> = (
|
||||
&'a PackageName,
|
||||
&'a Version,
|
||||
Option<&'a ExtraName>,
|
||||
Option<&'a GroupName>,
|
||||
);
|
||||
|
||||
let mut petgraph: Graph<ResolutionGraphNode, Option<MarkerTree>, Directed> =
|
||||
Graph::with_capacity(resolution.packages.len(), resolution.packages.len());
|
||||
let mut inverse: FxHashMap<NodeKey, NodeIndex<u32>> =
|
||||
FxHashMap::with_capacity_and_hasher(resolution.packages.len(), FxBuildHasher);
|
||||
let mut diagnostics = Vec::new();
|
||||
|
||||
// Add the root node.
|
||||
let root_index = petgraph.add_node(ResolutionGraphNode::Root);
|
||||
|
||||
// Add every package to the graph.
|
||||
for (package, versions) in &resolution.packages {
|
||||
let ResolutionPackage {
|
||||
|
@ -227,13 +236,13 @@ impl ResolutionGraph {
|
|||
}
|
||||
|
||||
// Add the distribution to the graph.
|
||||
let index = petgraph.add_node(AnnotatedDist {
|
||||
let index = petgraph.add_node(ResolutionGraphNode::Dist(AnnotatedDist {
|
||||
dist,
|
||||
extra: extra.clone(),
|
||||
dev: dev.clone(),
|
||||
hashes,
|
||||
metadata,
|
||||
});
|
||||
}));
|
||||
inverse.insert((name, version, extra.as_ref(), dev.as_ref()), index);
|
||||
}
|
||||
}
|
||||
|
@ -241,12 +250,14 @@ impl ResolutionGraph {
|
|||
// Add every edge to the graph.
|
||||
for (names, version_set) in resolution.dependencies {
|
||||
for versions in version_set {
|
||||
let from_index = inverse[&(
|
||||
&names.from,
|
||||
&versions.from_version,
|
||||
versions.from_extra.as_ref(),
|
||||
versions.from_dev.as_ref(),
|
||||
)];
|
||||
let from_index = names.from.as_ref().map_or(root_index, |from| {
|
||||
inverse[&(
|
||||
from,
|
||||
&versions.from_version,
|
||||
versions.from_extra.as_ref(),
|
||||
versions.from_dev.as_ref(),
|
||||
)]
|
||||
});
|
||||
let to_index = inverse[&(
|
||||
&names.to,
|
||||
&versions.to_version,
|
||||
|
@ -291,25 +302,29 @@ impl ResolutionGraph {
|
|||
})
|
||||
}
|
||||
|
||||
/// Return the number of distinct packages in the graph.
|
||||
pub fn len(&self) -> usize {
|
||||
/// Returns an iterator over the distinct packages in the graph.
|
||||
fn dists(&self) -> impl Iterator<Item = &AnnotatedDist> {
|
||||
self.petgraph
|
||||
.node_indices()
|
||||
.map(|index| &self.petgraph[index])
|
||||
.filter(|dist| dist.is_base())
|
||||
.count()
|
||||
.filter_map(move |index| match &self.petgraph[index] {
|
||||
ResolutionGraphNode::Root => None,
|
||||
ResolutionGraphNode::Dist(dist) => Some(dist),
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the number of distinct packages in the graph.
|
||||
pub fn len(&self) -> usize {
|
||||
self.dists().filter(|dist| dist.is_base()).count()
|
||||
}
|
||||
|
||||
/// Return `true` if there are no packages in the graph.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
self.dists().any(super::AnnotatedDist::is_base)
|
||||
}
|
||||
|
||||
/// Returns `true` if the graph contains the given package.
|
||||
pub fn contains(&self, name: &PackageName) -> bool {
|
||||
self.petgraph
|
||||
.node_indices()
|
||||
.any(|index| self.petgraph[index].name() == name)
|
||||
self.dists().any(|dist| dist.name() == name)
|
||||
}
|
||||
|
||||
/// Return the [`ResolutionDiagnostic`]s that were encountered while building the graph.
|
||||
|
@ -390,7 +405,9 @@ impl ResolutionGraph {
|
|||
|
||||
let mut seen_marker_values = IndexSet::default();
|
||||
for i in self.petgraph.node_indices() {
|
||||
let dist = &self.petgraph[i];
|
||||
let ResolutionGraphNode::Dist(dist) = &self.petgraph[i] else {
|
||||
continue;
|
||||
};
|
||||
let version_id = match dist.version_or_url() {
|
||||
VersionOrUrlRef::Version(version) => {
|
||||
VersionId::from_registry(dist.name().clone(), version.clone())
|
||||
|
@ -460,14 +477,8 @@ impl From<ResolutionGraph> for distribution_types::Resolution {
|
|||
fn from(graph: ResolutionGraph) -> Self {
|
||||
Self::new(
|
||||
graph
|
||||
.petgraph
|
||||
.node_indices()
|
||||
.map(|node| {
|
||||
(
|
||||
graph.petgraph[node].name().clone(),
|
||||
graph.petgraph[node].dist.clone(),
|
||||
)
|
||||
})
|
||||
.dists()
|
||||
.map(|node| (node.name().clone(), node.dist.clone()))
|
||||
.collect(),
|
||||
graph.diagnostics,
|
||||
)
|
||||
|
|
|
@ -7,6 +7,7 @@ use uv_normalize::{ExtraName, GroupName, PackageName};
|
|||
|
||||
pub use crate::resolution::display::{AnnotationStyle, DisplayResolutionGraph};
|
||||
pub use crate::resolution::graph::ResolutionGraph;
|
||||
pub(crate) use crate::resolution::graph::ResolutionGraphNode;
|
||||
pub(crate) use crate::resolution::requirements_txt::RequirementsTxtDist;
|
||||
|
||||
mod display;
|
||||
|
|
|
@ -5,18 +5,19 @@ use std::path::Path;
|
|||
use itertools::Itertools;
|
||||
|
||||
use distribution_types::{DistributionMetadata, Name, ResolvedDist, Verbatim, VersionOrUrlRef};
|
||||
use pep508_rs::{split_scheme, Scheme};
|
||||
use pep508_rs::{split_scheme, MarkerTree, Scheme};
|
||||
use pypi_types::HashDigest;
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
|
||||
use crate::resolution::AnnotatedDist;
|
||||
|
||||
/// A pinned package with its resolved distribution and all the extras that were pinned for it.
|
||||
#[derive(Debug, Clone)]
|
||||
/// A pinned package with its resolved distribution and all the extras that were pinned for it.
|
||||
pub(crate) struct RequirementsTxtDist {
|
||||
pub(crate) dist: ResolvedDist,
|
||||
pub(crate) extras: Vec<ExtraName>,
|
||||
pub(crate) hashes: Vec<HashDigest>,
|
||||
pub(crate) markers: Option<MarkerTree>,
|
||||
}
|
||||
|
||||
impl RequirementsTxtDist {
|
||||
|
@ -26,7 +27,11 @@ impl RequirementsTxtDist {
|
|||
/// This typically results in a PEP 508 representation of the requirement, but will write an
|
||||
/// unnamed requirement for relative paths, which can't be represented with PEP 508 (but are
|
||||
/// supported in `requirements.txt`).
|
||||
pub(crate) fn to_requirements_txt(&self, include_extras: bool) -> Cow<str> {
|
||||
pub(crate) fn to_requirements_txt(
|
||||
&self,
|
||||
include_extras: bool,
|
||||
include_markers: bool,
|
||||
) -> Cow<str> {
|
||||
// If the URL is editable, write it as an editable requirement.
|
||||
if self.dist.is_editable() {
|
||||
if let VersionOrUrlRef::Url(url) = self.dist.version_or_url() {
|
||||
|
@ -39,7 +44,7 @@ impl RequirementsTxtDist {
|
|||
if self.dist.is_local() {
|
||||
if let VersionOrUrlRef::Url(url) = self.dist.version_or_url() {
|
||||
let given = url.verbatim();
|
||||
match split_scheme(&given) {
|
||||
let given = match split_scheme(&given) {
|
||||
Some((scheme, path)) => {
|
||||
match Scheme::parse(scheme) {
|
||||
Some(Scheme::File) => {
|
||||
|
@ -49,6 +54,7 @@ impl RequirementsTxtDist {
|
|||
.is_some()
|
||||
{
|
||||
// Always absolute; nothing to do.
|
||||
None
|
||||
} else if let Some(path) = path.strip_prefix("//") {
|
||||
// Strip the prefix, to convert, e.g., `file://flask-3.0.3-py3-none-any.whl` to `flask-3.0.3-py3-none-any.whl`.
|
||||
//
|
||||
|
@ -59,40 +65,64 @@ impl RequirementsTxtDist {
|
|||
if !path.starts_with("${PROJECT_ROOT}")
|
||||
&& !Path::new(path).has_root()
|
||||
{
|
||||
return Cow::Owned(path.to_string());
|
||||
Some(Cow::Owned(path.to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// Ex) `file:./flask-3.0.3-py3-none-any.whl`
|
||||
return given;
|
||||
Some(given)
|
||||
}
|
||||
}
|
||||
Some(_) => {}
|
||||
Some(_) => None,
|
||||
None => {
|
||||
// Ex) `flask @ C:\Users\user\flask-3.0.3-py3-none-any.whl`
|
||||
return given;
|
||||
Some(given)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Ex) `flask @ flask-3.0.3-py3-none-any.whl`
|
||||
return given;
|
||||
Some(given)
|
||||
}
|
||||
};
|
||||
if let Some(given) = given {
|
||||
return if let Some(markers) = self.markers.as_ref().filter(|_| include_markers)
|
||||
{
|
||||
Cow::Owned(format!("{given} ; {markers}"))
|
||||
} else {
|
||||
given
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.extras.is_empty() || !include_extras {
|
||||
self.dist.verbatim()
|
||||
if let Some(markers) = self.markers.as_ref().filter(|_| include_markers) {
|
||||
Cow::Owned(format!("{} ; {}", self.dist.verbatim(), markers,))
|
||||
} else {
|
||||
self.dist.verbatim()
|
||||
}
|
||||
} else {
|
||||
let mut extras = self.extras.clone();
|
||||
extras.sort_unstable();
|
||||
extras.dedup();
|
||||
Cow::Owned(format!(
|
||||
"{}[{}]{}",
|
||||
self.name(),
|
||||
extras.into_iter().join(", "),
|
||||
self.version_or_url().verbatim()
|
||||
))
|
||||
if let Some(markers) = self.markers.as_ref().filter(|_| include_markers) {
|
||||
Cow::Owned(format!(
|
||||
"{}[{}]{} ; {}",
|
||||
self.name(),
|
||||
extras.into_iter().join(", "),
|
||||
self.version_or_url().verbatim(),
|
||||
markers,
|
||||
))
|
||||
} else {
|
||||
Cow::Owned(format!(
|
||||
"{}[{}]{}",
|
||||
self.name(),
|
||||
extras.into_iter().join(", "),
|
||||
self.version_or_url().verbatim()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +147,7 @@ impl From<&AnnotatedDist> for RequirementsTxtDist {
|
|||
vec![]
|
||||
},
|
||||
hashes: annotated.hashes.clone(),
|
||||
markers: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1589,14 +1589,17 @@ impl SolveState {
|
|||
continue;
|
||||
}
|
||||
|
||||
let PubGrubPackageInner::Package {
|
||||
name: ref self_name,
|
||||
extra: ref self_extra,
|
||||
dev: ref self_dev,
|
||||
..
|
||||
} = &**self_package
|
||||
else {
|
||||
continue;
|
||||
let (self_name, self_extra, self_dev) = match &**self_package {
|
||||
PubGrubPackageInner::Package {
|
||||
name: self_name,
|
||||
extra: self_extra,
|
||||
dev: self_dev,
|
||||
..
|
||||
} => (Some(self_name), self_extra.as_ref(), self_dev.as_ref()),
|
||||
|
||||
PubGrubPackageInner::Root(_) => (None, None, None),
|
||||
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
match **dependency_package {
|
||||
|
@ -1606,17 +1609,17 @@ impl SolveState {
|
|||
dev: ref dependency_dev,
|
||||
..
|
||||
} => {
|
||||
if self_name == dependency_name {
|
||||
if self_name.is_some_and(|self_name| self_name == dependency_name) {
|
||||
continue;
|
||||
}
|
||||
let names = ResolutionDependencyNames {
|
||||
from: self_name.clone(),
|
||||
from: self_name.cloned(),
|
||||
to: dependency_name.clone(),
|
||||
};
|
||||
let versions = ResolutionDependencyVersions {
|
||||
from_version: self_version.clone(),
|
||||
from_extra: self_extra.clone(),
|
||||
from_dev: self_dev.clone(),
|
||||
from_extra: self_extra.cloned(),
|
||||
from_dev: self_dev.cloned(),
|
||||
to_version: dependency_version.clone(),
|
||||
to_extra: dependency_extra.clone(),
|
||||
to_dev: dependency_dev.clone(),
|
||||
|
@ -1630,17 +1633,17 @@ impl SolveState {
|
|||
marker: ref dependency_marker,
|
||||
..
|
||||
} => {
|
||||
if self_name == dependency_name {
|
||||
if self_name.is_some_and(|self_name| self_name == dependency_name) {
|
||||
continue;
|
||||
}
|
||||
let names = ResolutionDependencyNames {
|
||||
from: self_name.clone(),
|
||||
from: self_name.cloned(),
|
||||
to: dependency_name.clone(),
|
||||
};
|
||||
let versions = ResolutionDependencyVersions {
|
||||
from_version: self_version.clone(),
|
||||
from_extra: self_extra.clone(),
|
||||
from_dev: self_dev.clone(),
|
||||
from_extra: self_extra.cloned(),
|
||||
from_dev: self_dev.cloned(),
|
||||
to_version: dependency_version.clone(),
|
||||
to_extra: None,
|
||||
to_dev: None,
|
||||
|
@ -1655,17 +1658,17 @@ impl SolveState {
|
|||
marker: ref dependency_marker,
|
||||
..
|
||||
} => {
|
||||
if self_name == dependency_name {
|
||||
if self_name.is_some_and(|self_name| self_name == dependency_name) {
|
||||
continue;
|
||||
}
|
||||
let names = ResolutionDependencyNames {
|
||||
from: self_name.clone(),
|
||||
from: self_name.cloned(),
|
||||
to: dependency_name.clone(),
|
||||
};
|
||||
let versions = ResolutionDependencyVersions {
|
||||
from_version: self_version.clone(),
|
||||
from_extra: self_extra.clone(),
|
||||
from_dev: self_dev.clone(),
|
||||
from_extra: self_extra.cloned(),
|
||||
from_dev: self_dev.cloned(),
|
||||
to_version: dependency_version.clone(),
|
||||
to_extra: Some(dependency_extra.clone()),
|
||||
to_dev: None,
|
||||
|
@ -1680,17 +1683,17 @@ impl SolveState {
|
|||
marker: ref dependency_marker,
|
||||
..
|
||||
} => {
|
||||
if self_name == dependency_name {
|
||||
if self_name.is_some_and(|self_name| self_name == dependency_name) {
|
||||
continue;
|
||||
}
|
||||
let names = ResolutionDependencyNames {
|
||||
from: self_name.clone(),
|
||||
from: self_name.cloned(),
|
||||
to: dependency_name.clone(),
|
||||
};
|
||||
let versions = ResolutionDependencyVersions {
|
||||
from_version: self_version.clone(),
|
||||
from_extra: self_extra.clone(),
|
||||
from_dev: self_dev.clone(),
|
||||
from_extra: self_extra.cloned(),
|
||||
from_dev: self_dev.cloned(),
|
||||
to_version: dependency_version.clone(),
|
||||
to_extra: None,
|
||||
to_dev: Some(dependency_dev.clone()),
|
||||
|
@ -1756,7 +1759,7 @@ pub(crate) struct ResolutionPackage {
|
|||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub(crate) struct ResolutionDependencyNames {
|
||||
pub(crate) from: PackageName,
|
||||
pub(crate) from: Option<PackageName>,
|
||||
pub(crate) to: PackageName,
|
||||
}
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@ pub struct PipOptions {
|
|||
pub prerelease: Option<PreReleaseMode>,
|
||||
pub output_file: Option<PathBuf>,
|
||||
pub no_strip_extras: Option<bool>,
|
||||
pub no_strip_markers: Option<bool>,
|
||||
pub no_annotate: Option<bool>,
|
||||
pub no_header: Option<bool>,
|
||||
pub custom_compile_command: Option<String>,
|
||||
|
|
|
@ -58,6 +58,7 @@ pub(crate) async fn pip_compile(
|
|||
generate_hashes: bool,
|
||||
no_emit_packages: Vec<PackageName>,
|
||||
include_extras: bool,
|
||||
include_markers: bool,
|
||||
include_annotations: bool,
|
||||
include_header: bool,
|
||||
custom_compile_command: Option<String>,
|
||||
|
@ -442,6 +443,7 @@ pub(crate) async fn pip_compile(
|
|||
&no_emit_packages,
|
||||
generate_hashes,
|
||||
include_extras,
|
||||
include_markers,
|
||||
include_annotations,
|
||||
include_index_annotation,
|
||||
annotation_style,
|
||||
|
|
|
@ -263,6 +263,7 @@ async fn run() -> Result<ExitStatus> {
|
|||
args.settings.generate_hashes,
|
||||
args.settings.no_emit_package,
|
||||
args.settings.no_strip_extras,
|
||||
args.settings.no_strip_markers,
|
||||
!args.settings.no_annotate,
|
||||
!args.settings.no_header,
|
||||
args.settings.custom_compile_command,
|
||||
|
|
|
@ -501,6 +501,8 @@ impl PipCompileSettings {
|
|||
output_file,
|
||||
no_strip_extras,
|
||||
strip_extras,
|
||||
no_strip_markers,
|
||||
strip_markers,
|
||||
no_annotate,
|
||||
annotate,
|
||||
no_header,
|
||||
|
@ -573,6 +575,7 @@ impl PipCompileSettings {
|
|||
no_deps: flag(no_deps, deps),
|
||||
output_file,
|
||||
no_strip_extras: flag(no_strip_extras, strip_extras),
|
||||
no_strip_markers: flag(no_strip_markers, strip_markers),
|
||||
no_annotate: flag(no_annotate, annotate),
|
||||
no_header: flag(no_header, header),
|
||||
custom_compile_command,
|
||||
|
@ -1487,6 +1490,7 @@ pub(crate) struct PipSettings {
|
|||
pub(crate) prerelease: PreReleaseMode,
|
||||
pub(crate) output_file: Option<PathBuf>,
|
||||
pub(crate) no_strip_extras: bool,
|
||||
pub(crate) no_strip_markers: bool,
|
||||
pub(crate) no_annotate: bool,
|
||||
pub(crate) no_header: bool,
|
||||
pub(crate) custom_compile_command: Option<String>,
|
||||
|
@ -1542,6 +1546,7 @@ impl PipSettings {
|
|||
prerelease,
|
||||
output_file,
|
||||
no_strip_extras,
|
||||
no_strip_markers,
|
||||
no_annotate,
|
||||
no_header,
|
||||
custom_compile_command,
|
||||
|
@ -1639,6 +1644,10 @@ impl PipSettings {
|
|||
.no_strip_extras
|
||||
.combine(no_strip_extras)
|
||||
.unwrap_or_default(),
|
||||
no_strip_markers: args
|
||||
.no_strip_markers
|
||||
.combine(no_strip_markers)
|
||||
.unwrap_or_default(),
|
||||
no_annotate: args.no_annotate.combine(no_annotate).unwrap_or_default(),
|
||||
no_header: args.no_header.combine(no_header).unwrap_or_default(),
|
||||
custom_compile_command: args.custom_compile_command.combine(custom_compile_command),
|
||||
|
|
|
@ -6199,6 +6199,131 @@ fn no_strip_extras() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a package with `--no-strip-markers`.
|
||||
#[test]
|
||||
fn no_strip_markers() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let requirements_in = context.temp_dir.child("requirements.in");
|
||||
requirements_in.write_str("anyio ; python_version > '3.11'")?;
|
||||
|
||||
uv_snapshot!(context.compile()
|
||||
.arg("requirements.in")
|
||||
.arg("--no-strip-markers")
|
||||
.arg("--python-platform")
|
||||
.arg("linux"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2024-03-25T00:00:00Z requirements.in --no-strip-markers --python-platform linux
|
||||
anyio==4.3.0 ; python_version > '3.11'
|
||||
# via -r requirements.in
|
||||
idna==3.6 ; python_version > '3.11'
|
||||
# via anyio
|
||||
sniffio==1.3.1 ; python_version > '3.11'
|
||||
# via anyio
|
||||
|
||||
----- stderr -----
|
||||
Resolved 3 packages in [TIME]
|
||||
"###
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a package with `--no-strip-markers`. In this case, a single package is included with
|
||||
/// multiple markers.
|
||||
#[test]
|
||||
fn no_strip_markers_multiple_markers() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let requirements_in = context.temp_dir.child("requirements.in");
|
||||
requirements_in.write_str(indoc::indoc! {r"
|
||||
trio ; python_version > '3.11'
|
||||
trio ; sys_platform == 'win32'
|
||||
"})?;
|
||||
|
||||
uv_snapshot!(context.compile()
|
||||
.arg("requirements.in")
|
||||
.arg("--no-strip-markers")
|
||||
.arg("--python-platform")
|
||||
.arg("windows"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2024-03-25T00:00:00Z requirements.in --no-strip-markers --python-platform windows
|
||||
attrs==23.2.0 ; python_version > '3.11' or sys_platform == 'win32'
|
||||
# via
|
||||
# outcome
|
||||
# trio
|
||||
cffi==1.16.0 ; implementation_name != 'pypy' and os_name == 'nt' and (python_version > '3.11' or sys_platform == 'win32')
|
||||
# via trio
|
||||
idna==3.6 ; python_version > '3.11' or sys_platform == 'win32'
|
||||
# via trio
|
||||
outcome==1.3.0.post0 ; python_version > '3.11' or sys_platform == 'win32'
|
||||
# via trio
|
||||
pycparser==2.21 ; implementation_name != 'pypy' and os_name == 'nt' and (python_version > '3.11' or sys_platform == 'win32')
|
||||
# via cffi
|
||||
sniffio==1.3.1 ; python_version > '3.11' or sys_platform == 'win32'
|
||||
# via trio
|
||||
sortedcontainers==2.4.0 ; python_version > '3.11' or sys_platform == 'win32'
|
||||
# via trio
|
||||
trio==0.25.0 ; python_version > '3.11' or sys_platform == 'win32'
|
||||
# via -r requirements.in
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
"###
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a package with `--no-strip-markers`. In this case, one of the dependencies has markers
|
||||
/// on its own requirements.
|
||||
#[test]
|
||||
fn no_strip_markers_transitive_marker() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let requirements_in = context.temp_dir.child("requirements.in");
|
||||
requirements_in.write_str("trio ; python_version > '3.11'")?;
|
||||
|
||||
uv_snapshot!(context.compile()
|
||||
.arg("requirements.in")
|
||||
.arg("--no-strip-markers")
|
||||
.arg("--python-platform")
|
||||
.arg("windows"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2024-03-25T00:00:00Z requirements.in --no-strip-markers --python-platform windows
|
||||
attrs==23.2.0 ; python_version > '3.11'
|
||||
# via
|
||||
# outcome
|
||||
# trio
|
||||
cffi==1.16.0 ; python_version > '3.11' and implementation_name != 'pypy' and os_name == 'nt'
|
||||
# via trio
|
||||
idna==3.6 ; python_version > '3.11'
|
||||
# via trio
|
||||
outcome==1.3.0.post0 ; python_version > '3.11'
|
||||
# via trio
|
||||
pycparser==2.21 ; python_version > '3.11' and implementation_name != 'pypy' and os_name == 'nt'
|
||||
# via cffi
|
||||
sniffio==1.3.1 ; python_version > '3.11'
|
||||
# via trio
|
||||
sortedcontainers==2.4.0 ; python_version > '3.11'
|
||||
# via trio
|
||||
trio==0.25.0 ; python_version > '3.11'
|
||||
# via -r requirements.in
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
"###
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resolve a package from a `requirements.in` file, with a `constraints.txt` file pinning one of
|
||||
/// its transitive dependencies to a specific version.
|
||||
#[test]
|
||||
|
|
|
@ -129,6 +129,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -257,6 +258,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -386,6 +388,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -547,6 +550,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -654,6 +658,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -793,6 +798,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -969,6 +975,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1144,6 +1151,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1292,6 +1300,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1421,6 +1430,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1588,6 +1598,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1738,6 +1749,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1867,6 +1879,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -1979,6 +1992,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -2091,6 +2105,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -2205,6 +2220,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
@ -2344,6 +2360,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
|
|||
prerelease: IfNecessaryOrExplicit,
|
||||
output_file: None,
|
||||
no_strip_extras: false,
|
||||
no_strip_markers: false,
|
||||
no_annotate: false,
|
||||
no_header: false,
|
||||
custom_compile_command: None,
|
||||
|
|
6
uv.schema.json
generated
6
uv.schema.json
generated
|
@ -672,6 +672,12 @@
|
|||
"null"
|
||||
]
|
||||
},
|
||||
"no-strip-markers": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"only-binary": {
|
||||
"type": [
|
||||
"array",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue