Add PEP 751 support to `uv pip compile` (#13019)

## Summary

You now specify `--format pylock.toml` or `-o pylock.toml` to output in
PEP 751 format.
This commit is contained in:
Charlie Marsh 2025-04-21 18:48:54 -04:00 committed by GitHub
parent b594c2d702
commit 2ba4edfbbe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1547 additions and 125 deletions

View File

@ -1075,13 +1075,22 @@ pub struct PipCompileArgs {
#[arg(long, group = "sources")]
pub group: Vec<PipGroupName>,
/// Write the compiled requirements to the given `requirements.txt` file.
/// Write the compiled requirements to the given `requirements.txt` or `pylock.toml` file.
///
/// If the file already exists, the existing versions will be preferred when resolving
/// dependencies, unless `--upgrade` is also specified.
#[arg(long, short)]
pub output_file: Option<PathBuf>,
/// The format in which the resolution should be output.
///
/// Supports both `requirements.txt` and `pylock.toml` (PEP 751) output formats.
///
/// uv will infer the output format from the file extension of the output file, if
/// provided. Otherwise, defaults to `requirements.txt`.
#[arg(long, value_enum)]
pub format: Option<ExportFormat>,
/// Include extras in the output file.
///
/// By default, uv strips extras, as any packages pulled in by the extras are already included

View File

@ -7,7 +7,7 @@ use uv_configuration::Upgrade;
use uv_fs::CWD;
use uv_git::ResolvedRepositoryReference;
use uv_requirements_txt::RequirementsTxt;
use uv_resolver::{Lock, LockError, Preference, PreferenceError};
use uv_resolver::{Lock, LockError, Preference, PreferenceError, PylockToml, PylockTomlError};
#[derive(Debug, Default)]
pub struct LockedRequirements {
@ -17,9 +17,19 @@ pub struct LockedRequirements {
pub git: Vec<ResolvedRepositoryReference>,
}
impl LockedRequirements {
/// Create a [`LockedRequirements`] from a list of preferences.
pub fn from_preferences(preferences: Vec<Preference>) -> Self {
Self {
preferences,
..LockedRequirements::default()
}
}
}
/// Load the preferred requirements from an existing `requirements.txt`, applying the upgrade strategy.
pub async fn read_requirements_txt(
output_file: Option<&Path>,
output_file: &Path,
upgrade: &Upgrade,
) -> Result<Vec<Preference>> {
// As an optimization, skip reading the lockfile is we're upgrading all packages anyway.
@ -27,11 +37,6 @@ pub async fn read_requirements_txt(
return Ok(Vec::new());
}
// If the lockfile doesn't exist, don't respect any pinned versions.
let Some(output_file) = output_file.filter(|path| path.exists()) else {
return Ok(Vec::new());
};
// Parse the requirements from the lockfile.
let requirements_txt = RequirementsTxt::parse(
output_file,
@ -95,3 +100,40 @@ pub fn read_lock_requirements(
Ok(LockedRequirements { preferences, git })
}
/// Load the preferred requirements from an existing `pylock.toml` file, applying the upgrade strategy.
pub async fn read_pylock_toml_requirements(
output_file: &Path,
upgrade: &Upgrade,
) -> Result<LockedRequirements, PylockTomlError> {
// As an optimization, skip iterating over the lockfile is we're upgrading all packages anyway.
if upgrade.is_all() {
return Ok(LockedRequirements::default());
}
// Read the `pylock.toml` from disk, and deserialize it from TOML.
let content = fs_err::tokio::read_to_string(&output_file).await?;
let lock = toml::from_str::<PylockToml>(&content)?;
let mut preferences = Vec::new();
let mut git = Vec::new();
for package in &lock.packages {
// Skip the distribution if it's not included in the upgrade strategy.
if upgrade.contains(&package.name) {
continue;
}
// Map each entry in the lockfile to a preference.
if let Some(preference) = Preference::from_pylock_toml(package)? {
preferences.push(preference);
}
// Map each entry in the lockfile to a Git SHA.
if let Some(git_ref) = package.as_git_ref() {
git.push(git_ref);
}
}
Ok(LockedRequirements { preferences, git })
}

View File

@ -5,7 +5,7 @@ pub use exclusions::Exclusions;
pub use flat_index::{FlatDistributions, FlatIndex};
pub use fork_strategy::ForkStrategy;
pub use lock::{
Installable, Lock, LockError, LockVersion, Package, PackageMap, PylockToml,
Installable, Lock, LockError, LockVersion, Package, PackageMap, PylockToml, PylockTomlError,
RequirementsTxtExport, ResolverManifest, SatisfiesResult, TreeDisplay, VERSION,
};
pub use manifest::Manifest;

View File

@ -14,7 +14,8 @@ use uv_pep508::MarkerTree;
use uv_pypi_types::ConflictItem;
use crate::graph_ops::{marker_reachability, Reachable};
pub use crate::lock::export::pylock_toml::PylockToml;
pub(crate) use crate::lock::export::pylock_toml::PylockTomlPackage;
pub use crate::lock::export::pylock_toml::{PylockToml, PylockTomlError};
pub use crate::lock::export::requirements_txt::RequirementsTxtExport;
use crate::universal_marker::resolve_conflicts;
use crate::{Installable, Package};

View File

@ -11,6 +11,7 @@ use serde::Deserialize;
use toml_edit::{value, Array, ArrayOfTables, Item, Table};
use url::Url;
use uv_cache_key::RepositoryUrl;
use uv_configuration::{DependencyGroupsWithDefaults, ExtrasSpecification, InstallOptions};
use uv_distribution_filename::{
BuildTag, DistExtension, ExtensionError, SourceDistExtension, SourceDistFilename,
@ -18,11 +19,12 @@ use uv_distribution_filename::{
};
use uv_distribution_types::{
BuiltDist, DirectUrlBuiltDist, DirectUrlSourceDist, DirectorySourceDist, Dist, Edge,
FileLocation, GitSourceDist, IndexUrl, Node, PathBuiltDist, PathSourceDist, RegistryBuiltDist,
RegistryBuiltWheel, RegistrySourceDist, RemoteSource, Resolution, ResolvedDist, SourceDist,
ToUrlError, UrlString,
FileLocation, GitSourceDist, IndexUrl, Name, Node, PathBuiltDist, PathSourceDist,
RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, RemoteSource, Resolution,
ResolvedDist, SourceDist, ToUrlError, UrlString,
};
use uv_fs::{relative_to, PortablePathBuf};
use uv_git::{RepositoryReference, ResolvedRepositoryReference};
use uv_git_types::{GitOid, GitReference, GitUrl, GitUrlParseError};
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep440::Version;
@ -33,7 +35,8 @@ use uv_small_str::SmallString;
use crate::lock::export::ExportableRequirements;
use crate::lock::{each_element_on_its_line_array, Source};
use crate::{Installable, LockError, RequiresPython};
use crate::resolution::ResolutionGraphNode;
use crate::{Installable, LockError, RequiresPython, ResolverOutput};
#[derive(Debug, thiserror::Error)]
pub enum PylockTomlError {
@ -89,6 +92,10 @@ pub enum PylockTomlError {
Extension(#[from] ExtensionError),
#[error(transparent)]
Jiff(#[from] jiff::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Deserialize(#[from] toml::de::Error),
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
@ -105,17 +112,19 @@ pub struct PylockToml {
#[serde(skip_serializing_if = "Vec::is_empty", default)]
default_groups: Vec<GroupName>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
packages: Vec<PylockTomlPackage>,
pub packages: Vec<PylockTomlPackage>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
attestation_identities: Vec<PylockTomlAttestationIdentity>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
struct PylockTomlPackage {
name: PackageName,
pub struct PylockTomlPackage {
pub name: PackageName,
#[serde(skip_serializing_if = "Option::is_none")]
version: Option<Version>,
pub version: Option<Version>,
#[serde(skip_serializing_if = "Option::is_none")]
pub index: Option<Url>,
#[serde(
skip_serializing_if = "uv_pep508::marker::ser::is_empty",
serialize_with = "uv_pep508::marker::ser::serialize",
@ -127,8 +136,6 @@ struct PylockTomlPackage {
#[serde(skip_serializing_if = "Vec::is_empty", default)]
dependencies: Vec<PylockTomlDependency>,
#[serde(skip_serializing_if = "Option::is_none")]
index: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
vcs: Option<PylockTomlVcs>,
#[serde(skip_serializing_if = "Option::is_none")]
directory: Option<PylockTomlDirectory>,
@ -239,6 +246,267 @@ struct PylockTomlAttestationIdentity {
}
impl<'lock> PylockToml {
/// Construct a [`PylockToml`] from a [`ResolverOutput`].
pub fn from_resolution(
resolution: &ResolverOutput,
omit: &[PackageName],
install_path: &Path,
) -> Result<Self, PylockTomlError> {
// The lock version is always `1.0` at time of writing.
let lock_version = Version::new([1, 0]);
// The created by field is always `uv` at time of writing.
let created_by = "uv".to_string();
// Use the `requires-python` from the target lockfile.
let requires_python = resolution.requires_python.clone();
// We don't support locking for multiple extras at time of writing.
let extras = vec![];
// We don't support locking for multiple dependency groups at time of writing.
let dependency_groups = vec![];
// We don't support locking for multiple dependency groups at time of writing.
let default_groups = vec![];
// We don't support attestation identities at time of writing.
let attestation_identities = vec![];
// Convert each node to a `pylock.toml`-style package.
let mut packages = Vec::with_capacity(resolution.graph.node_count());
for node_index in resolution.graph.node_indices() {
let ResolutionGraphNode::Dist(node) = &resolution.graph[node_index] else {
continue;
};
if !node.is_base() {
continue;
}
let ResolvedDist::Installable { dist, version } = &node.dist else {
continue;
};
if omit.contains(dist.name()) {
continue;
}
// Create a `pylock.toml`-style package.
let mut package = PylockTomlPackage {
name: dist.name().clone(),
version: version.clone(),
marker: node.marker.pep508(),
requires_python: None,
dependencies: vec![],
index: None,
vcs: None,
directory: None,
archive: None,
sdist: None,
wheels: None,
};
match &**dist {
Dist::Built(BuiltDist::DirectUrl(dist)) => {
package.archive = Some(PylockTomlArchive {
url: Some((*dist.location).clone()),
path: None,
size: dist.size(),
upload_time: None,
subdirectory: None,
hashes: Hashes::from(node.hashes.clone()),
});
}
Dist::Built(BuiltDist::Path(dist)) => {
let path = relative_to(&dist.install_path, install_path)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
package.archive = Some(PylockTomlArchive {
url: None,
path: Some(PortablePathBuf::from(path)),
size: dist.size(),
upload_time: None,
subdirectory: None,
hashes: Hashes::from(node.hashes.clone()),
});
}
Dist::Built(BuiltDist::Registry(dist)) => {
package.wheels = Some(
dist.wheels
.iter()
.map(|wheel| {
let url =
wheel.file.url.to_url().map_err(PylockTomlError::ToUrl)?;
Ok(PylockTomlWheel {
// Optional "when the last component of path/ url would be the same value".
name: if url
.filename()
.is_ok_and(|filename| filename == *wheel.file.filename)
{
None
} else {
Some(wheel.filename.clone())
},
upload_time: wheel
.file
.upload_time_utc_ms
.map(Timestamp::from_millisecond)
.transpose()?,
url: Some(
wheel.file.url.to_url().map_err(PylockTomlError::ToUrl)?,
),
path: None,
size: wheel.file.size,
hashes: Hashes::from(wheel.file.hashes.clone()),
})
})
.collect::<Result<Vec<_>, PylockTomlError>>()?,
);
if let Some(sdist) = dist.sdist.as_ref() {
let url = sdist.file.url.to_url().map_err(PylockTomlError::ToUrl)?;
package.sdist = Some(PylockTomlSdist {
// Optional "when the last component of path/ url would be the same value".
name: if url
.filename()
.is_ok_and(|filename| filename == *sdist.file.filename)
{
None
} else {
Some(sdist.file.filename.clone())
},
upload_time: sdist
.file
.upload_time_utc_ms
.map(Timestamp::from_millisecond)
.transpose()?,
url: Some(url),
path: None,
size: sdist.file.size,
hashes: Hashes::from(sdist.file.hashes.clone()),
});
}
}
Dist::Source(SourceDist::DirectUrl(dist)) => {
package.archive = Some(PylockTomlArchive {
url: Some((*dist.location).clone()),
path: None,
size: dist.size(),
upload_time: None,
subdirectory: dist.subdirectory.clone().map(PortablePathBuf::from),
hashes: Hashes::from(node.hashes.clone()),
});
}
Dist::Source(SourceDist::Directory(dist)) => {
let path = relative_to(&dist.install_path, install_path)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
package.directory = Some(PylockTomlDirectory {
path: PortablePathBuf::from(path),
editable: if dist.editable { Some(true) } else { None },
subdirectory: None,
});
}
Dist::Source(SourceDist::Git(dist)) => {
package.vcs = Some(PylockTomlVcs {
r#type: VcsKind::Git,
url: Some(dist.git.repository().clone()),
path: None,
requested_revision: dist.git.reference().as_str().map(ToString::to_string),
commit_id: dist.git.precise().unwrap_or_else(|| {
panic!("Git distribution is missing a precise hash: {dist}")
}),
subdirectory: dist.subdirectory.clone().map(PortablePathBuf::from),
});
}
Dist::Source(SourceDist::Path(dist)) => {
let path = relative_to(&dist.install_path, install_path)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
package.archive = Some(PylockTomlArchive {
url: None,
path: Some(PortablePathBuf::from(path)),
size: dist.size(),
upload_time: None,
subdirectory: None,
hashes: Hashes::from(node.hashes.clone()),
});
}
Dist::Source(SourceDist::Registry(dist)) => {
package.wheels = Some(
dist.wheels
.iter()
.map(|wheel| {
let url =
wheel.file.url.to_url().map_err(PylockTomlError::ToUrl)?;
Ok(PylockTomlWheel {
// Optional "when the last component of path/ url would be the same value".
name: if url
.filename()
.is_ok_and(|filename| filename == *wheel.file.filename)
{
None
} else {
Some(wheel.filename.clone())
},
upload_time: wheel
.file
.upload_time_utc_ms
.map(Timestamp::from_millisecond)
.transpose()?,
url: Some(
wheel.file.url.to_url().map_err(PylockTomlError::ToUrl)?,
),
path: None,
size: wheel.file.size,
hashes: Hashes::from(wheel.file.hashes.clone()),
})
})
.collect::<Result<Vec<_>, PylockTomlError>>()?,
);
let url = dist.file.url.to_url().map_err(PylockTomlError::ToUrl)?;
package.sdist = Some(PylockTomlSdist {
// Optional "when the last component of path/ url would be the same value".
name: if url
.filename()
.is_ok_and(|filename| filename == *dist.file.filename)
{
None
} else {
Some(dist.file.filename.clone())
},
upload_time: dist
.file
.upload_time_utc_ms
.map(Timestamp::from_millisecond)
.transpose()?,
url: Some(url),
path: None,
size: dist.file.size,
hashes: Hashes::from(dist.file.hashes.clone()),
});
}
}
// Add the package to the list of packages.
packages.push(package);
}
// Sort the packages by name, then version.
packages.sort_by(|a, b| a.name.cmp(&b.name).then(a.version.cmp(&b.version)));
// Return the constructed `pylock.toml`.
Ok(PylockToml {
lock_version,
created_by,
requires_python: Some(requires_python),
extras,
dependency_groups,
default_groups,
packages,
attestation_identities,
})
}
/// Construct a [`PylockToml`] from a uv lockfile.
pub fn from_lock(
target: &impl Installable<'lock>,
@ -258,7 +526,7 @@ impl<'lock> PylockToml {
install_options,
);
// Sort the nodes, such that unnamed URLs (editables) appear at the top.
// Sort the nodes.
nodes.sort_unstable_by_key(|node| &node.package.id);
// The lock version is always `1.0` at time of writing.
@ -826,6 +1094,20 @@ impl PylockTomlPackage {
best.map(|(_, i)| i)
}
/// Returns the [`ResolvedRepositoryReference`] for the package, if it is a Git source.
pub fn as_git_ref(&self) -> Option<ResolvedRepositoryReference> {
let vcs = self.vcs.as_ref()?;
let url = vcs.url.as_ref()?;
let requested_revision = vcs.requested_revision.as_ref()?;
Some(ResolvedRepositoryReference {
reference: RepositoryReference {
url: RepositoryUrl::new(url),
reference: GitReference::from_rev(requested_revision.clone()),
},
sha: vcs.commit_id,
})
}
}
impl PylockTomlWheel {

View File

@ -50,8 +50,9 @@ use uv_types::{BuildContext, HashStrategy};
use uv_workspace::WorkspaceMember;
use crate::fork_strategy::ForkStrategy;
pub use crate::lock::export::PylockToml;
pub(crate) use crate::lock::export::PylockTomlPackage;
pub use crate::lock::export::RequirementsTxtExport;
pub use crate::lock::export::{PylockToml, PylockTomlError};
pub use crate::lock::installable::Installable;
pub use crate::lock::map::PackageMap;
pub use crate::lock::tree::TreeDisplay;

View File

@ -7,10 +7,11 @@ use tracing::trace;
use uv_distribution_types::IndexUrl;
use uv_normalize::PackageName;
use uv_pep440::{Operator, Version};
use uv_pep508::{MarkerTree, VersionOrUrl};
use uv_pep508::{MarkerTree, VerbatimUrl, VersionOrUrl};
use uv_pypi_types::{HashDigest, HashDigests, HashError};
use uv_requirements_txt::{RequirementEntry, RequirementsTxtRequirement};
use crate::lock::PylockTomlPackage;
use crate::universal_marker::UniversalMarker;
use crate::{LockError, ResolverEnvironment};
@ -93,6 +94,27 @@ impl Preference {
}))
}
/// Create a [`Preference`] from a locked distribution.
pub fn from_pylock_toml(package: &PylockTomlPackage) -> Result<Option<Self>, LockError> {
let Some(version) = package.version.as_ref() else {
return Ok(None);
};
Ok(Some(Self {
name: package.name.clone(),
version: version.clone(),
marker: MarkerTree::TRUE,
index: PreferenceIndex::from(
package
.index
.as_ref()
.map(|index| IndexUrl::from(VerbatimUrl::from(index.clone()))),
),
// `pylock.toml` doesn't have fork annotations.
fork_markers: vec![],
hashes: HashDigests::empty(),
}))
}
/// Return the [`PackageName`] of the package for this [`Preference`].
pub fn name(&self) -> &PackageName {
&self.name

View File

@ -4,8 +4,8 @@ use std::path::PathBuf;
use url::Url;
use uv_configuration::{
ConfigSettings, IndexStrategy, KeyringProviderType, RequiredVersion, TargetTriple,
TrustedPublishing,
ConfigSettings, ExportFormat, IndexStrategy, KeyringProviderType, RequiredVersion,
TargetTriple, TrustedPublishing,
};
use uv_distribution_types::{Index, IndexUrl, PipExtraIndex, PipFindLinks, PipIndex};
use uv_install_wheel::LinkMode;
@ -75,6 +75,7 @@ macro_rules! impl_combine_or {
impl_combine_or!(AnnotationStyle);
impl_combine_or!(ExcludeNewer);
impl_combine_or!(ExportFormat);
impl_combine_or!(ForkStrategy);
impl_combine_or!(Index);
impl_combine_or!(IndexStrategy);

View File

@ -14,8 +14,8 @@ use uv_auth::UrlAuthPolicies;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, IndexStrategy,
NoBinary, NoBuild, PreviewMode, Reinstall, SourceStrategy, Upgrade,
BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification,
IndexStrategy, NoBinary, NoBuild, PreviewMode, Reinstall, SourceStrategy, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState};
@ -23,7 +23,8 @@ use uv_distribution_types::{
DependencyMetadata, HashGeneration, Index, IndexLocations, NameRequirementSpecification,
Origin, Requirement, UnresolvedRequirementSpecification, Verbatim,
};
use uv_fs::Simplified;
use uv_fs::{Simplified, CWD};
use uv_git::ResolvedRepositoryReference;
use uv_install_wheel::LinkMode;
use uv_normalize::{GroupName, PackageName};
use uv_pypi_types::{Conflicts, SupportedEnvironments};
@ -31,12 +32,13 @@ use uv_python::{
EnvironmentPreference, PythonEnvironment, PythonInstallation, PythonPreference, PythonRequest,
PythonVersion, VersionRequest,
};
use uv_requirements::upgrade::{read_pylock_toml_requirements, LockedRequirements};
use uv_requirements::{
upgrade::read_requirements_txt, RequirementsSource, RequirementsSpecification,
};
use uv_resolver::{
AnnotationStyle, DependencyMode, DisplayResolutionGraph, ExcludeNewer, FlatIndex, ForkStrategy,
InMemoryIndex, OptionsBuilder, PrereleaseMode, PythonRequirement, RequiresPython,
InMemoryIndex, OptionsBuilder, PrereleaseMode, PylockToml, PythonRequirement, RequiresPython,
ResolutionMode, ResolverEnvironment,
};
use uv_torch::{TorchMode, TorchStrategy};
@ -64,6 +66,7 @@ pub(crate) async fn pip_compile(
extras: ExtrasSpecification,
groups: BTreeMap<PathBuf, Vec<GroupName>>,
output_file: Option<&Path>,
format: Option<ExportFormat>,
resolution_mode: ResolutionMode,
prerelease_mode: PrereleaseMode,
fork_strategy: ForkStrategy,
@ -118,15 +121,18 @@ pub(crate) async fn pip_compile(
"uv pip compile".green()
));
}
if output_file
.and_then(Path::extension)
.is_some_and(|name| name.eq_ignore_ascii_case("toml"))
{
return Err(anyhow!(
"TOML is not a supported output format for `{}` (only `requirements.txt`-style output is supported)",
"uv pip compile".green()
));
}
// Determine the output format.
let format = format.unwrap_or_else(|| {
let extension = output_file.and_then(Path::extension);
if extension.is_some_and(|ext| ext.eq_ignore_ascii_case("txt")) {
ExportFormat::RequirementsTxt
} else if extension.is_some_and(|ext| ext.eq_ignore_ascii_case("toml")) {
ExportFormat::PylockToml
} else {
ExportFormat::RequirementsTxt
}
});
// Respect `UV_PYTHON`
if python.is_none() && python_version.is_none() {
@ -334,8 +340,9 @@ pub(crate) async fn pip_compile(
(Some(tags), ResolverEnvironment::specific(marker_env))
};
// Generate, but don't enforce hashes for the requirements.
let hasher = if generate_hashes {
// Generate, but don't enforce hashes for the requirements. PEP 751 _requires_ a hash to be
// present, but otherwise, we omit them by default.
let hasher = if generate_hashes || matches!(format, ExportFormat::PylockToml) {
HashStrategy::Generate(HashGeneration::All)
} else {
HashStrategy::None
@ -396,7 +403,25 @@ pub(crate) async fn pip_compile(
.build();
// Read the lockfile, if present.
let preferences = read_requirements_txt(output_file, &upgrade).await?;
let LockedRequirements { preferences, git } =
if let Some(output_file) = output_file.filter(|output_file| output_file.exists()) {
match format {
ExportFormat::RequirementsTxt => LockedRequirements::from_preferences(
read_requirements_txt(output_file, &upgrade).await?,
),
ExportFormat::PylockToml => {
read_pylock_toml_requirements(output_file, &upgrade).await?
}
}
} else {
LockedRequirements::default()
};
// Populate the Git resolver.
for ResolvedRepositoryReference { reference, sha } in git {
debug!("Inserting Git reference into resolver: `{reference:?}` at `{sha}`");
state.git().insert(reference, sha);
}
// Combine the `--no-binary` and `--no-build` flags from the requirements files.
let build_options = build_options.combine(no_binary, no_build);
@ -524,96 +549,135 @@ pub(crate) async fn pip_compile(
)?;
}
if include_marker_expression {
if let Some(marker_env) = resolver_env.marker_environment() {
let relevant_markers = resolution.marker_tree(&top_level_index, marker_env)?;
if let Some(relevant_markers) = relevant_markers.contents() {
writeln!(
writer,
"{}",
"# Pinned dependencies known to be valid for:".green()
)?;
writeln!(writer, "{}", format!("# {relevant_markers}").green())?;
match format {
ExportFormat::RequirementsTxt => {
if include_marker_expression {
if let Some(marker_env) = resolver_env.marker_environment() {
let relevant_markers = resolution.marker_tree(&top_level_index, marker_env)?;
if let Some(relevant_markers) = relevant_markers.contents() {
writeln!(
writer,
"{}",
"# Pinned dependencies known to be valid for:".green()
)?;
writeln!(writer, "{}", format!("# {relevant_markers}").green())?;
}
}
}
}
}
let mut wrote_preamble = false;
let mut wrote_preamble = false;
// If necessary, include the `--index-url` and `--extra-index-url` locations.
if include_index_url {
if let Some(index) = index_locations.default_index() {
writeln!(writer, "--index-url {}", index.url().verbatim())?;
wrote_preamble = true;
}
let mut seen = FxHashSet::default();
for extra_index in index_locations.implicit_indexes() {
if seen.insert(extra_index.url()) {
writeln!(writer, "--extra-index-url {}", extra_index.url().verbatim())?;
wrote_preamble = true;
// If necessary, include the `--index-url` and `--extra-index-url` locations.
if include_index_url {
if let Some(index) = index_locations.default_index() {
writeln!(writer, "--index-url {}", index.url().verbatim())?;
wrote_preamble = true;
}
let mut seen = FxHashSet::default();
for extra_index in index_locations.implicit_indexes() {
if seen.insert(extra_index.url()) {
writeln!(writer, "--extra-index-url {}", extra_index.url().verbatim())?;
wrote_preamble = true;
}
}
}
}
}
// If necessary, include the `--find-links` locations.
if include_find_links {
for flat_index in index_locations.flat_indexes() {
writeln!(writer, "--find-links {}", flat_index.url().verbatim())?;
wrote_preamble = true;
}
}
// If necessary, include the `--no-binary` and `--only-binary` options.
if include_build_options {
match build_options.no_binary() {
NoBinary::None => {}
NoBinary::All => {
writeln!(writer, "--no-binary :all:")?;
wrote_preamble = true;
}
NoBinary::Packages(packages) => {
for package in packages {
writeln!(writer, "--no-binary {package}")?;
// If necessary, include the `--find-links` locations.
if include_find_links {
for flat_index in index_locations.flat_indexes() {
writeln!(writer, "--find-links {}", flat_index.url().verbatim())?;
wrote_preamble = true;
}
}
}
match build_options.no_build() {
NoBuild::None => {}
NoBuild::All => {
writeln!(writer, "--only-binary :all:")?;
wrote_preamble = true;
}
NoBuild::Packages(packages) => {
for package in packages {
writeln!(writer, "--only-binary {package}")?;
wrote_preamble = true;
// If necessary, include the `--no-binary` and `--only-binary` options.
if include_build_options {
match build_options.no_binary() {
NoBinary::None => {}
NoBinary::All => {
writeln!(writer, "--no-binary :all:")?;
wrote_preamble = true;
}
NoBinary::Packages(packages) => {
for package in packages {
writeln!(writer, "--no-binary {package}")?;
wrote_preamble = true;
}
}
}
match build_options.no_build() {
NoBuild::None => {}
NoBuild::All => {
writeln!(writer, "--only-binary :all:")?;
wrote_preamble = true;
}
NoBuild::Packages(packages) => {
for package in packages {
writeln!(writer, "--only-binary {package}")?;
wrote_preamble = true;
}
}
}
}
// If we wrote an index, add a newline to separate it from the requirements
if wrote_preamble {
writeln!(writer)?;
}
write!(
writer,
"{}",
DisplayResolutionGraph::new(
&resolution,
&resolver_env,
&no_emit_packages,
generate_hashes,
include_extras,
include_markers || universal,
include_annotations,
include_index_annotation,
annotation_style,
)
)?;
}
ExportFormat::PylockToml => {
if include_marker_expression {
warn_user!("The `--emit-marker-expression` option is not supported for `pylock.toml` output");
}
if include_index_url {
warn_user!(
"The `--emit-index-url` option is not supported for `pylock.toml` output"
);
}
if include_find_links {
warn_user!(
"The `--emit-find-links` option is not supported for `pylock.toml` output"
);
}
if include_build_options {
warn_user!(
"The `--emit-build-options` option is not supported for `pylock.toml` output"
);
}
if include_index_annotation {
warn_user!("The `--emit-index-annotation` option is not supported for `pylock.toml` output");
}
// Determine the directory relative to which the output file should be written.
let output_file = output_file.map(std::path::absolute).transpose()?;
let install_path = if let Some(output_file) = output_file.as_deref() {
output_file.parent().unwrap()
} else {
&*CWD
};
// Convert the resolution to a `pylock.toml` file.
let export = PylockToml::from_resolution(&resolution, &no_emit_packages, install_path)?;
write!(writer, "{}", export.to_toml()?)?;
}
}
// If we wrote an index, add a newline to separate it from the requirements
if wrote_preamble {
writeln!(writer)?;
}
write!(
writer,
"{}",
DisplayResolutionGraph::new(
&resolution,
&resolver_env,
&no_emit_packages,
generate_hashes,
include_extras,
include_markers || universal,
include_annotations,
include_index_annotation,
annotation_style,
)
)?;
// If any "unsafe" packages were excluded, notify the user.
let excluded = no_emit_packages
.into_iter()

View File

@ -450,6 +450,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.settings.extras,
groups,
args.settings.output_file.as_deref(),
args.format,
args.settings.resolution,
args.settings.prerelease,
args.settings.fork_strategy,

View File

@ -1638,6 +1638,7 @@ impl ExportSettings {
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub(crate) struct PipCompileSettings {
pub(crate) format: Option<ExportFormat>,
pub(crate) src_file: Vec<PathBuf>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) overrides: Vec<PathBuf>,
@ -1666,6 +1667,7 @@ impl PipCompileSettings {
deps,
group,
output_file,
format,
no_strip_extras,
strip_extras,
no_strip_markers,
@ -1754,6 +1756,7 @@ impl PipCompileSettings {
};
Self {
format,
src_file,
constraints: constraints
.into_iter()

View File

@ -16254,18 +16254,973 @@ fn compile_invalid_output_file() -> Result<()> {
error: `pyproject.toml` is not a supported output format for `uv pip compile` (only `requirements.txt`-style output is supported)
");
Ok(())
}
#[test]
fn pep_751_compile_registry_wheel() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("iniconfig")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.in")
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("uv.toml"), @r"
success: false
exit_code: 2
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "iniconfig"
version = "2.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", upload-time = 2023-01-07T11:08:11Z, size = 4646, hashes = { sha256 = "2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", upload-time = 2023-01-07T11:08:09Z, size = 5892, hashes = { sha256 = "b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" } }]
----- stderr -----
Resolved 1 package in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
error: TOML is not a supported output format for `uv pip compile` (only `requirements.txt`-style output is supported)
");
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ iniconfig==2.0.0
"
);
Ok(())
}
#[test]
fn pep_751_compile_registry_sdist() -> Result<()> {
let context = TestContext::new("3.12").with_exclude_newer("2025-01-29T00:00:00Z");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("source-distribution")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "source-distribution"
version = "0.0.3"
sdist = { url = "https://files.pythonhosted.org/packages/1f/e5/5b016c945d745f8b108e759d428341488a6aee8f51f07c6c4e33498bb91f/source_distribution-0.0.3.tar.gz", upload-time = 2024-11-03T02:35:36Z, size = 2166, hashes = { sha256 = "be5895c175dbca2d91709a6ab7d5f28e1794272db551ae9a5faf3ae2ed74c3d8" } }
----- stderr -----
Resolved 1 package in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ source-distribution==0.0.3
"
);
Ok(())
}
#[test]
fn pep_751_compile_directory() -> Result<()> {
let context = TestContext::new("3.12");
// Create a local dependency in a subdirectory.
let pyproject_toml = context.temp_dir.child("foo").child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "foo"
version = "1.0.0"
dependencies = ["anyio"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
"#,
)?;
context
.temp_dir
.child("foo")
.child("src")
.child("foo")
.child("__init__.py")
.touch()?;
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("./foo")?;
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 = ["foo"]
[tool.uv.sources]
foo = { path = "foo" }
"#,
)?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "4.3.0"
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", upload-time = 2024-02-19T08:36:28Z, size = 159642, hashes = { sha256 = "f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", upload-time = 2024-02-19T08:36:26Z, size = 85584, hashes = { sha256 = "048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8" } }]
[[packages]]
name = "foo"
version = "1.0.0"
directory = { path = "foo" }
[[packages]]
name = "idna"
version = "3.6"
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", upload-time = 2023-11-25T15:40:54Z, size = 175426, hashes = { sha256 = "9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", upload-time = 2023-11-25T15:40:52Z, size = 61567, hashes = { sha256 = "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 4 packages in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Prepared 4 packages in [TIME]
Installed 4 packages in [TIME]
+ anyio==4.3.0
+ foo==1.0.0 (from file://[TEMP_DIR]/foo)
+ idna==3.6
+ sniffio==1.3.1
"
);
Ok(())
}
#[test]
#[cfg(feature = "git")]
fn pep_751_compile_git() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str(
"uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git@0.0.1",
)?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "uv-public-pypackage"
version = "0.1.0"
vcs = { type = "git", url = "https://github.com/astral-test/uv-public-pypackage.git", requested-revision = "0.0.1", commit-id = "0dacfd662c64cb4ceb16e6cf65a157a8b715b979" }
----- stderr -----
Resolved 1 package in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ uv-public-pypackage==0.1.0 (from git+https://github.com/astral-test/uv-public-pypackage.git@0dacfd662c64cb4ceb16e6cf65a157a8b715b979)
"
);
Ok(())
}
#[test]
fn pep_751_compile_url_wheel() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str(
"anyio @ https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl",
)?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "4.3.0"
archive = { url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", hashes = { sha256 = "048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8" } }
[[packages]]
name = "idna"
version = "3.6"
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", upload-time = 2023-11-25T15:40:54Z, size = 175426, hashes = { sha256 = "9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", upload-time = 2023-11-25T15:40:52Z, size = 61567, hashes = { sha256 = "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 3 packages in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Prepared 2 packages in [TIME]
Installed 3 packages in [TIME]
+ anyio==4.3.0 (from https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl)
+ idna==3.6
+ sniffio==1.3.1
"
);
Ok(())
}
#[test]
fn pep_751_compile_url_sdist() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str(
"anyio @ https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz",
)?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "4.3.0"
archive = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hashes = { sha256 = "f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" } }
[[packages]]
name = "idna"
version = "3.6"
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", upload-time = 2023-11-25T15:40:54Z, size = 175426, hashes = { sha256 = "9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", upload-time = 2023-11-25T15:40:52Z, size = 61567, hashes = { sha256 = "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 3 packages in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
+ anyio==4.3.0 (from https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz)
+ idna==3.6
+ sniffio==1.3.1
"
);
Ok(())
}
#[test]
fn pep_751_compile_path_wheel() -> Result<()> {
let context = TestContext::new("3.12");
// Download the source.
let archive = context.temp_dir.child("iniconfig-2.0.0-py3-none-any.whl");
download_to_disk(
"https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl",
&archive,
);
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("./iniconfig-2.0.0-py3-none-any.whl")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "iniconfig"
version = "2.0.0"
archive = { path = "iniconfig-2.0.0-py3-none-any.whl", hashes = { sha256 = "b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" } }
----- stderr -----
Resolved 1 package in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed 1 package in [TIME]
+ iniconfig==2.0.0 (from file://[TEMP_DIR]/iniconfig-2.0.0-py3-none-any.whl)
"
);
// Ensure that the path is relative to the output `pylock.toml` file.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("nested/pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o nested/pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "iniconfig"
version = "2.0.0"
archive = { path = "../iniconfig-2.0.0-py3-none-any.whl", hashes = { sha256 = "b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" } }
----- stderr -----
Resolved 1 package in [TIME]
"#);
Ok(())
}
#[test]
fn pep_751_compile_path_sdist() -> Result<()> {
let context = TestContext::new("3.12");
// Download the source.
let archive = context.temp_dir.child("iniconfig-2.0.0.tar.gz");
download_to_disk(
"https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz",
&archive,
);
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("./iniconfig-2.0.0.tar.gz")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "iniconfig"
version = "2.0.0"
archive = { path = "iniconfig-2.0.0.tar.gz", hashes = { sha256 = "2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" } }
----- stderr -----
Resolved 1 package in [TIME]
"#);
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ iniconfig==2.0.0 (from file://[TEMP_DIR]/iniconfig-2.0.0.tar.gz)
"
);
// Ensure that the path is relative to the output `pylock.toml` file.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("nested/pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o nested/pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "iniconfig"
version = "2.0.0"
archive = { path = "../iniconfig-2.0.0.tar.gz", hashes = { sha256 = "2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" } }
----- stderr -----
Resolved 1 package in [TIME]
"#);
Ok(())
}
#[test]
fn pep_751_compile_preferences() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str(indoc::indoc! {r"
anyio==3.0.0
idna==3.0.0
"})?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "3.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/99/0d/65165f99e5f4f3b4c43a5ed9db0fb7aa655f5a58f290727a30528a87eb45/anyio-3.0.0.tar.gz", upload-time = 2021-04-20T14:02:14Z, size = 116952, hashes = { sha256 = "b553598332c050af19f7d41f73a7790142f5bc3d5eb8bd82f5e515ec22019bd9" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/3b/49/ebee263b69fe243bd1fd0a88bc6bb0f7732bf1794ba3273cb446351f9482/anyio-3.0.0-py3-none-any.whl", upload-time = 2021-04-20T14:02:13Z, size = 72182, hashes = { sha256 = "e71c3d9d72291d12056c0265d07c6bbedf92332f78573e278aeb116f24f30395" } }]
[[packages]]
name = "idna"
version = "3.0"
sdist = { url = "https://files.pythonhosted.org/packages/2f/2e/bfe821bd26194fb474e0932df8ed82e24bd312ba628a8644d93c5a28b5d4/idna-3.0.tar.gz", upload-time = 2021-01-01T05:58:25Z, size = 180786, hashes = { sha256 = "c9a26e10e5558412384fac891eefb41957831d31be55f1e2c98ed97a70abb969" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/0f/6b/3a878f15ef3324754bf4780f8f047d692d9860be894ff8fb3135cef8bed8/idna-3.0-py2.py3-none-any.whl", upload-time = 2021-01-01T05:58:22Z, size = 58618, hashes = { sha256 = "320229aadbdfc597bc28876748cc0c9d04d476e0fe6caacaaddea146365d9f63" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 3 packages in [TIME]
"#);
// Modify the requirements to loosen the `anyio` version.
requirements_txt.write_str("anyio")?;
// The `anyio` version should be retained, since we respect the existing preferences.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "3.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/99/0d/65165f99e5f4f3b4c43a5ed9db0fb7aa655f5a58f290727a30528a87eb45/anyio-3.0.0.tar.gz", upload-time = 2021-04-20T14:02:14Z, size = 116952, hashes = { sha256 = "b553598332c050af19f7d41f73a7790142f5bc3d5eb8bd82f5e515ec22019bd9" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/3b/49/ebee263b69fe243bd1fd0a88bc6bb0f7732bf1794ba3273cb446351f9482/anyio-3.0.0-py3-none-any.whl", upload-time = 2021-04-20T14:02:13Z, size = 72182, hashes = { sha256 = "e71c3d9d72291d12056c0265d07c6bbedf92332f78573e278aeb116f24f30395" } }]
[[packages]]
name = "idna"
version = "3.0"
sdist = { url = "https://files.pythonhosted.org/packages/2f/2e/bfe821bd26194fb474e0932df8ed82e24bd312ba628a8644d93c5a28b5d4/idna-3.0.tar.gz", upload-time = 2021-01-01T05:58:25Z, size = 180786, hashes = { sha256 = "c9a26e10e5558412384fac891eefb41957831d31be55f1e2c98ed97a70abb969" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/0f/6b/3a878f15ef3324754bf4780f8f047d692d9860be894ff8fb3135cef8bed8/idna-3.0-py2.py3-none-any.whl", upload-time = 2021-01-01T05:58:22Z, size = 58618, hashes = { sha256 = "320229aadbdfc597bc28876748cc0c9d04d476e0fe6caacaaddea146365d9f63" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 3 packages in [TIME]
"#);
// Unless we pass `--upgrade-package`.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml")
.arg("--upgrade-package")
.arg("idna"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "3.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/99/0d/65165f99e5f4f3b4c43a5ed9db0fb7aa655f5a58f290727a30528a87eb45/anyio-3.0.0.tar.gz", upload-time = 2021-04-20T14:02:14Z, size = 116952, hashes = { sha256 = "b553598332c050af19f7d41f73a7790142f5bc3d5eb8bd82f5e515ec22019bd9" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/3b/49/ebee263b69fe243bd1fd0a88bc6bb0f7732bf1794ba3273cb446351f9482/anyio-3.0.0-py3-none-any.whl", upload-time = 2021-04-20T14:02:13Z, size = 72182, hashes = { sha256 = "e71c3d9d72291d12056c0265d07c6bbedf92332f78573e278aeb116f24f30395" } }]
[[packages]]
name = "idna"
version = "3.6"
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", upload-time = 2023-11-25T15:40:54Z, size = 175426, hashes = { sha256 = "9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", upload-time = 2023-11-25T15:40:52Z, size = 61567, hashes = { sha256 = "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 3 packages in [TIME]
"#);
// Or `--upgrade`.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml")
.arg("--upgrade"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "4.3.0"
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", upload-time = 2024-02-19T08:36:28Z, size = 159642, hashes = { sha256 = "f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", upload-time = 2024-02-19T08:36:26Z, size = 85584, hashes = { sha256 = "048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8" } }]
[[packages]]
name = "idna"
version = "3.6"
sdist = { url = "https://files.pythonhosted.org/packages/bf/3f/ea4b9117521a1e9c50344b909be7886dd00a519552724809bb1f486986c2/idna-3.6.tar.gz", upload-time = 2023-11-25T15:40:54Z, size = 175426, hashes = { sha256 = "9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", upload-time = 2023-11-25T15:40:52Z, size = 61567, hashes = { sha256 = "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
----- stderr -----
Resolved 3 packages in [TIME]
"#);
Ok(())
}
#[test]
fn pep_751_compile_warn() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("iniconfig")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml")
.arg("--emit-index-url"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml --emit-index-url
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "iniconfig"
version = "2.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", upload-time = 2023-01-07T11:08:11Z, size = 4646, hashes = { sha256 = "2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", upload-time = 2023-01-07T11:08:09Z, size = 5892, hashes = { sha256 = "b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" } }]
----- stderr -----
Resolved 1 package in [TIME]
warning: The `--emit-index-url` option is not supported for `pylock.toml` output
"#);
Ok(())
}
#[test]
fn pep_751_compile_non_universal() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("black")?;
// `colorama` should be excluded, since we're on Linux.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--python-platform")
.arg("linux")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --python-platform linux -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "black"
version = "24.3.0"
sdist = { url = "https://files.pythonhosted.org/packages/8f/5f/bac24a952668c7482cfdb4ebf91ba57a796c9da8829363a772040c1a3312/black-24.3.0.tar.gz", upload-time = 2024-03-15T19:35:43Z, size = 634292, hashes = { sha256 = "a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f" } }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3b/32/1a25d1b83147ca128797a627f429f9dc390eb066805c6aa319bea3ffffa5/black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:43:32Z, size = 1587891, hashes = { sha256 = "7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395" } },
{ url = "https://files.pythonhosted.org/packages/c4/91/6cb204786acc693edc4bf1b9230ffdc3cbfaeb7cd04d3a12fb4b13882a53/black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:41:59Z, size = 1434886, hashes = { sha256 = "9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995" } },
{ url = "https://files.pythonhosted.org/packages/ef/e4/53b5d07117381f7d5e946a54dd4c62617faad90713649619bbc683769dfe/black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:22Z, size = 1747400, hashes = { sha256 = "e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7" } },
{ url = "https://files.pythonhosted.org/packages/13/9c/f2e7532d11b05add5ab383a9f90be1a49954bf510803f98064b45b42f98e/black-24.3.0-cp310-cp310-win_amd64.whl", upload-time = 2024-03-15T19:39:43Z, size = 1363816, hashes = { sha256 = "4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0" } },
{ url = "https://files.pythonhosted.org/packages/68/df/ceea5828be9c4931cb5a75b7e8fb02971f57524da7a16dfec0d4d575327f/black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:45:27Z, size = 1571235, hashes = { sha256 = "4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9" } },
{ url = "https://files.pythonhosted.org/packages/46/5f/30398c5056cb72f883b32b6520ad00042a9d0454b693f70509867db03a80/black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:43:52Z, size = 1414926, hashes = { sha256 = "aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597" } },
{ url = "https://files.pythonhosted.org/packages/6b/59/498885b279e890f656ea4300a2671c964acb6d97994ea626479c2e5501b4/black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:13Z, size = 1725920, hashes = { sha256 = "65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d" } },
{ url = "https://files.pythonhosted.org/packages/8f/b0/4bef40c808cc615187db983b75bacdca1c110a229d41ba9887549fac529c/black-24.3.0-cp311-cp311-win_amd64.whl", upload-time = 2024-03-15T19:39:34Z, size = 1372608, hashes = { sha256 = "bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5" } },
{ url = "https://files.pythonhosted.org/packages/b6/c6/1d174efa9ff02b22d0124c73fc5f4d4fb006d0d9a081aadc354d05754a13/black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:45:20Z, size = 1600822, hashes = { sha256 = "2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f" } },
{ url = "https://files.pythonhosted.org/packages/d9/ed/704731afffe460b8ff0672623b40fce9fe569f2ee617c15857e4d4440a3a/black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:45:00Z, size = 1429987, hashes = { sha256 = "4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11" } },
{ url = "https://files.pythonhosted.org/packages/a8/05/8dd038e30caadab7120176d4bc109b7ca2f4457f12eef746b0560a583458/black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:24Z, size = 1755319, hashes = { sha256 = "c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4" } },
{ url = "https://files.pythonhosted.org/packages/71/9d/e5fa1ff4ef1940be15a64883c0bb8d2fcf626efec996eab4ae5a8c691d2c/black-24.3.0-cp312-cp312-win_amd64.whl", upload-time = 2024-03-15T19:39:37Z, size = 1385180, hashes = { sha256 = "56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5" } },
{ url = "https://files.pythonhosted.org/packages/37/76/1f85c4349d6b3424c7672dbc6c4b39ab89372b575801ffdc23d34b023c6f/black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:47:26Z, size = 1579568, hashes = { sha256 = "79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837" } },
{ url = "https://files.pythonhosted.org/packages/ba/24/6d82cde63c1340ea55cb74fd697f62b94b6d6fa7069a1aa216475dfd2a30/black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:46:18Z, size = 1423188, hashes = { sha256 = "e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd" } },
{ url = "https://files.pythonhosted.org/packages/71/61/48664319cee4f8e22633e075ff101ec6253195b056cb23e0c5f8a5086e87/black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:15Z, size = 1730623, hashes = { sha256 = "65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213" } },
{ url = "https://files.pythonhosted.org/packages/3b/95/ed26a160d7a13d6afb3e94448ec079fb4e37bbedeaf408b6b6dbf67d6cd2/black-24.3.0-cp38-cp38-win_amd64.whl", upload-time = 2024-03-15T19:39:43Z, size = 1370465, hashes = { sha256 = "b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959" } },
{ url = "https://files.pythonhosted.org/packages/62/f5/78881e9b1c340ccc02d5d4ebe61cfb9140452b3d11272a896b405033511b/black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:48:33Z, size = 1587504, hashes = { sha256 = "c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb" } },
{ url = "https://files.pythonhosted.org/packages/17/cc/67ba827fe23b39d55e8408937763b2ad21d904d63ca1c60b47d608ee7fb2/black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:47:39Z, size = 1434037, hashes = { sha256 = "6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7" } },
{ url = "https://files.pythonhosted.org/packages/fa/aa/6a2493c7d3506e9b64edbd0782e21637c376da005eecc546904e47b5cdbf/black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:16Z, size = 1745481, hashes = { sha256 = "d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7" } },
{ url = "https://files.pythonhosted.org/packages/18/68/9e86e73b58819624af6797ffe68dd7d09ed90fa1f9eb8d4d675f8c5e6ab0/black-24.3.0-cp39-cp39-win_amd64.whl", upload-time = 2024-03-15T19:39:15Z, size = 1363531, hashes = { sha256 = "7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f" } },
{ url = "https://files.pythonhosted.org/packages/4d/ea/31770a7e49f3eedfd8cd7b35e78b3a3aaad860400f8673994bc988318135/black-24.3.0-py3-none-any.whl", upload-time = 2024-03-15T19:35:41Z, size = 201493, hashes = { sha256 = "41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93" } },
]
[[packages]]
name = "click"
version = "8.1.7"
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", upload-time = 2023-08-17T17:29:11Z, size = 336121, hashes = { sha256 = "ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", upload-time = 2023-08-17T17:29:10Z, size = 97941, hashes = { sha256 = "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28" } }]
[[packages]]
name = "mypy-extensions"
version = "1.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", upload-time = 2023-02-04T12:11:27Z, size = 4433, hashes = { sha256 = "75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", upload-time = 2023-02-04T12:11:25Z, size = 4695, hashes = { sha256 = "4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d" } }]
[[packages]]
name = "packaging"
version = "24.0"
sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/b43a27ac7472e1818c4bafd44430e69605baefe1f34440593e0332ec8b4d/packaging-24.0.tar.gz", upload-time = 2024-03-10T09:39:28Z, size = 147882, hashes = { sha256 = "eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", upload-time = 2024-03-10T09:39:25Z, size = 53488, hashes = { sha256 = "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5" } }]
[[packages]]
name = "pathspec"
version = "0.12.1"
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", upload-time = 2023-12-10T22:30:45Z, size = 51043, hashes = { sha256 = "a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", upload-time = 2023-12-10T22:30:43Z, size = 31191, hashes = { sha256 = "a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08" } }]
[[packages]]
name = "platformdirs"
version = "4.2.0"
sdist = { url = "https://files.pythonhosted.org/packages/96/dc/c1d911bf5bb0fdc58cc05010e9f3efe3b67970cef779ba7fbc3183b987a8/platformdirs-4.2.0.tar.gz", upload-time = 2024-01-31T01:00:36Z, size = 20055, hashes = { sha256 = "ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/55/72/4898c44ee9ea6f43396fbc23d9bfaf3d06e01b83698bdf2e4c919deceb7c/platformdirs-4.2.0-py3-none-any.whl", upload-time = 2024-01-31T01:00:34Z, size = 17717, hashes = { sha256 = "0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068" } }]
----- stderr -----
Resolved 6 packages in [TIME]
"#);
// `colorama` should be included, since we're on Windows.
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--python-platform")
.arg("windows")
.arg("-o")
.arg("pylock.toml"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --python-platform windows -o pylock.toml
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "black"
version = "24.3.0"
sdist = { url = "https://files.pythonhosted.org/packages/8f/5f/bac24a952668c7482cfdb4ebf91ba57a796c9da8829363a772040c1a3312/black-24.3.0.tar.gz", upload-time = 2024-03-15T19:35:43Z, size = 634292, hashes = { sha256 = "a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f" } }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3b/32/1a25d1b83147ca128797a627f429f9dc390eb066805c6aa319bea3ffffa5/black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:43:32Z, size = 1587891, hashes = { sha256 = "7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395" } },
{ url = "https://files.pythonhosted.org/packages/c4/91/6cb204786acc693edc4bf1b9230ffdc3cbfaeb7cd04d3a12fb4b13882a53/black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:41:59Z, size = 1434886, hashes = { sha256 = "9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995" } },
{ url = "https://files.pythonhosted.org/packages/ef/e4/53b5d07117381f7d5e946a54dd4c62617faad90713649619bbc683769dfe/black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:22Z, size = 1747400, hashes = { sha256 = "e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7" } },
{ url = "https://files.pythonhosted.org/packages/13/9c/f2e7532d11b05add5ab383a9f90be1a49954bf510803f98064b45b42f98e/black-24.3.0-cp310-cp310-win_amd64.whl", upload-time = 2024-03-15T19:39:43Z, size = 1363816, hashes = { sha256 = "4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0" } },
{ url = "https://files.pythonhosted.org/packages/68/df/ceea5828be9c4931cb5a75b7e8fb02971f57524da7a16dfec0d4d575327f/black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:45:27Z, size = 1571235, hashes = { sha256 = "4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9" } },
{ url = "https://files.pythonhosted.org/packages/46/5f/30398c5056cb72f883b32b6520ad00042a9d0454b693f70509867db03a80/black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:43:52Z, size = 1414926, hashes = { sha256 = "aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597" } },
{ url = "https://files.pythonhosted.org/packages/6b/59/498885b279e890f656ea4300a2671c964acb6d97994ea626479c2e5501b4/black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:13Z, size = 1725920, hashes = { sha256 = "65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d" } },
{ url = "https://files.pythonhosted.org/packages/8f/b0/4bef40c808cc615187db983b75bacdca1c110a229d41ba9887549fac529c/black-24.3.0-cp311-cp311-win_amd64.whl", upload-time = 2024-03-15T19:39:34Z, size = 1372608, hashes = { sha256 = "bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5" } },
{ url = "https://files.pythonhosted.org/packages/b6/c6/1d174efa9ff02b22d0124c73fc5f4d4fb006d0d9a081aadc354d05754a13/black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:45:20Z, size = 1600822, hashes = { sha256 = "2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f" } },
{ url = "https://files.pythonhosted.org/packages/d9/ed/704731afffe460b8ff0672623b40fce9fe569f2ee617c15857e4d4440a3a/black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:45:00Z, size = 1429987, hashes = { sha256 = "4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11" } },
{ url = "https://files.pythonhosted.org/packages/a8/05/8dd038e30caadab7120176d4bc109b7ca2f4457f12eef746b0560a583458/black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:24Z, size = 1755319, hashes = { sha256 = "c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4" } },
{ url = "https://files.pythonhosted.org/packages/71/9d/e5fa1ff4ef1940be15a64883c0bb8d2fcf626efec996eab4ae5a8c691d2c/black-24.3.0-cp312-cp312-win_amd64.whl", upload-time = 2024-03-15T19:39:37Z, size = 1385180, hashes = { sha256 = "56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5" } },
{ url = "https://files.pythonhosted.org/packages/37/76/1f85c4349d6b3424c7672dbc6c4b39ab89372b575801ffdc23d34b023c6f/black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:47:26Z, size = 1579568, hashes = { sha256 = "79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837" } },
{ url = "https://files.pythonhosted.org/packages/ba/24/6d82cde63c1340ea55cb74fd697f62b94b6d6fa7069a1aa216475dfd2a30/black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:46:18Z, size = 1423188, hashes = { sha256 = "e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd" } },
{ url = "https://files.pythonhosted.org/packages/71/61/48664319cee4f8e22633e075ff101ec6253195b056cb23e0c5f8a5086e87/black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:15Z, size = 1730623, hashes = { sha256 = "65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213" } },
{ url = "https://files.pythonhosted.org/packages/3b/95/ed26a160d7a13d6afb3e94448ec079fb4e37bbedeaf408b6b6dbf67d6cd2/black-24.3.0-cp38-cp38-win_amd64.whl", upload-time = 2024-03-15T19:39:43Z, size = 1370465, hashes = { sha256 = "b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959" } },
{ url = "https://files.pythonhosted.org/packages/62/f5/78881e9b1c340ccc02d5d4ebe61cfb9140452b3d11272a896b405033511b/black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", upload-time = 2024-03-15T19:48:33Z, size = 1587504, hashes = { sha256 = "c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb" } },
{ url = "https://files.pythonhosted.org/packages/17/cc/67ba827fe23b39d55e8408937763b2ad21d904d63ca1c60b47d608ee7fb2/black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", upload-time = 2024-03-15T19:47:39Z, size = 1434037, hashes = { sha256 = "6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7" } },
{ url = "https://files.pythonhosted.org/packages/fa/aa/6a2493c7d3506e9b64edbd0782e21637c376da005eecc546904e47b5cdbf/black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", upload-time = 2024-03-15T19:38:16Z, size = 1745481, hashes = { sha256 = "d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7" } },
{ url = "https://files.pythonhosted.org/packages/18/68/9e86e73b58819624af6797ffe68dd7d09ed90fa1f9eb8d4d675f8c5e6ab0/black-24.3.0-cp39-cp39-win_amd64.whl", upload-time = 2024-03-15T19:39:15Z, size = 1363531, hashes = { sha256 = "7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f" } },
{ url = "https://files.pythonhosted.org/packages/4d/ea/31770a7e49f3eedfd8cd7b35e78b3a3aaad860400f8673994bc988318135/black-24.3.0-py3-none-any.whl", upload-time = 2024-03-15T19:35:41Z, size = 201493, hashes = { sha256 = "41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93" } },
]
[[packages]]
name = "click"
version = "8.1.7"
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", upload-time = 2023-08-17T17:29:11Z, size = 336121, hashes = { sha256 = "ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", upload-time = 2023-08-17T17:29:10Z, size = 97941, hashes = { sha256 = "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28" } }]
[[packages]]
name = "colorama"
version = "0.4.6"
marker = "sys_platform == 'win32'"
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", upload-time = 2022-10-25T02:36:22Z, size = 27697, hashes = { sha256 = "08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", upload-time = 2022-10-25T02:36:20Z, size = 25335, hashes = { sha256 = "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" } }]
[[packages]]
name = "mypy-extensions"
version = "1.0.0"
sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", upload-time = 2023-02-04T12:11:27Z, size = 4433, hashes = { sha256 = "75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", upload-time = 2023-02-04T12:11:25Z, size = 4695, hashes = { sha256 = "4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d" } }]
[[packages]]
name = "packaging"
version = "24.0"
sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/b43a27ac7472e1818c4bafd44430e69605baefe1f34440593e0332ec8b4d/packaging-24.0.tar.gz", upload-time = 2024-03-10T09:39:28Z, size = 147882, hashes = { sha256 = "eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", upload-time = 2024-03-10T09:39:25Z, size = 53488, hashes = { sha256 = "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5" } }]
[[packages]]
name = "pathspec"
version = "0.12.1"
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", upload-time = 2023-12-10T22:30:45Z, size = 51043, hashes = { sha256 = "a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", upload-time = 2023-12-10T22:30:43Z, size = 31191, hashes = { sha256 = "a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08" } }]
[[packages]]
name = "platformdirs"
version = "4.2.0"
sdist = { url = "https://files.pythonhosted.org/packages/96/dc/c1d911bf5bb0fdc58cc05010e9f3efe3b67970cef779ba7fbc3183b987a8/platformdirs-4.2.0.tar.gz", upload-time = 2024-01-31T01:00:36Z, size = 20055, hashes = { sha256 = "ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/55/72/4898c44ee9ea6f43396fbc23d9bfaf3d06e01b83698bdf2e4c919deceb7c/platformdirs-4.2.0-py3-none-any.whl", upload-time = 2024-01-31T01:00:34Z, size = 17717, hashes = { sha256 = "0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068" } }]
----- stderr -----
Resolved 7 packages in [TIME]
"#);
Ok(())
}
#[test]
fn pep_751_compile_no_emit_package() -> Result<()> {
let context = TestContext::new("3.12");
let requirements_txt = context.temp_dir.child("requirements.txt");
requirements_txt.write_str("anyio")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.txt")
.arg("--universal")
.arg("-o")
.arg("pylock.toml")
.arg("--no-emit-package")
.arg("idna"), @r#"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.txt --universal -o pylock.toml --no-emit-package idna
lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.12.9"
[[packages]]
name = "anyio"
version = "4.3.0"
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", upload-time = 2024-02-19T08:36:28Z, size = 159642, hashes = { sha256 = "f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl", upload-time = 2024-02-19T08:36:26Z, size = 85584, hashes = { sha256 = "048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8" } }]
[[packages]]
name = "sniffio"
version = "1.3.1"
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", upload-time = 2024-02-25T23:20:04Z, size = 20372, hashes = { sha256 = "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", upload-time = 2024-02-25T23:20:01Z, size = 10235, hashes = { sha256 = "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" } }]
# The following packages were excluded from the output:
# idna
----- stderr -----
Resolved 3 packages in [TIME]
"#);
Ok(())
}

View File

@ -84,6 +84,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -244,6 +245,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -405,6 +407,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -598,6 +601,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -760,6 +764,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -900,6 +905,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -1087,6 +1093,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -1280,6 +1287,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -1529,6 +1537,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -1713,6 +1722,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -1858,6 +1868,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -2049,6 +2060,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -2263,6 +2275,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -2398,6 +2411,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -2533,6 +2547,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -2670,6 +2685,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -2990,6 +3006,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -3153,6 +3170,7 @@ fn resolve_both() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -3438,6 +3456,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -3699,6 +3718,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -3837,6 +3857,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -3994,6 +4015,7 @@ fn allow_insecure_host() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -4143,6 +4165,7 @@ fn index_priority() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -4336,6 +4359,7 @@ fn index_priority() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -4535,6 +4559,7 @@ fn index_priority() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -4729,6 +4754,7 @@ fn index_priority() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -4930,6 +4956,7 @@ fn index_priority() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],
@ -5124,6 +5151,7 @@ fn index_priority() -> anyhow::Result<()> {
),
}
PipCompileSettings {
format: None,
src_file: [
"requirements.in",
],

View File

@ -5723,6 +5723,19 @@ uv pip compile [OPTIONS] <SRC_FILE|--group <GROUP>>
<li><code>requires-python</code>: Optimize for selecting latest supported version of each package, for each supported Python version</li>
</ul>
</dd><dt id="uv-pip-compile--format"><a href="#uv-pip-compile--format"><code>--format</code></a> <i>format</i></dt><dd><p>The format in which the resolution should be output.</p>
<p>Supports both <code>requirements.txt</code> and <code>pylock.toml</code> (PEP 751) output formats.</p>
<p>uv will infer the output format from the file extension of the output file, if provided. Otherwise, defaults to <code>requirements.txt</code>.</p>
<p>Possible values:</p>
<ul>
<li><code>requirements.txt</code>: Export in <code>requirements.txt</code> format</li>
<li><code>pylock.toml</code>: Export in <code>pylock.toml</code> format</li>
</ul>
</dd><dt id="uv-pip-compile--generate-hashes"><a href="#uv-pip-compile--generate-hashes"><code>--generate-hashes</code></a></dt><dd><p>Include distribution hashes in the output file</p>
</dd><dt id="uv-pip-compile--group"><a href="#uv-pip-compile--group"><code>--group</code></a> <i>group</i></dt><dd><p>Install the specified dependency group from a <code>pyproject.toml</code>.</p>
@ -5872,7 +5885,7 @@ uv pip compile [OPTIONS] <SRC_FILE|--group <GROUP>>
<p>Multiple packages may be provided. Disable binaries for all packages with <code>:all:</code>. Clear previously specified packages with <code>:none:</code>.</p>
</dd><dt id="uv-pip-compile--output-file"><a href="#uv-pip-compile--output-file"><code>--output-file</code></a>, <code>-o</code> <i>output-file</i></dt><dd><p>Write the compiled requirements to the given <code>requirements.txt</code> file.</p>
</dd><dt id="uv-pip-compile--output-file"><a href="#uv-pip-compile--output-file"><code>--output-file</code></a>, <code>-o</code> <i>output-file</i></dt><dd><p>Write the compiled requirements to the given <code>requirements.txt</code> or <code>pylock.toml</code> file.</p>
<p>If the file already exists, the existing versions will be preferred when resolving dependencies, unless <code>--upgrade</code> is also specified.</p>